From 6a940a0bb0d25b531e23d70ae93a44627486090a Mon Sep 17 00:00:00 2001 From: jinqiming <45981669@qq.com> Date: Thu, 17 Sep 2020 18:04:40 +0800 Subject: [PATCH 01/82] =?UTF-8?q?=E4=BF=AE=E6=94=B9readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- snow-common/pom.xml | 1 + .../com/snow/common/constant/Constants.java | 14 +++ .../com/snow/common/enums/BusinessType.java | 8 ++ snow-dingtalk/pom.xml | 6 ++ .../com/snow/dingtalk/SyncEventListener.java | 32 +++++++ .../snow/dingtalk/common/BaseConstantUrl.java | 8 +- .../com/snow/dingtalk/common/BaseService.java | 44 ++++++++-- .../snow/dingtalk/model/DepartmentDTO.java | 86 +++++++++++++++++++ .../dingtalk/service/DepartmentService.java | 50 +++++++++++ .../src/main/java/com/snow/dingtalk/test.java | 10 --- .../java/com/snow/system/event/SyncEvent.java | 38 ++++++++ .../service/impl/SysDeptServiceImpl.java | 9 ++ 12 files changed, 290 insertions(+), 16 deletions(-) create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/SyncEventListener.java create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/model/DepartmentDTO.java create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/service/DepartmentService.java delete mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/test.java create mode 100644 snow-system/src/main/java/com/snow/system/event/SyncEvent.java diff --git a/snow-common/pom.xml b/snow-common/pom.xml index 4520fe1..2fe1641 100644 --- a/snow-common/pom.xml +++ b/snow-common/pom.xml @@ -100,6 +100,7 @@ hutool-all 5.4.2 + \ No newline at end of file diff --git a/snow-common/src/main/java/com/snow/common/constant/Constants.java b/snow-common/src/main/java/com/snow/common/constant/Constants.java index 6e3fdfd..036f1f8 100644 --- a/snow-common/src/main/java/com/snow/common/constant/Constants.java +++ b/snow-common/src/main/java/com/snow/common/constant/Constants.java @@ -91,4 +91,18 @@ public class Constants * 资源映射路径 前缀 */ public static final String RESOURCE_PREFIX = "/profile"; + + + public static final String POST="POST"; + + public static final String GET="GET"; + /** + * 钉钉企业内部APPkey + */ + public static final String ENTERPRICE_APP_KEY="enterpriceAppKey"; + /** + * 钉钉企业内部ENTERPRICE_APP_SECRET + */ + public static final String ENTERPRICE_APP_SECRET="enterpriceAppSecret"; + } diff --git a/snow-common/src/main/java/com/snow/common/enums/BusinessType.java b/snow-common/src/main/java/com/snow/common/enums/BusinessType.java index 996b8ea..5d423ea 100644 --- a/snow-common/src/main/java/com/snow/common/enums/BusinessType.java +++ b/snow-common/src/main/java/com/snow/common/enums/BusinessType.java @@ -56,4 +56,12 @@ public enum BusinessType * 清空 */ CLEAN, + /** + * 钉钉 + */ + DING_TALK, + /** + * 同步 + */ + SYNCHRONIZATION } diff --git a/snow-dingtalk/pom.xml b/snow-dingtalk/pom.xml index ca84560..b072cb6 100644 --- a/snow-dingtalk/pom.xml +++ b/snow-dingtalk/pom.xml @@ -24,5 +24,11 @@ alibaba-dingtalk-service-sdk 1.0.1 + + + org.projectlombok + lombok + 1.18.10 + \ No newline at end of file diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/SyncEventListener.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/SyncEventListener.java new file mode 100644 index 0000000..da4d184 --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/SyncEventListener.java @@ -0,0 +1,32 @@ +package com.snow.dingtalk; + +import com.alibaba.fastjson.JSON; +import com.snow.dingtalk.model.DepartmentDTO; +import com.snow.dingtalk.service.DepartmentService; +import com.snow.system.domain.SysDept; +import com.snow.system.event.SyncEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/9/17 17:40 + */ +@Component +public class SyncEventListener implements ApplicationListener { + + @Autowired + private DepartmentService departmentService; + @Override + public void onApplicationEvent(SyncEvent syncEvent) { + Integer eventType = syncEvent.getEventType(); + SysDept sysDept=(SysDept)syncEvent.getT(); + DepartmentDTO departmentDTO = DepartmentDTO.builder().name(sysDept.getDeptName()).order(sysDept.getOrderNum()) + .parentid(sysDept.getParentName()).build(); + departmentService.createDepartment(departmentDTO); + System.out.println("监听到的事件类型:"+eventType+JSON.toJSONString(syncEvent)); + } +} diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java index 7aa6724..77590b9 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java @@ -7,6 +7,12 @@ package com.snow.dingtalk.common; * @date 2020/9/16 11:02 */ public class BaseConstantUrl { - + /** + * 获取token url + */ public static final String GET_TOKEN_URL="https://oapi.dingtalk.com/gettoken"; + /** + * 创建部门 + */ + public static final String DEPARTMENT_CREATE="https://oapi.dingtalk.com/department/create"; } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseService.java index 4d28ee6..57cc262 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseService.java @@ -5,31 +5,45 @@ import cn.hutool.cache.impl.TimedCache; import com.dingtalk.api.DefaultDingTalkClient; import com.dingtalk.api.request.OapiGettokenRequest; import com.dingtalk.api.response.OapiGettokenResponse; +import com.snow.common.constant.Constants; +import com.snow.common.enums.BusinessType; import com.snow.common.utils.StringUtils; +import com.snow.system.domain.SysOperLog; +import com.snow.system.service.ISysConfigService; +import com.snow.system.service.ISysOperLogService; import com.taobao.api.ApiException; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.Date; + /** * @author qimingjin * @Title: * @Description: * @date 2020/9/16 10:46 */ -@Service public class BaseService { - public final String TOKEN="token"; + + public static final String TOKEN="token"; + @Autowired + private ISysConfigService isysConfigService; + @Autowired + private ISysOperLogService iSysOperLogService; + /** * 获取token * @return */ public String getDingTalkToken(){ + //创建缓存,缓存默认是7100S TimedCache timedCache = CacheUtil.newTimedCache(7100); if(StringUtils.isEmpty(timedCache.get(TOKEN))){ DefaultDingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.GET_TOKEN_URL); OapiGettokenRequest request = new OapiGettokenRequest(); - request.setAppkey("dingjidrzgnmznpofira"); - request.setAppsecret("IuKf2e8Z0stvf8LPMfHy_Im6sTi3G1mh0Jn0k4xuEnOhOyiLfKogwYympDVcRGK4"); - request.setHttpMethod("GET"); + request.setAppkey(isysConfigService.selectConfigByKey(Constants.ENTERPRICE_APP_KEY)); + request.setAppsecret(isysConfigService.selectConfigByKey(Constants.ENTERPRICE_APP_SECRET)); + request.setHttpMethod(Constants.GET); try { OapiGettokenResponse response = client.execute(request); if(response.getErrcode()==0){ @@ -37,9 +51,11 @@ public class BaseService { return response.getAccessToken(); }else { //记录获取token失败日志 + syncDingTalkErrorOperLog(BaseConstantUrl.GET_TOKEN_URL,response.getErrmsg(),"getDingTalkToken()"); return null; } } catch (ApiException e) { + syncDingTalkErrorOperLog(BaseConstantUrl.GET_TOKEN_URL,e.getMessage(),"getDingTalkToken()"); e.printStackTrace(); } return null; @@ -49,4 +65,22 @@ public class BaseService { } + /** + * 记录钉钉异常信息 + * @param url + * @param errorMessage + * @param method + */ + public void syncDingTalkErrorOperLog(String url,String errorMessage,String method){ + SysOperLog sysOperLog=new SysOperLog(); + sysOperLog.setOperTime(new Date()); + sysOperLog.setErrorMsg(errorMessage); + sysOperLog.setBusinessType(BusinessType.SYNCHRONIZATION.ordinal()); + sysOperLog.setOperName("系统自动记录"); + sysOperLog.setOperUrl(url); + sysOperLog.setMethod(method); + sysOperLog.setTitle("系统调用钉钉异常"); + iSysOperLogService.insertOperlog(sysOperLog); + } + } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/model/DepartmentDTO.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/model/DepartmentDTO.java new file mode 100644 index 0000000..0ec6b1c --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/model/DepartmentDTO.java @@ -0,0 +1,86 @@ +package com.snow.dingtalk.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/9/17 17:10 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class DepartmentDTO { + /** + * 部门名称,长度限制为1~64个字符,不允许包含字符‘-’‘,’以及‘,’ + */ + private String name; + + + /** + * 父部门id,根部门id为1 + */ + private String parentid; + + + /** + * 在父部门中的排序值,order值小的排序靠前 + */ + private String order; + + + /** + * 是否创建一个关联此部门的企业群,默认为false + */ + private Boolean createDeptGroup; + + + /** + * + 是否隐藏部门, + + true表示隐藏 + + false表示显示 + */ + private Boolean deptHiding; + + + /** + * 可以查看指定隐藏部门的其他部门列表,如果部门隐藏,则此值生效, + * 取值为其他的部门id组成的字符串,使用“\|”符号进行分割。总数不能超过200 + */ + + private String deptPermits; + + + /** + * 可以查看指定隐藏部门的其他人员列表,如果部门隐藏,则此值生效, + * 取值为其他的人员userid组成的字符串,使用“\|”符号进行分割。总数不能超过200 + */ + private String userPermits; + + + /** + * 限制本部门成员查看通讯录,限制开启后,本部门成员只能看到限定范围内的通讯录。true表示限制开启 + */ + private Boolean outerDept; + + + /** + * 部门标识字段,开发者可用该字段来唯一标识一个部门,并与钉钉外部通讯录里的部门做映射 + */ + private String sourceIdentifier; + + + /** + * 部门自定义字段,格式为文本类型的Json格式 + */ + private String ext; + +} diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/DepartmentService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/DepartmentService.java new file mode 100644 index 0000000..94d018b --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/DepartmentService.java @@ -0,0 +1,50 @@ +package com.snow.dingtalk.service; + +import com.dingtalk.api.DefaultDingTalkClient; +import com.dingtalk.api.DingTalkClient; +import com.dingtalk.api.request.OapiDepartmentCreateRequest; +import com.dingtalk.api.response.OapiDepartmentCreateResponse; +import com.snow.dingtalk.common.BaseConstantUrl; +import com.snow.dingtalk.common.BaseService; +import com.snow.dingtalk.model.DepartmentDTO; +import com.taobao.api.ApiException; +import com.taobao.api.Constants; +import org.slf4j.Logger; +import org.springframework.stereotype.Service; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/9/17 17:02 + */ +@Service +public class DepartmentService extends BaseService { + /** + * 创建部门 + * @param departmentDTO + * @return + */ + public Long createDepartment(DepartmentDTO departmentDTO){ + DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.DEPARTMENT_CREATE); + OapiDepartmentCreateRequest request = new OapiDepartmentCreateRequest(); + request.setParentid(departmentDTO.getParentid()); + request.setCreateDeptGroup(departmentDTO.getCreateDeptGroup()); + request.setOrder(departmentDTO.getOrder()); + request.setName(departmentDTO.getName()); + request.setHttpMethod(Constants.METHOD_POST); + request.setSourceIdentifier(departmentDTO.getSourceIdentifier()); + try { + OapiDepartmentCreateResponse response = client.execute(request,getDingTalkToken()); + if(response.getErrcode()==0){ + return response.getId(); + }else { + syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_CREATE,response.getErrmsg(),"createDepartment"); + } + } catch (ApiException e) { + syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_CREATE,e.getMessage(),"createDepartment"); + e.printStackTrace(); + } + return null; + } +} diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/test.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/test.java deleted file mode 100644 index 124f019..0000000 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/test.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.snow.dingtalk; - -/** - * @author qimingjin - * @Title: - * @Description: - * @date 2020/9/16 10:45 - */ -public class test { -} diff --git a/snow-system/src/main/java/com/snow/system/event/SyncEvent.java b/snow-system/src/main/java/com/snow/system/event/SyncEvent.java new file mode 100644 index 0000000..a8317c1 --- /dev/null +++ b/snow-system/src/main/java/com/snow/system/event/SyncEvent.java @@ -0,0 +1,38 @@ +package com.snow.system.event; + +import org.springframework.context.ApplicationEvent; + +/** + * @author qimingjin + * @Title: 同步事件监听器 + * @Description: + * @date 2020/9/17 17:34 + */ +public class SyncEvent extends ApplicationEvent { + + private Integer eventType; + + private T t; + + public SyncEvent(Object source,Integer eventType,T t) { + super(source); + this.eventType = eventType; + this.t=t; + } + + public T getT() { + return t; + } + + public void setT(T t) { + this.t = t; + } + + public Integer getEventType() { + return eventType; + } + + public void setEventType(Integer eventType) { + this.eventType = eventType; + } +} diff --git a/snow-system/src/main/java/com/snow/system/service/impl/SysDeptServiceImpl.java b/snow-system/src/main/java/com/snow/system/service/impl/SysDeptServiceImpl.java index 6a73579..2892004 100644 --- a/snow-system/src/main/java/com/snow/system/service/impl/SysDeptServiceImpl.java +++ b/snow-system/src/main/java/com/snow/system/service/impl/SysDeptServiceImpl.java @@ -5,8 +5,10 @@ import java.util.Iterator; import java.util.List; import com.snow.system.domain.SysDept; +import com.snow.system.event.SyncEvent; import org.apache.commons.lang3.ArrayUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.snow.common.annotation.DataScope; @@ -18,6 +20,8 @@ import com.snow.system.domain.SysRole; import com.snow.system.mapper.SysDeptMapper; import com.snow.system.service.ISysDeptService; +import javax.annotation.Resource; + /** * 部门管理 服务实现 * @@ -29,6 +33,9 @@ public class SysDeptServiceImpl implements ISysDeptService @Autowired private SysDeptMapper deptMapper; + @Resource + private ApplicationContext applicationContext; + /** * 查询部门管理数据 * @@ -204,6 +211,8 @@ public class SysDeptServiceImpl implements ISysDeptService throw new BusinessException("部门停用,不允许新增"); } dept.setAncestors(info.getAncestors() + "," + dept.getParentId()); + SyncEvent syncEvent = new SyncEvent(dept, 1, dept); + applicationContext.publishEvent(syncEvent); return deptMapper.insertDept(dept); } From 0d723be4ba6e7b1b276566bdc6398c5f2cdf39cb Mon Sep 17 00:00:00 2001 From: jinqiming <45981669@qq.com> Date: Fri, 18 Sep 2020 10:49:04 +0800 Subject: [PATCH 02/82] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=9B=91=E5=90=AC?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- snow-admin/pom.xml | 6 ++++ .../common/enums/DingTalkListenerType.java | 32 ++++++++++++++++++ .../com/snow/dingtalk/common/BaseService.java | 33 ++++++++++++++++--- .../{ => listener}/SyncEventListener.java | 22 +++++++++---- .../dingtalk/service/DepartmentService.java | 6 ++-- 5 files changed, 86 insertions(+), 13 deletions(-) create mode 100644 snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java rename snow-dingtalk/src/main/java/com/snow/dingtalk/{ => listener}/SyncEventListener.java (52%) diff --git a/snow-admin/pom.xml b/snow-admin/pom.xml index dd770d6..9c64e39 100644 --- a/snow-admin/pom.xml +++ b/snow-admin/pom.xml @@ -81,6 +81,12 @@ 4.3.1 + + com.snow + snow-dingtalk + 4.3.1 + + diff --git a/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java b/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java new file mode 100644 index 0000000..82d2948 --- /dev/null +++ b/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java @@ -0,0 +1,32 @@ +package com.snow.common.enums; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/9/18 10:18 + */ +public enum DingTalkListenerType { + DEPARTMENT_CREATE(1, "部门创建"), + DEPARTMENT_UPDATE(2, "部门更新"), + DEPARTMENT_DELETED(3, "部门删除"); + + private final Integer code; + private final String info; + + DingTalkListenerType(Integer code, String info) + { + this.code = code; + this.info = info; + } + + public Integer getCode() + { + return code; + } + + public String getInfo() + { + return info; + } +} diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseService.java index 57cc262..bcc8662 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseService.java @@ -7,6 +7,7 @@ import com.dingtalk.api.request.OapiGettokenRequest; import com.dingtalk.api.response.OapiGettokenResponse; import com.snow.common.constant.Constants; import com.snow.common.enums.BusinessType; +import com.snow.common.json.JSON; import com.snow.common.utils.StringUtils; import com.snow.system.domain.SysOperLog; import com.snow.system.service.ISysConfigService; @@ -47,15 +48,16 @@ public class BaseService { try { OapiGettokenResponse response = client.execute(request); if(response.getErrcode()==0){ - timedCache.put( TOKEN,response.getAccessToken()); + timedCache.put(TOKEN,response.getAccessToken()); + syncDingTalkErrorOperLog(BaseConstantUrl.GET_TOKEN_URL,response.getMessage(),"getDingTalkToken()", com.alibaba.fastjson.JSON.toJSONString(request)); return response.getAccessToken(); }else { //记录获取token失败日志 - syncDingTalkErrorOperLog(BaseConstantUrl.GET_TOKEN_URL,response.getErrmsg(),"getDingTalkToken()"); + syncDingTalkErrorOperLog(BaseConstantUrl.GET_TOKEN_URL,response.getErrmsg(),"getDingTalkToken()", com.alibaba.fastjson.JSON.toJSONString(request)); return null; } } catch (ApiException e) { - syncDingTalkErrorOperLog(BaseConstantUrl.GET_TOKEN_URL,e.getMessage(),"getDingTalkToken()"); + syncDingTalkErrorOperLog(BaseConstantUrl.GET_TOKEN_URL,e.getMessage(),"getDingTalkToken()",com.alibaba.fastjson.JSON.toJSONString(request)); e.printStackTrace(); } return null; @@ -71,7 +73,7 @@ public class BaseService { * @param errorMessage * @param method */ - public void syncDingTalkErrorOperLog(String url,String errorMessage,String method){ + public void syncDingTalkErrorOperLog(String url,String errorMessage,String method,String operParam){ SysOperLog sysOperLog=new SysOperLog(); sysOperLog.setOperTime(new Date()); sysOperLog.setErrorMsg(errorMessage); @@ -79,7 +81,30 @@ public class BaseService { sysOperLog.setOperName("系统自动记录"); sysOperLog.setOperUrl(url); sysOperLog.setMethod(method); + sysOperLog.setOperParam(operParam); sysOperLog.setTitle("系统调用钉钉异常"); + sysOperLog.setStatus(1); + iSysOperLogService.insertOperlog(sysOperLog); + } + + /** + * 成功 + * @param url + * @param successMessage + * @param method + * @param operParam + */ + public void syncDingTalkSuccessOperLog(String url,String successMessage,String method,String operParam){ + SysOperLog sysOperLog=new SysOperLog(); + sysOperLog.setOperTime(new Date()); + sysOperLog.setBusinessType(BusinessType.SYNCHRONIZATION.ordinal()); + sysOperLog.setJsonResult(successMessage); + sysOperLog.setOperName("系统自动记录"); + sysOperLog.setOperUrl(url); + sysOperLog.setMethod(method); + sysOperLog.setOperParam(operParam); + sysOperLog.setTitle("调用钉钉成功"); + sysOperLog.setStatus(0); iSysOperLogService.insertOperlog(sysOperLog); } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/SyncEventListener.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java similarity index 52% rename from snow-dingtalk/src/main/java/com/snow/dingtalk/SyncEventListener.java rename to snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java index da4d184..7d883e5 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/SyncEventListener.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java @@ -1,32 +1,40 @@ -package com.snow.dingtalk; +package com.snow.dingtalk.listener; import com.alibaba.fastjson.JSON; +import com.snow.common.enums.DingTalkListenerType; import com.snow.dingtalk.model.DepartmentDTO; import com.snow.dingtalk.service.DepartmentService; import com.snow.system.domain.SysDept; import com.snow.system.event.SyncEvent; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; /** * @author qimingjin - * @Title: + * @Title: 同步事件监听器 * @Description: * @date 2020/9/17 17:40 */ @Component +@Slf4j public class SyncEventListener implements ApplicationListener { @Autowired private DepartmentService departmentService; + @Override public void onApplicationEvent(SyncEvent syncEvent) { + log.info("进入监听器....."); Integer eventType = syncEvent.getEventType(); - SysDept sysDept=(SysDept)syncEvent.getT(); - DepartmentDTO departmentDTO = DepartmentDTO.builder().name(sysDept.getDeptName()).order(sysDept.getOrderNum()) - .parentid(sysDept.getParentName()).build(); - departmentService.createDepartment(departmentDTO); - System.out.println("监听到的事件类型:"+eventType+JSON.toJSONString(syncEvent)); + if(eventType==DingTalkListenerType.DEPARTMENT_CREATE.getCode()){ + SysDept sysDept=(SysDept)syncEvent.getT(); + DepartmentDTO departmentDTO = DepartmentDTO.builder().name(sysDept.getDeptName()).order(sysDept.getOrderNum()) + .parentid(sysDept.getParentName()).build(); + departmentService.createDepartment(departmentDTO); + } + + log.info("监听到的事件类型:"+eventType+JSON.toJSONString(syncEvent)); } } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/DepartmentService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/DepartmentService.java index 94d018b..9cd3441 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/DepartmentService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/DepartmentService.java @@ -1,5 +1,6 @@ package com.snow.dingtalk.service; +import com.alibaba.fastjson.JSON; import com.dingtalk.api.DefaultDingTalkClient; import com.dingtalk.api.DingTalkClient; import com.dingtalk.api.request.OapiDepartmentCreateRequest; @@ -37,12 +38,13 @@ public class DepartmentService extends BaseService { try { OapiDepartmentCreateResponse response = client.execute(request,getDingTalkToken()); if(response.getErrcode()==0){ + syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_CREATE,response.getMessage(),"createDepartment",JSON.toJSONString(request)); return response.getId(); }else { - syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_CREATE,response.getErrmsg(),"createDepartment"); + syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_CREATE,response.getErrmsg(),"createDepartment",JSON.toJSONString(request)); } } catch (ApiException e) { - syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_CREATE,e.getMessage(),"createDepartment"); + syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_CREATE,e.getMessage(),"createDepartment",JSON.toJSONString(request)); e.printStackTrace(); } return null; From 51170f41a85f76948f151d77a4948bb38c327d91 Mon Sep 17 00:00:00 2001 From: jinqiming <45981669@qq.com> Date: Fri, 18 Sep 2020 17:03:54 +0800 Subject: [PATCH 03/82] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=9B=91=E5=90=AC?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/snow/common/constant/Constants.java | 9 +- .../snow/dingtalk/common/BaseConstantUrl.java | 6 + .../dingtalk/listener/SyncEventListener.java | 4 +- ...tDTO.java => DepartmentCreateRequest.java} | 2 +- .../model/ProcessinstanceCreateRequest.java | 205 ++++++++++++++++++ .../dingtalk/service/DepartmentService.java | 5 +- .../service/ProcessInstanceService.java | 58 +++++ 7 files changed, 280 insertions(+), 9 deletions(-) rename snow-dingtalk/src/main/java/com/snow/dingtalk/model/{DepartmentDTO.java => DepartmentCreateRequest.java} (98%) create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/model/ProcessinstanceCreateRequest.java create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/service/ProcessInstanceService.java diff --git a/snow-common/src/main/java/com/snow/common/constant/Constants.java b/snow-common/src/main/java/com/snow/common/constant/Constants.java index 036f1f8..3715ad5 100644 --- a/snow-common/src/main/java/com/snow/common/constant/Constants.java +++ b/snow-common/src/main/java/com/snow/common/constant/Constants.java @@ -99,10 +99,13 @@ public class Constants /** * 钉钉企业内部APPkey */ - public static final String ENTERPRICE_APP_KEY="enterpriceAppKey"; + public static final String ENTERPRICE_APP_KEY="enterprice.app.key"; /** * 钉钉企业内部ENTERPRICE_APP_SECRET */ - public static final String ENTERPRICE_APP_SECRET="enterpriceAppSecret"; - + public static final String ENTERPRICE_APP_SECRET="enterprice.app.secret"; + /** + * 钉钉企业内部 AGENT_ID + */ + public static final String AGENT_ID="agent.id"; } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java index 77590b9..428a69f 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java @@ -15,4 +15,10 @@ public class BaseConstantUrl { * 创建部门 */ public static final String DEPARTMENT_CREATE="https://oapi.dingtalk.com/department/create"; + + /** + * 创建流程 + * + */ + public static final String FLOW_CREATE="https://oapi.dingtalk.com/topapi/processinstance/create"; } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java index 7d883e5..a52eb0c 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java @@ -2,7 +2,7 @@ package com.snow.dingtalk.listener; import com.alibaba.fastjson.JSON; import com.snow.common.enums.DingTalkListenerType; -import com.snow.dingtalk.model.DepartmentDTO; +import com.snow.dingtalk.model.DepartmentCreateRequest; import com.snow.dingtalk.service.DepartmentService; import com.snow.system.domain.SysDept; import com.snow.system.event.SyncEvent; @@ -30,7 +30,7 @@ public class SyncEventListener implements ApplicationListener { Integer eventType = syncEvent.getEventType(); if(eventType==DingTalkListenerType.DEPARTMENT_CREATE.getCode()){ SysDept sysDept=(SysDept)syncEvent.getT(); - DepartmentDTO departmentDTO = DepartmentDTO.builder().name(sysDept.getDeptName()).order(sysDept.getOrderNum()) + DepartmentCreateRequest departmentDTO = DepartmentCreateRequest.builder().name(sysDept.getDeptName()).order(sysDept.getOrderNum()) .parentid(sysDept.getParentName()).build(); departmentService.createDepartment(departmentDTO); } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/model/DepartmentDTO.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/model/DepartmentCreateRequest.java similarity index 98% rename from snow-dingtalk/src/main/java/com/snow/dingtalk/model/DepartmentDTO.java rename to snow-dingtalk/src/main/java/com/snow/dingtalk/model/DepartmentCreateRequest.java index 0ec6b1c..7f7679e 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/model/DepartmentDTO.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/model/DepartmentCreateRequest.java @@ -15,7 +15,7 @@ import lombok.NoArgsConstructor; @Builder @AllArgsConstructor @NoArgsConstructor -public class DepartmentDTO { +public class DepartmentCreateRequest { /** * 部门名称,长度限制为1~64个字符,不允许包含字符‘-’‘,’以及‘,’ */ diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/model/ProcessinstanceCreateRequest.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/model/ProcessinstanceCreateRequest.java new file mode 100644 index 0000000..8f52890 --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/model/ProcessinstanceCreateRequest.java @@ -0,0 +1,205 @@ +package com.snow.dingtalk.model; + +import com.dingtalk.api.request.OapiProcessinstanceCreateRequest; +import com.taobao.api.internal.mapping.ApiField; +import com.taobao.api.internal.mapping.ApiListField; +import com.taobao.api.internal.util.json.JSONWriter; +import lombok.NonNull; + +import java.util.List; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/9/18 15:26 + */ +public class ProcessinstanceCreateRequest { + /** + * + * 审批人userid列表,最大列表长度20。 + * + * 多个审批人用逗号分隔,按传入的顺序依次审批 + */ + private String approvers; + /** + * 审批人列表。 + * + * 支持会签/或签,优先级高于approvers变量 + */ + private String approversV2; + /** + *抄送人userid列表,最大列表长度:20。多个抄送人用逗号分隔。 + * + * 该参数需要与cc_position参数一起传,抄送人才会生效; + * + * 该参数需要与approvers或approvers_v2参数一起传,抄送人才会生效; + */ + private String ccList; + /** + * 抄送时间,分为(START, FINISH, START_FINISH),默认是START + */ + private String ccPosition; + /** + * 发起人所在的部门。 + * + * 如果发起人属于根部门,传-1 + */ + @NonNull + private Long deptId; + + private String formComponentValues; + /** + * 审批实例发起人的userid + */ + private String originatorUserId; + /** + * 审批流的唯一码,process_code就在审批流编辑的页面URL中 + */ + private String processCode; + + + public ProcessinstanceCreateRequest() { + } + + public void setApprovers(String approvers) { + this.approvers = approvers; + } + + public String getApprovers() { + return this.approvers; + } + + public void setApproversV2(String approversV2) { + this.approversV2 = approversV2; + } + + public void setApproversV2(List approversV2) { + this.approversV2 = (new JSONWriter(false, false, true)).write(approversV2); + } + + public String getApproversV2() { + return this.approversV2; + } + + public void setCcList(String ccList) { + this.ccList = ccList; + } + + public String getCcList() { + return this.ccList; + } + + public void setCcPosition(String ccPosition) { + this.ccPosition = ccPosition; + } + + public String getCcPosition() { + return this.ccPosition; + } + + public void setDeptId(Long deptId) { + this.deptId = deptId; + } + + public Long getDeptId() { + return this.deptId; + } + + public void setFormComponentValues(String formComponentValues) { + this.formComponentValues = formComponentValues; + } + + public void setFormComponentValues(List formComponentValues) { + this.formComponentValues = (new JSONWriter(false, false, true)).write(formComponentValues); + } + + public String getFormComponentValues() { + return this.formComponentValues; + } + + public void setOriginatorUserId(String originatorUserId) { + this.originatorUserId = originatorUserId; + } + + public String getOriginatorUserId() { + return this.originatorUserId; + } + + public void setProcessCode(String processCode) { + this.processCode = processCode; + } + + public String getProcessCode() { + return this.processCode; + } + + + + + + public static class ProcessInstanceApproverVo { + private static final long serialVersionUID = 7264365528946378186L; + @ApiField("task_action_type") + private String taskActionType; + @ApiListField("user_ids") + @ApiField("string") + private List userIds; + + public ProcessInstanceApproverVo() { + } + + public String getTaskActionType() { + return this.taskActionType; + } + + public void setTaskActionType(String taskActionType) { + this.taskActionType = taskActionType; + } + + public List getUserIds() { + return this.userIds; + } + + public void setUserIds(List userIds) { + this.userIds = userIds; + } + } + + public static class FormComponentValueVo { + private static final long serialVersionUID = 4315945541956941229L; + @ApiField("ext_value") + private String extValue; + @ApiField("name") + private String name; + @ApiField("value") + private String value; + + public FormComponentValueVo() { + } + + public String getExtValue() { + return this.extValue; + } + + public void setExtValue(String extValue) { + this.extValue = extValue; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return this.value; + } + + public void setValue(String value) { + this.value = value; + } + } +} diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/DepartmentService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/DepartmentService.java index 9cd3441..8bd484d 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/DepartmentService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/DepartmentService.java @@ -7,10 +7,9 @@ import com.dingtalk.api.request.OapiDepartmentCreateRequest; import com.dingtalk.api.response.OapiDepartmentCreateResponse; import com.snow.dingtalk.common.BaseConstantUrl; import com.snow.dingtalk.common.BaseService; -import com.snow.dingtalk.model.DepartmentDTO; +import com.snow.dingtalk.model.DepartmentCreateRequest; import com.taobao.api.ApiException; import com.taobao.api.Constants; -import org.slf4j.Logger; import org.springframework.stereotype.Service; /** @@ -26,7 +25,7 @@ public class DepartmentService extends BaseService { * @param departmentDTO * @return */ - public Long createDepartment(DepartmentDTO departmentDTO){ + public Long createDepartment(DepartmentCreateRequest departmentDTO){ DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.DEPARTMENT_CREATE); OapiDepartmentCreateRequest request = new OapiDepartmentCreateRequest(); request.setParentid(departmentDTO.getParentid()); diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/ProcessInstanceService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/ProcessInstanceService.java new file mode 100644 index 0000000..1322380 --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/ProcessInstanceService.java @@ -0,0 +1,58 @@ +package com.snow.dingtalk.service; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.dingtalk.api.DefaultDingTalkClient; +import com.dingtalk.api.request.OapiProcessinstanceCreateRequest; +import com.dingtalk.api.response.OapiProcessinstanceCreateResponse; +import com.snow.common.constant.Constants; +import com.snow.dingtalk.common.BaseConstantUrl; +import com.snow.dingtalk.common.BaseService; +import com.snow.dingtalk.model.ProcessinstanceCreateRequest; +import com.snow.system.service.ISysConfigService; +import com.snow.system.service.ISysOperLogService; +import com.taobao.api.ApiException; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/9/18 14:32 + */ +@Service +public class ProcessInstanceService extends BaseService { + @Autowired + private ISysConfigService isysConfigService; + + /** + * 创建流程 + * @param processinstanceCreateRequest + */ + public String create(ProcessinstanceCreateRequest processinstanceCreateRequest){ + DefaultDingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.FLOW_CREATE); + OapiProcessinstanceCreateRequest request = new OapiProcessinstanceCreateRequest(); + request.setAgentId(Long.parseLong(isysConfigService.selectConfigByKey(Constants.AGENT_ID))); + BeanUtils.copyProperties(processinstanceCreateRequest,request); + try { + OapiProcessinstanceCreateResponse response = client.execute(request,getDingTalkToken()); + if(response.getErrcode()==0){ + syncDingTalkErrorOperLog(BaseConstantUrl.FLOW_CREATE,response.getMessage(),"ProcessInstanceCreateRequest",JSON.toJSONString(request)); + return response.getProcessInstanceId(); + }else { + syncDingTalkErrorOperLog(BaseConstantUrl.FLOW_CREATE,response.getErrmsg(),"ProcessInstanceCreateRequest",JSON.toJSONString(request)); + } + } catch (ApiException e) { + syncDingTalkErrorOperLog(BaseConstantUrl.FLOW_CREATE,e.getMessage(),"ProcessInstanceCreateRequest",JSON.toJSONString(request)); + e.printStackTrace(); + } + return null; + } +} From 5b52ffdcdcb9a1efece7b27c61df4eff53fd58f4 Mon Sep 17 00:00:00 2001 From: jinqiming <45981669@qq.com> Date: Tue, 22 Sep 2020 17:08:49 +0800 Subject: [PATCH 04/82] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=B9=E6=8E=A5?= =?UTF-8?q?=E9=92=89=E9=92=89=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/templates/main.html | 13 + .../common/enums/DingTalkListenerType.java | 4 +- .../snow/common/enums/WorkRecordStatus.java | 30 ++ .../snow/dingtalk/common/BaseConstantUrl.java | 20 ++ .../dingtalk/listener/SyncEventListener.java | 3 + ...java => ProcessInstanceCreateRequest.java} | 10 +- .../dingtalk/model/UserCreateRequest.java | 263 ++++++++++++++++++ .../dingtalk/model/WorkrecordAddRequest.java | 174 ++++++++++++ .../model/WorkrecordGetbyuseridRequest.java | 17 ++ .../service/ProcessInstanceService.java | 11 +- .../snow/dingtalk/service/UserService.java | 54 ++++ .../dingtalk/service/WorkRecodeService.java | 111 ++++++++ .../java/com/snow/system/event/SyncEvent.java | 4 + .../service/impl/SysUserServiceImpl.java | 8 + 14 files changed, 707 insertions(+), 15 deletions(-) create mode 100644 snow-common/src/main/java/com/snow/common/enums/WorkRecordStatus.java rename snow-dingtalk/src/main/java/com/snow/dingtalk/model/{ProcessinstanceCreateRequest.java => ProcessInstanceCreateRequest.java} (92%) create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/model/UserCreateRequest.java create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/model/WorkrecordAddRequest.java create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/model/WorkrecordGetbyuseridRequest.java create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/service/UserService.java create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/service/WorkRecodeService.java diff --git a/snow-admin/src/main/resources/templates/main.html b/snow-admin/src/main/resources/templates/main.html index d622df2..29d4b53 100644 --- a/snow-admin/src/main/resources/templates/main.html +++ b/snow-admin/src/main/resources/templates/main.html @@ -1015,7 +1015,9 @@ + diff --git a/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java b/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java index 82d2948..e536d52 100644 --- a/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java +++ b/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java @@ -9,7 +9,9 @@ package com.snow.common.enums; public enum DingTalkListenerType { DEPARTMENT_CREATE(1, "部门创建"), DEPARTMENT_UPDATE(2, "部门更新"), - DEPARTMENT_DELETED(3, "部门删除"); + DEPARTMENT_DELETED(3, "部门删除"), + + USER_CREATED(4,"用户创建"); private final Integer code; private final String info; diff --git a/snow-common/src/main/java/com/snow/common/enums/WorkRecordStatus.java b/snow-common/src/main/java/com/snow/common/enums/WorkRecordStatus.java new file mode 100644 index 0000000..03d4891 --- /dev/null +++ b/snow-common/src/main/java/com/snow/common/enums/WorkRecordStatus.java @@ -0,0 +1,30 @@ +package com.snow.common.enums; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/9/21 15:21 + */ +public enum WorkRecordStatus { + FINISHED(1, "完成"), NO_FINISHED(0, "未完成"); + + private final Integer code; + private final String info; + + WorkRecordStatus(Integer code, String info) + { + this.code = code; + this.info = info; + } + + public Integer getCode() + { + return code; + } + + public String getInfo() + { + return info; + } +} diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java index 428a69f..504166d 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java @@ -7,6 +7,11 @@ package com.snow.dingtalk.common; * @date 2020/9/16 11:02 */ public class BaseConstantUrl { + + /** + * 创建用户 + */ + public static final String USER_CREATE="https://oapi.dingtalk.com/user/create"; /** * 获取token url */ @@ -21,4 +26,19 @@ public class BaseConstantUrl { * */ public static final String FLOW_CREATE="https://oapi.dingtalk.com/topapi/processinstance/create"; + + /** + * 创建任务待办 + */ + public static final String WORK_RECORD_CREATE="https://oapi.dingtalk.com/topapi/workrecord/add"; + + + /** + * 通过ID获取我的代办 + */ + public static final String GET_WORK_RECORD_USER_ID_="https://oapi.dingtalk.com/topapi/workrecord/getbyuserid"; + /** + * 更新待办 + */ + public static final String WORK_RECORD_UPDATE="https://oapi.dingtalk.com/topapi/workrecord/update"; } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java index a52eb0c..4174a8d 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java @@ -34,6 +34,9 @@ public class SyncEventListener implements ApplicationListener { .parentid(sysDept.getParentName()).build(); departmentService.createDepartment(departmentDTO); } + else if(eventType == DingTalkListenerType.USER_CREATED.getCode()){ + + } log.info("监听到的事件类型:"+eventType+JSON.toJSONString(syncEvent)); } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/model/ProcessinstanceCreateRequest.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/model/ProcessInstanceCreateRequest.java similarity index 92% rename from snow-dingtalk/src/main/java/com/snow/dingtalk/model/ProcessinstanceCreateRequest.java rename to snow-dingtalk/src/main/java/com/snow/dingtalk/model/ProcessInstanceCreateRequest.java index 8f52890..d8f0029 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/model/ProcessinstanceCreateRequest.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/model/ProcessInstanceCreateRequest.java @@ -1,6 +1,6 @@ package com.snow.dingtalk.model; -import com.dingtalk.api.request.OapiProcessinstanceCreateRequest; + import com.taobao.api.internal.mapping.ApiField; import com.taobao.api.internal.mapping.ApiListField; import com.taobao.api.internal.util.json.JSONWriter; @@ -14,7 +14,7 @@ import java.util.List; * @Description: * @date 2020/9/18 15:26 */ -public class ProcessinstanceCreateRequest { +public class ProcessInstanceCreateRequest { /** * * 审批人userid列表,最大列表长度20。 @@ -59,7 +59,7 @@ public class ProcessinstanceCreateRequest { private String processCode; - public ProcessinstanceCreateRequest() { + public ProcessInstanceCreateRequest() { } public void setApprovers(String approvers) { @@ -74,7 +74,7 @@ public class ProcessinstanceCreateRequest { this.approversV2 = approversV2; } - public void setApproversV2(List approversV2) { + public void setApproversV2(List approversV2) { this.approversV2 = (new JSONWriter(false, false, true)).write(approversV2); } @@ -110,7 +110,7 @@ public class ProcessinstanceCreateRequest { this.formComponentValues = formComponentValues; } - public void setFormComponentValues(List formComponentValues) { + public void setFormComponentValues(List formComponentValues) { this.formComponentValues = (new JSONWriter(false, false, true)).write(formComponentValues); } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/model/UserCreateRequest.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/model/UserCreateRequest.java new file mode 100644 index 0000000..51a398d --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/model/UserCreateRequest.java @@ -0,0 +1,263 @@ +package com.snow.dingtalk.model; + +import lombok.NonNull; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/9/22 14:59 + */ +public class UserCreateRequest { + /** + * 数组类型,数组里面值为整型,成员所属部门id列表 + */ + @NonNull + private String department; + /** + * 邮箱。长度为0~64个字符。企业内必须唯一,不可重复 + */ + private String email; + /** + * + * 扩展属性,可以设置多种属性(手机上最多显示10个扩展属性,具体显示哪些属性,请到OA管理后台->设置->通讯录信息设置和OA管理后台->设置->手机端显示信息设置)。 + * + * 该字段的值支持链接类型填写,同时链接支持变量通配符自动替换,目前支持通配符有:userid,corpid。示例: [工位地址](http://www.dingtalk.com?userid=#userid#&corpid=#corpid#) + */ + private String extattr; + /** + * 入职时间,Unix时间戳,单位ms + */ + private Long hiredDate; + /** + * 是否号码隐藏。true表示隐藏,false表示不隐藏。 + * + * 隐藏手机号后,手机号在个人资料页隐藏,但仍可对其发DING、发起钉钉免费商务电话。 + */ + private Boolean isHide; + /** + * + * 是否高管模式。true表示是,false表示不是。 + * + * 开启后,手机号码对所有员工隐藏。普通员工无法对其发DING、发起钉钉免费商务电话。 + * 高管之间不受影响。 + */ + private Boolean isSenior; + /** + * 员工工号。对应显示到OA后台和客户端个人资料的工号栏目。 + * + * 长度为0~64个字符 + */ + private String jobnumber; + /** + * 手机号码,企业内必须唯一,不可重复。如果是国际号码,请使用+xx-xxxxxx的格式 + */ + @NonNull + private String mobile; + /** + * 成员名称。 + * + * 长度为1~64个字符 + */ + @NonNull + private String name; + /** + * + * 在对应的部门中的排序, + * + * Map结构的json字符串,key是部门的id, value是人员在这个部门的排序值 + */ + private String orderInDepts; + /** + * + * 员工的企业邮箱,员工的企业邮箱已开通,才能增加此字段, 否则会报错 + */ + private String orgEmail; + /** + * 职位信息。 + * + * 长度为0~64个字符 + */ + private String position; + /** + * + * 设置用户在每个部门下的职位。 + * + * Map结构的json字符串, + * + * Map的Key是deptId,表示部门id, + * + * Map的Value是职位,表示在这个部门下的职位 + */ + private String positionInDepts; + /** + * 备注,长度为0~1000个字符 + */ + private String remark; + /** + * 分机号,长度为0~50个字符,企业内必须唯一,不可重复 + */ + private String tel; + /** + * 员工在当前企业内的唯一标识,也称staffId。可由企业在创建时指定,并代表一定含义比如工号,创建后不可修改,企业内必须唯一。 + * + * 长度为1~64个字符,如果不传,服务器将自动生成一个userid。 + */ + private String userid; + /** + *办公地点,长度为0~50个字符 + */ + private String workPlace; + + + public UserCreateRequest() { + } + + public void setDepartment(String department) { + this.department = department; + } + + public String getDepartment() { + return this.department; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getEmail() { + return this.email; + } + + public void setExtattr(String extattr) { + this.extattr = extattr; + } + + public void setExtattrString(String extattr) { + this.extattr = extattr; + } + + public String getExtattr() { + return this.extattr; + } + + public void setHiredDate(Long hiredDate) { + this.hiredDate = hiredDate; + } + + public Long getHiredDate() { + return this.hiredDate; + } + + public void setIsHide(Boolean isHide) { + this.isHide = isHide; + } + + public Boolean getIsHide() { + return this.isHide; + } + + public void setIsSenior(Boolean isSenior) { + this.isSenior = isSenior; + } + + public Boolean getIsSenior() { + return this.isSenior; + } + + public void setJobnumber(String jobnumber) { + this.jobnumber = jobnumber; + } + + public String getJobnumber() { + return this.jobnumber; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } + + public String getMobile() { + return this.mobile; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + + public void setOrderInDepts(String orderInDepts) { + this.orderInDepts = orderInDepts; + } + + public void setOrderInDeptsString(String orderInDepts) { + this.orderInDepts = orderInDepts; + } + + public String getOrderInDepts() { + return this.orderInDepts; + } + + public void setOrgEmail(String orgEmail) { + this.orgEmail = orgEmail; + } + + public String getOrgEmail() { + return this.orgEmail; + } + + public void setPosition(String position) { + this.position = position; + } + + public String getPosition() { + return this.position; + } + + public void setPositionInDepts(String positionInDepts) { + this.positionInDepts = positionInDepts; + } + + public void setPositionInDeptsString(String positionInDepts) { + this.positionInDepts = positionInDepts; + } + + public String getPositionInDepts() { + return this.positionInDepts; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getRemark() { + return this.remark; + } + + public void setTel(String tel) { + this.tel = tel; + } + + public String getTel() { + return this.tel; + } + + public void setUserid(String userid) { + this.userid = userid; + } + + public String getUserid() { + return this.userid; + } + + public void setWorkPlace(String workPlace) { + this.workPlace = workPlace; + } + + public String getWorkPlace() { + return this.workPlace; + } +} diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/model/WorkrecordAddRequest.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/model/WorkrecordAddRequest.java new file mode 100644 index 0000000..310b4a6 --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/model/WorkrecordAddRequest.java @@ -0,0 +1,174 @@ +package com.snow.dingtalk.model; + +import com.taobao.api.internal.mapping.ApiField; +import com.taobao.api.internal.util.json.JSONWriter; +import lombok.NonNull; + +import java.util.List; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/9/21 14:37 + */ +public class WorkrecordAddRequest { + /** + * 外部业务id,建议带上业务方来源字段,防止与其他业务方冲突 + */ + private String bizId; + /** + * 待办时间。Unix时间戳,毫秒级 + */ + private Long createTime; + /** + * 待办事项表单 + */ + private String formItemList; + + /** + * pc端跳转url,不传则使用url参数 + */ + private String pcUrl; + /** + * 待办的pc打开方式。2表示在pc端打开,4表示在浏览器打开 + */ + private Long pcOpenType; + /** + * 待办来源名称 + */ + private String sourceName; + /** + * 待办事项的标题,最多50个字符 + */ + @NonNull + private String title; + /** + * 待办事项的跳转链接。当链接是某个微应用链接时,希望在PC端工作台打开,可通过该方式实现。 + */ + @NonNull + private String url; + /** + * 待办事项对应的用户id + */ + @NonNull + private String userid; + + + public WorkrecordAddRequest() { + } + + public void setBizId(String bizId) { + this.bizId = bizId; + } + + public String getBizId() { + return this.bizId; + } + + public void setCreateTime(Long createTime) { + this.createTime = createTime; + } + + public Long getCreateTime() { + return this.createTime; + } + + public void setFormItemList(String formItemList) { + this.formItemList = formItemList; + } + + public void setFormItemList(List formItemList) { + this.formItemList = (new JSONWriter(false, false, true)).write(formItemList); + } + + public String getFormItemList() { + return this.formItemList; + } + + + + public void setPcUrl(String pcUrl) { + this.pcUrl = pcUrl; + } + + public String getPcUrl() { + return this.pcUrl; + } + + public void setPcOpenType(Long pcOpenType) { + this.pcOpenType = pcOpenType; + } + + public Long getPcOpenType() { + return this.pcOpenType; + } + + public void setSourceName(String sourceName) { + this.sourceName = sourceName; + } + + public String getSourceName() { + return this.sourceName; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getTitle() { + return this.title; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getUrl() { + return this.url; + } + + public void setUserid(String userid) { + this.userid = userid; + } + + public String getUserid() { + return this.userid; + } + + /** + * 待办事项表单 + */ + public static class FormItemVo { + private static final long serialVersionUID = 1767476148969288532L; + /** + * 表单标题 + */ + @ApiField("content") + private String content; + /** + * 表单内容 + */ + @ApiField("title") + private String title; + + public FormItemVo() { + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + } +} diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/model/WorkrecordGetbyuseridRequest.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/model/WorkrecordGetbyuseridRequest.java new file mode 100644 index 0000000..3f536c1 --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/model/WorkrecordGetbyuseridRequest.java @@ -0,0 +1,17 @@ +package com.snow.dingtalk.model; + +import lombok.Data; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/9/21 15:19 + */ +@Data +public class WorkrecordGetbyuseridRequest { + private Long limit; + private Long offset; + private Long status; + private String userid; +} diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/ProcessInstanceService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/ProcessInstanceService.java index 1322380..7a2da00 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/ProcessInstanceService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/ProcessInstanceService.java @@ -1,26 +1,19 @@ package com.snow.dingtalk.service; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; import com.dingtalk.api.DefaultDingTalkClient; import com.dingtalk.api.request.OapiProcessinstanceCreateRequest; import com.dingtalk.api.response.OapiProcessinstanceCreateResponse; import com.snow.common.constant.Constants; import com.snow.dingtalk.common.BaseConstantUrl; import com.snow.dingtalk.common.BaseService; -import com.snow.dingtalk.model.ProcessinstanceCreateRequest; +import com.snow.dingtalk.model.ProcessInstanceCreateRequest; import com.snow.system.service.ISysConfigService; -import com.snow.system.service.ISysOperLogService; import com.taobao.api.ApiException; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - /** * @author qimingjin * @Title: @@ -36,7 +29,7 @@ public class ProcessInstanceService extends BaseService { * 创建流程 * @param processinstanceCreateRequest */ - public String create(ProcessinstanceCreateRequest processinstanceCreateRequest){ + public String create(ProcessInstanceCreateRequest processinstanceCreateRequest){ DefaultDingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.FLOW_CREATE); OapiProcessinstanceCreateRequest request = new OapiProcessinstanceCreateRequest(); request.setAgentId(Long.parseLong(isysConfigService.selectConfigByKey(Constants.AGENT_ID))); diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/UserService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/UserService.java new file mode 100644 index 0000000..16d41b3 --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/UserService.java @@ -0,0 +1,54 @@ +package com.snow.dingtalk.service; + +import com.alibaba.fastjson.JSON; +import com.dingtalk.api.DefaultDingTalkClient; +import com.dingtalk.api.DingTalkClient; +import com.dingtalk.api.request.OapiUserCreateRequest; +import com.dingtalk.api.request.OapiWorkrecordAddRequest; +import com.dingtalk.api.response.OapiUserCreateResponse; +import com.dingtalk.api.response.OapiWorkrecordAddResponse; +import com.snow.dingtalk.common.BaseConstantUrl; +import com.snow.dingtalk.common.BaseService; +import com.snow.dingtalk.model.WorkrecordAddRequest; +import com.snow.system.service.ISysConfigService; +import com.taobao.api.ApiException; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/9/22 14:29 + */ +@Service +public class UserService extends BaseService { + @Autowired + private ISysConfigService isysConfigService; + + /** + * 创建工作待办 + * @param workrecordAddRequest + * @return + */ + public String create(WorkrecordAddRequest workrecordAddRequest){ + DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.USER_CREATE); + OapiUserCreateRequest request = new OapiUserCreateRequest(); + BeanUtils.copyProperties(workrecordAddRequest,request); + try { + OapiUserCreateResponse response = client.execute(request, getDingTalkToken()); + if (response.getErrcode()==0){ + syncDingTalkErrorOperLog(BaseConstantUrl.USER_CREATE,response.getMessage(),"UserCreateRequest",JSON.toJSONString(request)); + return response.getUserid(); + }else { + syncDingTalkErrorOperLog(BaseConstantUrl.USER_CREATE,response.getErrmsg(),"UserCreateRequest",JSON.toJSONString(request)); + } + } catch (ApiException e) { + e.printStackTrace(); + syncDingTalkErrorOperLog(BaseConstantUrl.USER_CREATE,e.getMessage(),"UserCreateRequest",JSON.toJSONString(request)); + } + return null; + } + +} diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/WorkRecodeService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/WorkRecodeService.java new file mode 100644 index 0000000..8a7e798 --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/WorkRecodeService.java @@ -0,0 +1,111 @@ +package com.snow.dingtalk.service; + +import com.alibaba.fastjson.JSON; +import com.dingtalk.api.DefaultDingTalkClient; +import com.dingtalk.api.DingTalkClient; +import com.dingtalk.api.request.OapiWorkrecordAddRequest; +import com.dingtalk.api.request.OapiWorkrecordGetbyuseridRequest; +import com.dingtalk.api.request.OapiWorkrecordUpdateRequest; +import com.dingtalk.api.response.OapiWorkrecordAddResponse; +import com.dingtalk.api.response.OapiWorkrecordGetbyuseridResponse; +import com.dingtalk.api.response.OapiWorkrecordUpdateResponse; +import com.snow.dingtalk.common.BaseConstantUrl; +import com.snow.dingtalk.common.BaseService; +import com.snow.dingtalk.model.WorkrecordAddRequest; +import com.snow.dingtalk.model.WorkrecordGetbyuseridRequest; +import com.snow.system.service.ISysConfigService; +import com.taobao.api.ApiException; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/9/21 14:28 + */ +@Service +public class WorkRecodeService extends BaseService { + @Autowired + private ISysConfigService isysConfigService; + + /** + * 创建工作待办 + * @param workrecordAddRequest + * @return + */ + public String create(WorkrecordAddRequest workrecordAddRequest){ + DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.WORK_RECORD_CREATE); + OapiWorkrecordAddRequest req = new OapiWorkrecordAddRequest(); + BeanUtils.copyProperties(workrecordAddRequest,req); + OapiWorkrecordAddResponse rsp = null; + try { + rsp = client.execute(req, getDingTalkToken()); + if (rsp.getErrcode()==0){ + syncDingTalkErrorOperLog(BaseConstantUrl.WORK_RECORD_CREATE,rsp.getMessage(),"WorkRecordAddRequest",JSON.toJSONString(req)); + return rsp.getRecordId(); + }else { + syncDingTalkErrorOperLog(BaseConstantUrl.WORK_RECORD_CREATE,rsp.getErrmsg(),"WorkRecordAddRequest",JSON.toJSONString(req)); + } + } catch (ApiException e) { + e.printStackTrace(); + syncDingTalkErrorOperLog(BaseConstantUrl.WORK_RECORD_CREATE,e.getMessage(),"WorkRecordAddRequest",JSON.toJSONString(req)); + } + return null; + } + + /** + * 根据用户ID获取待办 + * @param workrecordGetbyuseridRequest + * @return + */ + public OapiWorkrecordGetbyuseridResponse.PageResult getWorkRecordByUserId(WorkrecordGetbyuseridRequest workrecordGetbyuseridRequest){ + DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.GET_WORK_RECORD_USER_ID_); + OapiWorkrecordGetbyuseridRequest req = new OapiWorkrecordGetbyuseridRequest(); + req.setUserid(workrecordGetbyuseridRequest.getUserid()); + req.setOffset(workrecordGetbyuseridRequest.getOffset()); + req.setLimit(workrecordGetbyuseridRequest.getLimit()); + req.setStatus(workrecordGetbyuseridRequest.getStatus()); + try { + OapiWorkrecordGetbyuseridResponse rsp = client.execute(req, getDingTalkToken()); + if(rsp.getErrcode()==0){ + syncDingTalkErrorOperLog(BaseConstantUrl.GET_WORK_RECORD_USER_ID_,rsp.getMessage(),"WorkrecordGetbyuseridRequest",JSON.toJSONString(req)); + return rsp.getRecords(); + }else { + syncDingTalkErrorOperLog(BaseConstantUrl.GET_WORK_RECORD_USER_ID_,rsp.getErrmsg(),"WorkrecordGetbyuseridRequest",JSON.toJSONString(req)); + } + } catch (ApiException e) { + e.printStackTrace(); + syncDingTalkErrorOperLog(BaseConstantUrl.GET_WORK_RECORD_USER_ID_,e.getMessage(),"WorkrecordGetbyuseridRequest",JSON.toJSONString(req)); + } + return null; + } + + /** + * 更新待办 + * @param userId + * @param recordId + * @return + */ + public Boolean update(String userId,String recordId){ + DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.WORK_RECORD_UPDATE); + OapiWorkrecordUpdateRequest req = new OapiWorkrecordUpdateRequest(); + req.setUserid(userId); + req.setRecordId(recordId); + OapiWorkrecordUpdateResponse rsp = null; + try { + rsp = client.execute(req, getDingTalkToken()); + if(rsp.getErrcode()==0){ + syncDingTalkErrorOperLog(BaseConstantUrl.WORK_RECORD_UPDATE,rsp.getMessage(),"WorkrecordUpdateRequest",JSON.toJSONString(req)); + return rsp.getResult(); + }else { + syncDingTalkErrorOperLog(BaseConstantUrl.WORK_RECORD_UPDATE,rsp.getErrmsg(),"WorkrecordUpdateRequest",JSON.toJSONString(req)); + } + } catch (ApiException e) { + e.printStackTrace(); + syncDingTalkErrorOperLog(BaseConstantUrl.WORK_RECORD_UPDATE,e.getMessage(),"WorkrecordUpdateRequest",JSON.toJSONString(req)); + } + return false; + } +} diff --git a/snow-system/src/main/java/com/snow/system/event/SyncEvent.java b/snow-system/src/main/java/com/snow/system/event/SyncEvent.java index a8317c1..bdf6aec 100644 --- a/snow-system/src/main/java/com/snow/system/event/SyncEvent.java +++ b/snow-system/src/main/java/com/snow/system/event/SyncEvent.java @@ -14,12 +14,15 @@ public class SyncEvent extends ApplicationEvent { private T t; + + public SyncEvent(Object source,Integer eventType,T t) { super(source); this.eventType = eventType; this.t=t; } + public T getT() { return t; } @@ -35,4 +38,5 @@ public class SyncEvent extends ApplicationEvent { public void setEventType(Integer eventType) { this.eventType = eventType; } + } diff --git a/snow-system/src/main/java/com/snow/system/service/impl/SysUserServiceImpl.java b/snow-system/src/main/java/com/snow/system/service/impl/SysUserServiceImpl.java index 99042cd..7eb4fbf 100644 --- a/snow-system/src/main/java/com/snow/system/service/impl/SysUserServiceImpl.java +++ b/snow-system/src/main/java/com/snow/system/service/impl/SysUserServiceImpl.java @@ -5,9 +5,11 @@ import java.util.List; import com.snow.system.domain.SysUserPost; import com.snow.system.domain.SysUserRole; +import com.snow.system.event.SyncEvent; 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 org.springframework.transaction.annotation.Transactional; import com.snow.common.annotation.DataScope; @@ -55,6 +57,9 @@ public class SysUserServiceImpl implements ISysUserService @Autowired private ISysConfigService configService; + @Autowired + private ApplicationContext applicationContext; + /** * 根据条件分页查询用户列表 * @@ -203,6 +208,9 @@ public class SysUserServiceImpl implements ISysUserService insertUserPost(user); // 新增用户与角色管理 insertUserRole(user.getUserId(), user.getRoleIds()); + //同步用户数据 + SyncEvent syncEvent = new SyncEvent(user, 4, user); + applicationContext.publishEvent(syncEvent); return rows; } From 925268f83a72fd7c69ff39c5c135a01c83c7cfd7 Mon Sep 17 00:00:00 2001 From: jinqiming <45981669@qq.com> Date: Mon, 28 Sep 2020 10:37:19 +0800 Subject: [PATCH 05/82] =?UTF-8?q?=E6=8A=8A=E7=9B=91=E5=90=AC=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E6=94=B9=E6=88=90=E5=B7=A5=E5=8E=82=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DepartmentCreateEventService.java | 27 +++++++++++++++++ .../dingtalk/listener/ISyncDingTalkInfo.java | 17 +++++++++++ .../listener/SyncDingTalkInfoFactory.java | 29 +++++++++++++++++++ .../dingtalk/listener/SyncEventListener.java | 27 ++++------------- .../listener/UserCreateEventService.java | 16 ++++++++++ .../snow/dingtalk/service/UserService.java | 2 -- 6 files changed, 95 insertions(+), 23 deletions(-) create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/listener/DepartmentCreateEventService.java create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/listener/ISyncDingTalkInfo.java create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/listener/UserCreateEventService.java diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/DepartmentCreateEventService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/DepartmentCreateEventService.java new file mode 100644 index 0000000..75bdbce --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/DepartmentCreateEventService.java @@ -0,0 +1,27 @@ +package com.snow.dingtalk.listener; + +import com.snow.dingtalk.model.DepartmentCreateRequest; +import com.snow.dingtalk.service.DepartmentService; +import com.snow.system.domain.SysDept; +import com.snow.system.event.SyncEvent; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @author qimingjin + * @Title: 创建部门数据同步 + * @Description: + * @date 2020/9/28 9:33 + */ +public class DepartmentCreateEventService implements ISyncDingTalkInfo { + + @Autowired + private DepartmentService departmentService; + + @Override + public void syncDingTalkInfoEvent(SyncEvent syncEvent) { + SysDept sysDept=(SysDept)syncEvent.getT(); + DepartmentCreateRequest departmentDTO = DepartmentCreateRequest.builder().name(sysDept.getDeptName()).order(sysDept.getOrderNum()) + .parentid(sysDept.getParentName()).build(); + departmentService.createDepartment(departmentDTO); + } +} diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/ISyncDingTalkInfo.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/ISyncDingTalkInfo.java new file mode 100644 index 0000000..1790b4f --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/ISyncDingTalkInfo.java @@ -0,0 +1,17 @@ +package com.snow.dingtalk.listener; + +import com.snow.system.event.SyncEvent; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/9/28 9:31 + */ +public interface ISyncDingTalkInfo { + /** + * 同步钉钉事件 + * @param syncEvent + */ + void syncDingTalkInfoEvent(SyncEvent syncEvent); +} diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java new file mode 100644 index 0000000..249eacc --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java @@ -0,0 +1,29 @@ +package com.snow.dingtalk.listener; + +import com.snow.common.enums.DingTalkListenerType; +import com.snow.system.event.SyncEvent; +import lombok.extern.slf4j.Slf4j; + +/** + * @author qimingjin + * @Title: 创建同步钉钉数据工厂类 + * @Description: + * @date 2020/9/28 9:43 + */ +@Slf4j +public class SyncDingTalkInfoFactory { + + public ISyncDingTalkInfo getSyncDingTalkService(SyncEvent syncEvent){ + + Integer eventType = syncEvent.getEventType(); + if(eventType.equals(DingTalkListenerType.DEPARTMENT_CREATE.getCode())){ + return new DepartmentCreateEventService(); + } + else if(eventType.equals(DingTalkListenerType.USER_CREATED.getCode())){ + return new UserCreateEventService(); + }else { + throw new RuntimeException("不存在的监听类型"); + } + + } +} diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java index 4174a8d..b567aae 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java @@ -1,19 +1,14 @@ package com.snow.dingtalk.listener; import com.alibaba.fastjson.JSON; -import com.snow.common.enums.DingTalkListenerType; -import com.snow.dingtalk.model.DepartmentCreateRequest; -import com.snow.dingtalk.service.DepartmentService; -import com.snow.system.domain.SysDept; import com.snow.system.event.SyncEvent; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; /** * @author qimingjin - * @Title: 同步事件监听器 + * @Title: 同步事件监听器工厂 * @Description: * @date 2020/9/17 17:40 */ @@ -21,23 +16,13 @@ import org.springframework.stereotype.Component; @Slf4j public class SyncEventListener implements ApplicationListener { - @Autowired - private DepartmentService departmentService; - @Override public void onApplicationEvent(SyncEvent syncEvent) { log.info("进入监听器....."); - Integer eventType = syncEvent.getEventType(); - if(eventType==DingTalkListenerType.DEPARTMENT_CREATE.getCode()){ - SysDept sysDept=(SysDept)syncEvent.getT(); - DepartmentCreateRequest departmentDTO = DepartmentCreateRequest.builder().name(sysDept.getDeptName()).order(sysDept.getOrderNum()) - .parentid(sysDept.getParentName()).build(); - departmentService.createDepartment(departmentDTO); - } - else if(eventType == DingTalkListenerType.USER_CREATED.getCode()){ - - } - - log.info("监听到的事件类型:"+eventType+JSON.toJSONString(syncEvent)); + SyncDingTalkInfoFactory syncEventListenerFactory = new SyncDingTalkInfoFactory(); + syncEventListenerFactory.getSyncDingTalkService(syncEvent); + log.info("监听到的事件类型:"+JSON.toJSONString(syncEvent)); } + + } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/UserCreateEventService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/UserCreateEventService.java new file mode 100644 index 0000000..29e44dc --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/UserCreateEventService.java @@ -0,0 +1,16 @@ +package com.snow.dingtalk.listener; + +import com.snow.system.event.SyncEvent; + +/** + * @author qimingjin + * @Title: 创建用户 + * @Description: + * @date 2020/9/28 9:34 + */ +public class UserCreateEventService implements ISyncDingTalkInfo { + @Override + public void syncDingTalkInfoEvent(SyncEvent syncEvent) { + + } +} diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/UserService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/UserService.java index 16d41b3..b5c469b 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/UserService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/UserService.java @@ -4,9 +4,7 @@ import com.alibaba.fastjson.JSON; import com.dingtalk.api.DefaultDingTalkClient; import com.dingtalk.api.DingTalkClient; import com.dingtalk.api.request.OapiUserCreateRequest; -import com.dingtalk.api.request.OapiWorkrecordAddRequest; import com.dingtalk.api.response.OapiUserCreateResponse; -import com.dingtalk.api.response.OapiWorkrecordAddResponse; import com.snow.dingtalk.common.BaseConstantUrl; import com.snow.dingtalk.common.BaseService; import com.snow.dingtalk.model.WorkrecordAddRequest; From 671671882e125f22603ff0c6d48951813fa68e05 Mon Sep 17 00:00:00 2001 From: jinqiming <45981669@qq.com> Date: Mon, 28 Sep 2020 10:51:01 +0800 Subject: [PATCH 06/82] =?UTF-8?q?=E6=8A=8A=E7=9B=91=E5=90=AC=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E6=94=B9=E6=88=90=E5=B7=A5=E5=8E=82=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../listener/DepartmentCreateEventService.java | 11 +++++++++-- .../com/snow/dingtalk/listener/SyncEventListener.java | 3 ++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/DepartmentCreateEventService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/DepartmentCreateEventService.java index 75bdbce..a71e644 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/DepartmentCreateEventService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/DepartmentCreateEventService.java @@ -1,9 +1,11 @@ package com.snow.dingtalk.listener; +import com.alibaba.fastjson.JSON; import com.snow.dingtalk.model.DepartmentCreateRequest; import com.snow.dingtalk.service.DepartmentService; import com.snow.system.domain.SysDept; import com.snow.system.event.SyncEvent; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; /** @@ -12,6 +14,7 @@ import org.springframework.beans.factory.annotation.Autowired; * @Description: * @date 2020/9/28 9:33 */ +@Slf4j public class DepartmentCreateEventService implements ISyncDingTalkInfo { @Autowired @@ -19,9 +22,13 @@ public class DepartmentCreateEventService implements ISyncDingTalkInfo { @Override public void syncDingTalkInfoEvent(SyncEvent syncEvent) { + log.info("调用创建钉钉组织架构传入的原始参数:{}"+JSON.toJSONString(syncEvent)); SysDept sysDept=(SysDept)syncEvent.getT(); - DepartmentCreateRequest departmentDTO = DepartmentCreateRequest.builder().name(sysDept.getDeptName()).order(sysDept.getOrderNum()) - .parentid(sysDept.getParentName()).build(); + DepartmentCreateRequest departmentDTO = DepartmentCreateRequest.builder() + .name(sysDept.getDeptName()) + .order(sysDept.getOrderNum()) + .parentid(sysDept.getParentName()) + .build(); departmentService.createDepartment(departmentDTO); } } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java index b567aae..d10103c 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncEventListener.java @@ -20,7 +20,8 @@ public class SyncEventListener implements ApplicationListener { public void onApplicationEvent(SyncEvent syncEvent) { log.info("进入监听器....."); SyncDingTalkInfoFactory syncEventListenerFactory = new SyncDingTalkInfoFactory(); - syncEventListenerFactory.getSyncDingTalkService(syncEvent); + ISyncDingTalkInfo syncDingTalkService = syncEventListenerFactory.getSyncDingTalkService(syncEvent); + syncDingTalkService.syncDingTalkInfoEvent(syncEvent); log.info("监听到的事件类型:"+JSON.toJSONString(syncEvent)); } From ee0a0dfbcc24e91fd399d25748753ba3ff188885 Mon Sep 17 00:00:00 2001 From: "459816669@qq.com" <459816669@qq.com> Date: Sat, 31 Oct 2020 13:51:08 +0800 Subject: [PATCH 07/82] =?UTF-8?q?=E4=BF=AE=E6=94=B9service=E6=B3=A8?= =?UTF-8?q?=E5=85=A5=E4=B8=BAnull?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 ++ snow-admin/pom.xml | 1 + snow-dingtalk/pom.xml | 2 +- .../snow/dingtalk/common/BaseConstantUrl.java | 5 ++ .../com/snow/dingtalk/common/BaseService.java | 20 ++--- .../DepartmentCreateEventService.java | 9 +- .../listener/SyncDingTalkInfoFactory.java | 3 + .../dingtalk/service/DepartmentService.java | 44 +++------- .../service/ProcessInstanceService.java | 6 +- .../service/impl/DepartmentServiceImpl.java | 87 +++++++++++++++++++ .../service/impl/SysConfigServiceImpl.java | 2 +- 11 files changed, 134 insertions(+), 51 deletions(-) create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/DepartmentServiceImpl.java diff --git a/pom.xml b/pom.xml index a27419b..0f7a263 100644 --- a/pom.xml +++ b/pom.xml @@ -202,6 +202,12 @@ ${ruoyi.version} + + com.snow + snow-dingtalk + ${ruoyi.version} + + diff --git a/snow-admin/pom.xml b/snow-admin/pom.xml index 9c64e39..31f498c 100644 --- a/snow-admin/pom.xml +++ b/snow-admin/pom.xml @@ -81,6 +81,7 @@ 4.3.1 + com.snow snow-dingtalk diff --git a/snow-dingtalk/pom.xml b/snow-dingtalk/pom.xml index b072cb6..ad0bbf0 100644 --- a/snow-dingtalk/pom.xml +++ b/snow-dingtalk/pom.xml @@ -16,7 +16,7 @@ com.snow - snow-system + snow-framework 4.3.1 diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java index 504166d..be34f4a 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java @@ -21,6 +21,11 @@ public class BaseConstantUrl { */ public static final String DEPARTMENT_CREATE="https://oapi.dingtalk.com/department/create"; + /** + * 获取钉钉部门信息 + */ + public static final String DEPARTMENT_LIST="https://oapi.dingtalk.com/department/list"; + /** * 创建流程 * diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseService.java index bcc8662..00f9500 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseService.java @@ -7,14 +7,14 @@ import com.dingtalk.api.request.OapiGettokenRequest; import com.dingtalk.api.response.OapiGettokenResponse; import com.snow.common.constant.Constants; import com.snow.common.enums.BusinessType; -import com.snow.common.json.JSON; import com.snow.common.utils.StringUtils; +import com.snow.common.utils.spring.SpringUtils; import com.snow.system.domain.SysOperLog; import com.snow.system.service.ISysConfigService; import com.snow.system.service.ISysOperLogService; +import com.snow.system.service.impl.SysConfigServiceImpl; +import com.snow.system.service.impl.SysOperLogServiceImpl; import com.taobao.api.ApiException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; import java.util.Date; @@ -26,11 +26,11 @@ import java.util.Date; */ public class BaseService { - public static final String TOKEN="token"; - @Autowired - private ISysConfigService isysConfigService; - @Autowired - private ISysOperLogService iSysOperLogService; + public static final String TOKEN="dingtalk_token"; + + private SysConfigServiceImpl sysConfigService=SpringUtils.getBean("sysConfigServiceImpl"); + + private SysOperLogServiceImpl iSysOperLogService=SpringUtils.getBean("sysOperLogServiceImpl"); /** * 获取token @@ -42,8 +42,8 @@ public class BaseService { if(StringUtils.isEmpty(timedCache.get(TOKEN))){ DefaultDingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.GET_TOKEN_URL); OapiGettokenRequest request = new OapiGettokenRequest(); - request.setAppkey(isysConfigService.selectConfigByKey(Constants.ENTERPRICE_APP_KEY)); - request.setAppsecret(isysConfigService.selectConfigByKey(Constants.ENTERPRICE_APP_SECRET)); + request.setAppkey(sysConfigService.selectConfigByKey(Constants.ENTERPRICE_APP_KEY)); + request.setAppsecret(sysConfigService.selectConfigByKey(Constants.ENTERPRICE_APP_SECRET)); request.setHttpMethod(Constants.GET); try { OapiGettokenResponse response = client.execute(request); diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/DepartmentCreateEventService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/DepartmentCreateEventService.java index a71e644..2f0b930 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/DepartmentCreateEventService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/DepartmentCreateEventService.java @@ -1,12 +1,12 @@ package com.snow.dingtalk.listener; import com.alibaba.fastjson.JSON; +import com.snow.common.utils.spring.SpringUtils; import com.snow.dingtalk.model.DepartmentCreateRequest; -import com.snow.dingtalk.service.DepartmentService; +import com.snow.dingtalk.service.impl.DepartmentServiceImpl; import com.snow.system.domain.SysDept; import com.snow.system.event.SyncEvent; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; /** * @author qimingjin @@ -17,8 +17,9 @@ import org.springframework.beans.factory.annotation.Autowired; @Slf4j public class DepartmentCreateEventService implements ISyncDingTalkInfo { - @Autowired - private DepartmentService departmentService; + + private DepartmentServiceImpl departmentService=SpringUtils.getBean("departmentServiceImpl"); + @Override public void syncDingTalkInfoEvent(SyncEvent syncEvent) { diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java index 249eacc..bcce8f6 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java @@ -3,6 +3,7 @@ package com.snow.dingtalk.listener; import com.snow.common.enums.DingTalkListenerType; import com.snow.system.event.SyncEvent; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; /** * @author qimingjin @@ -13,6 +14,8 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class SyncDingTalkInfoFactory { + + public ISyncDingTalkInfo getSyncDingTalkService(SyncEvent syncEvent){ Integer eventType = syncEvent.getEventType(); diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/DepartmentService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/DepartmentService.java index 8bd484d..0c65643 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/DepartmentService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/DepartmentService.java @@ -1,17 +1,11 @@ package com.snow.dingtalk.service; -import com.alibaba.fastjson.JSON; -import com.dingtalk.api.DefaultDingTalkClient; -import com.dingtalk.api.DingTalkClient; -import com.dingtalk.api.request.OapiDepartmentCreateRequest; -import com.dingtalk.api.response.OapiDepartmentCreateResponse; -import com.snow.dingtalk.common.BaseConstantUrl; -import com.snow.dingtalk.common.BaseService; +import com.dingtalk.api.response.OapiDepartmentListResponse; import com.snow.dingtalk.model.DepartmentCreateRequest; -import com.taobao.api.ApiException; -import com.taobao.api.Constants; import org.springframework.stereotype.Service; +import java.util.List; + /** * @author qimingjin * @Title: @@ -19,33 +13,17 @@ import org.springframework.stereotype.Service; * @date 2020/9/17 17:02 */ @Service -public class DepartmentService extends BaseService { +public interface DepartmentService { /** * 创建部门 * @param departmentDTO * @return */ - public Long createDepartment(DepartmentCreateRequest departmentDTO){ - DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.DEPARTMENT_CREATE); - OapiDepartmentCreateRequest request = new OapiDepartmentCreateRequest(); - request.setParentid(departmentDTO.getParentid()); - request.setCreateDeptGroup(departmentDTO.getCreateDeptGroup()); - request.setOrder(departmentDTO.getOrder()); - request.setName(departmentDTO.getName()); - request.setHttpMethod(Constants.METHOD_POST); - request.setSourceIdentifier(departmentDTO.getSourceIdentifier()); - try { - OapiDepartmentCreateResponse response = client.execute(request,getDingTalkToken()); - if(response.getErrcode()==0){ - syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_CREATE,response.getMessage(),"createDepartment",JSON.toJSONString(request)); - return response.getId(); - }else { - syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_CREATE,response.getErrmsg(),"createDepartment",JSON.toJSONString(request)); - } - } catch (ApiException e) { - syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_CREATE,e.getMessage(),"createDepartment",JSON.toJSONString(request)); - e.printStackTrace(); - } - return null; - } + Long createDepartment(DepartmentCreateRequest departmentDTO); + + /** + * 获取部门详情 + * @return + */ + List getDingTalkDepartmentList(); } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/ProcessInstanceService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/ProcessInstanceService.java index 7a2da00..28259fc 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/ProcessInstanceService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/ProcessInstanceService.java @@ -5,10 +5,12 @@ import com.dingtalk.api.DefaultDingTalkClient; import com.dingtalk.api.request.OapiProcessinstanceCreateRequest; import com.dingtalk.api.response.OapiProcessinstanceCreateResponse; import com.snow.common.constant.Constants; +import com.snow.common.utils.spring.SpringUtils; import com.snow.dingtalk.common.BaseConstantUrl; import com.snow.dingtalk.common.BaseService; import com.snow.dingtalk.model.ProcessInstanceCreateRequest; import com.snow.system.service.ISysConfigService; +import com.snow.system.service.impl.SysConfigServiceImpl; import com.taobao.api.ApiException; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -22,8 +24,8 @@ import org.springframework.stereotype.Service; */ @Service public class ProcessInstanceService extends BaseService { - @Autowired - private ISysConfigService isysConfigService; + + private SysConfigServiceImpl isysConfigService=SpringUtils.getBean(SysConfigServiceImpl.class); /** * 创建流程 diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/DepartmentServiceImpl.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/DepartmentServiceImpl.java new file mode 100644 index 0000000..ddaf581 --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/DepartmentServiceImpl.java @@ -0,0 +1,87 @@ +package com.snow.dingtalk.service.impl; + +import com.alibaba.fastjson.JSON; +import com.dingtalk.api.DefaultDingTalkClient; +import com.dingtalk.api.DingTalkClient; +import com.dingtalk.api.request.OapiDepartmentCreateRequest; +import com.dingtalk.api.request.OapiDepartmentListRequest; +import com.dingtalk.api.response.OapiDepartmentCreateResponse; +import com.dingtalk.api.response.OapiDepartmentListResponse; +import com.snow.common.utils.spring.SpringUtils; +import com.snow.dingtalk.common.BaseConstantUrl; +import com.snow.dingtalk.common.BaseService; +import com.snow.dingtalk.model.DepartmentCreateRequest; +import com.snow.dingtalk.service.DepartmentService; +import com.snow.system.service.impl.SysDeptServiceImpl; +import com.taobao.api.ApiException; +import com.taobao.api.Constants; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @program: snow + * @description + * @author: 没用的阿吉 + * @create: 2020-10-31 12:59 + **/ +@Service(value = "departmentServiceImpl") +public class DepartmentServiceImpl extends BaseService implements DepartmentService { + + private SysDeptServiceImpl sysDeptServiceImpl=SpringUtils.getBean("sysDeptServiceImpl"); + + @Override + public Long createDepartment(DepartmentCreateRequest departmentDTO){ + DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.DEPARTMENT_CREATE); + OapiDepartmentCreateRequest request = new OapiDepartmentCreateRequest(); + request.setParentid(departmentDTO.getParentid()); + request.setCreateDeptGroup(departmentDTO.getCreateDeptGroup()); + request.setOrder(departmentDTO.getOrder()); + request.setName(departmentDTO.getName()); + request.setHttpMethod(Constants.METHOD_POST); + request.setSourceIdentifier(departmentDTO.getSourceIdentifier()); + try { + OapiDepartmentCreateResponse response = client.execute(request,getDingTalkToken()); + if(response.getErrcode()==0){ + syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_CREATE,response.getMessage(),"createDepartment",JSON.toJSONString(request)); + return response.getId(); + }else { + syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_CREATE,response.getErrmsg(),"createDepartment",JSON.toJSONString(request)); + } + } catch (ApiException e) { + syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_CREATE,e.getMessage(),"createDepartment",JSON.toJSONString(request)); + e.printStackTrace(); + } + return null; + } + + + @Override + public List getDingTalkDepartmentList(){ + DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.DEPARTMENT_LIST); + OapiDepartmentListRequest request = new OapiDepartmentListRequest(); + request.setId("1"); + request.setHttpMethod("GET"); + request.setFetchChild(true); + try { + OapiDepartmentListResponse response = client.execute(request, getDingTalkToken()); + if(response.getErrcode()==0){ + syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_LIST,response.getMessage(),"getDingTalkDepartmentList",JSON.toJSONString(request)); + return response.getDepartment(); + }else { + syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_LIST,response.getErrmsg(),"getDingTalkDepartmentList",JSON.toJSONString(request)); + } + } catch (ApiException e) { + syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_LIST,e.getMessage(),"getDingTalkDepartmentList",JSON.toJSONString(request)); + e.printStackTrace(); + } + return null; + } + + + public void sycnDepartmentData(){ + List dingTalkDepartmentList = getDingTalkDepartmentList(); + + + } +} diff --git a/snow-system/src/main/java/com/snow/system/service/impl/SysConfigServiceImpl.java b/snow-system/src/main/java/com/snow/system/service/impl/SysConfigServiceImpl.java index 6e02f89..1d6a43d 100644 --- a/snow-system/src/main/java/com/snow/system/service/impl/SysConfigServiceImpl.java +++ b/snow-system/src/main/java/com/snow/system/service/impl/SysConfigServiceImpl.java @@ -19,7 +19,7 @@ import com.snow.system.service.ISysConfigService; * * @author snow */ -@Service +@Service("sysConfigServiceImpl") public class SysConfigServiceImpl implements ISysConfigService { @Autowired From 248d87f637c4d32d6be336ab3d2fcf4970ef8fc0 Mon Sep 17 00:00:00 2001 From: jinqiming <45981669@qq.com> Date: Tue, 3 Nov 2020 17:36:34 +0800 Subject: [PATCH 08/82] =?UTF-8?q?=E6=B3=A8=E5=86=8C=E5=9B=9E=E8=B0=83?= =?UTF-8?q?=EF=BC=8C=E6=9A=82=E6=97=B6=E5=B0=91=E9=AA=8C=E8=AF=81=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/dingtalk/DingTalkCallBack.java | 73 +++++++++ .../system/DingtalkCallBackController.java | 126 +++++++++++++++ .../resources/templates/system/back/add.html | 69 ++++++++ .../resources/templates/system/back/back.html | 98 ++++++++++++ .../resources/templates/system/back/edit.html | 63 ++++++++ .../common/enums/DingTalkListenerType.java | 7 +- .../snow/dingtalk/common/BaseConstantUrl.java | 5 + .../dingtalk/listener/CallBackService.java | 27 ++++ .../listener/SyncDingTalkInfoFactory.java | 10 +- .../dingtalk/service/CallBackService.java | 16 ++ .../service/impl/CallBackServiceImpl.java | 92 +++++++++++ .../snow/system/domain/DingtalkCallBack.java | 148 ++++++++++++++++++ .../system/domain/DingtalkCallBackEvent.java | 96 ++++++++++++ .../mapper/DingtalkCallBackEventMapper.java | 61 ++++++++ .../system/mapper/DingtalkCallBackMapper.java | 61 ++++++++ .../service/IDingtalkCallBackService.java | 61 ++++++++ .../impl/DingtalkCallBackServiceImpl.java | 125 +++++++++++++++ .../system/DingtalkCallBackEventMapper.xml | 87 ++++++++++ .../mapper/system/DingtalkCallBackMapper.xml | 97 ++++++++++++ 19 files changed, 1319 insertions(+), 3 deletions(-) create mode 100644 snow-admin/src/main/java/com/snow/web/controller/dingtalk/DingTalkCallBack.java create mode 100644 snow-admin/src/main/java/com/snow/web/controller/system/DingtalkCallBackController.java create mode 100644 snow-admin/src/main/resources/templates/system/back/add.html create mode 100644 snow-admin/src/main/resources/templates/system/back/back.html create mode 100644 snow-admin/src/main/resources/templates/system/back/edit.html create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/listener/CallBackService.java create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/service/CallBackService.java create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/CallBackServiceImpl.java create mode 100644 snow-system/src/main/java/com/snow/system/domain/DingtalkCallBack.java create mode 100644 snow-system/src/main/java/com/snow/system/domain/DingtalkCallBackEvent.java create mode 100644 snow-system/src/main/java/com/snow/system/mapper/DingtalkCallBackEventMapper.java create mode 100644 snow-system/src/main/java/com/snow/system/mapper/DingtalkCallBackMapper.java create mode 100644 snow-system/src/main/java/com/snow/system/service/IDingtalkCallBackService.java create mode 100644 snow-system/src/main/java/com/snow/system/service/impl/DingtalkCallBackServiceImpl.java create mode 100644 snow-system/src/main/resources/mapper/system/DingtalkCallBackEventMapper.xml create mode 100644 snow-system/src/main/resources/mapper/system/DingtalkCallBackMapper.xml diff --git a/snow-admin/src/main/java/com/snow/web/controller/dingtalk/DingTalkCallBack.java b/snow-admin/src/main/java/com/snow/web/controller/dingtalk/DingTalkCallBack.java new file mode 100644 index 0000000..07dcb2a --- /dev/null +++ b/snow-admin/src/main/java/com/snow/web/controller/dingtalk/DingTalkCallBack.java @@ -0,0 +1,73 @@ +package com.snow.web.controller.dingtalk; + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/11/3 17:11 + */ +@RestController +@Slf4j +public class DingTalkCallBack { + + + /** + * 钉钉回调 + * @param signature + * @param timestamp + * @param nonce + * @param body + * @return + */ + @PostMapping(value = "/dingTalkCallBack") + public Object dingCallback( + @RequestParam(value = "signature") String signature, + @RequestParam(value = "timestamp") Long timestamp, + @RequestParam(value = "nonce") String nonce, + @RequestBody(required = false) JSONObject body + ) { + String params = "signature:" + signature + " timestamp:" + timestamp + " nonce:" + nonce + " body:" + body; + try { + log.info("begin callback:" + params); + DingTalkEncryptor dingTalkEncryptor = new DingTalkEncryptor(Constant.TOKEN, Constant.ENCODING_AES_KEY, Constant.SUITE_KEY); + + // 从post请求的body中获取回调信息的加密数据进行解密处理 + String encrypt = body.getString("encrypt"); + String plainText = dingTalkEncryptor.getDecryptMsg(signature, timestamp.toString(), nonce, encrypt); + JSONObject callBackContent = JSON.parseObject(plainText); + + // 根据回调事件类型做不同的业务处理 + String eventType = callBackContent.getString("EventType"); + if (EVENT_CHECK_CREATE_SUITE_URL.equals(eventType)) { + log.info("验证新创建的回调URL有效性: " + plainText); + } else if (EVENT_CHECK_UPADTE_SUITE_URL.equals(eventType)) { + log.info("验证更新回调URL有效性: " + plainText); + } else if (EVENT_SUITE_TICKET.equals(eventType)) { + // suite_ticket用于用签名形式生成accessToken(访问钉钉服务端的凭证),需要保存到应用的db。 + // 钉钉会定期向本callback url推送suite_ticket新值用以提升安全性。 + // 应用在获取到新的时值时,保存db成功后,返回给钉钉success加密串(如本demo的return) + log.info("应用suite_ticket数据推送: " + plainText); + } else if (EVENT_TMP_AUTH_CODE.equals(eventType)) { + // 本事件应用应该异步进行授权开通企业的初始化,目的是尽最大努力快速返回给钉钉服务端。用以提升企业管理员开通应用体验 + // 即使本接口没有收到数据或者收到事件后处理初始化失败都可以后续再用户试用应用时从前端获取到corpId并拉取授权企业信息,进而初始化开通及企业。 + log.info("企业授权开通应用事件: " + plainText); + } else { + // 其他类型事件处理 + } + + // 返回success的加密信息表示回调处理成功 + return dingTalkEncryptor.getEncryptedMap("success", timestamp, nonce); + } catch (Exception e) { + //失败的情况,应用的开发者应该通过告警感知,并干预修复 + log.error("process callback fail." + params, e); + return "fail"; + } + } +} diff --git a/snow-admin/src/main/java/com/snow/web/controller/system/DingtalkCallBackController.java b/snow-admin/src/main/java/com/snow/web/controller/system/DingtalkCallBackController.java new file mode 100644 index 0000000..20f2cdf --- /dev/null +++ b/snow-admin/src/main/java/com/snow/web/controller/system/DingtalkCallBackController.java @@ -0,0 +1,126 @@ +package com.snow.web.controller.system; + +import java.util.List; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import com.snow.common.annotation.Log; +import com.snow.common.enums.BusinessType; +import com.snow.system.domain.DingtalkCallBack; +import com.snow.system.service.IDingtalkCallBackService; +import com.snow.common.core.controller.BaseController; +import com.snow.common.core.domain.AjaxResult; +import com.snow.common.utils.poi.ExcelUtil; +import com.snow.common.core.page.TableDataInfo; + +/** + * 回调事件Controller + * + * @author qimingjin + * @date 2020-11-02 + */ +@Controller +@RequestMapping("/system/back") +public class DingtalkCallBackController extends BaseController +{ + private String prefix = "system/back"; + + @Autowired + private IDingtalkCallBackService dingtalkCallBackService; + + @RequiresPermissions("system:back:view") + @GetMapping() + public String back() + { + return prefix + "/back"; + } + + /** + * 查询回调事件列表 + */ + @RequiresPermissions("system:back:list") + @PostMapping("/list") + @ResponseBody + public TableDataInfo list(DingtalkCallBack dingtalkCallBack) + { + startPage(); + List list = dingtalkCallBackService.selectDingtalkCallBackList(dingtalkCallBack); + return getDataTable(list); + } + + /** + * 导出回调事件列表 + */ + @RequiresPermissions("system:back:export") + @Log(title = "回调事件", businessType = BusinessType.EXPORT) + @PostMapping("/export") + @ResponseBody + public AjaxResult export(DingtalkCallBack dingtalkCallBack) + { + List list = dingtalkCallBackService.selectDingtalkCallBackList(dingtalkCallBack); + ExcelUtil util = new ExcelUtil(DingtalkCallBack.class); + return util.exportExcel(list, "back"); + } + + /** + * 新增回调事件 + */ + @GetMapping("/add") + public String add() + { + return prefix + "/add"; + } + + /** + * 新增保存回调事件 + */ + @RequiresPermissions("system:back:add") + @Log(title = "回调事件", businessType = BusinessType.INSERT) + @PostMapping("/add") + @ResponseBody + public AjaxResult addSave(DingtalkCallBack dingtalkCallBack) + { + return toAjax(dingtalkCallBackService.insertDingtalkCallBack(dingtalkCallBack)); + } + + /** + * 修改回调事件 + */ + @GetMapping("/edit/{id}") + public String edit(@PathVariable("id") Long id, ModelMap mmap) + { + DingtalkCallBack dingtalkCallBack = dingtalkCallBackService.selectDingtalkCallBackById(id); + mmap.put("dingtalkCallBack", dingtalkCallBack); + return prefix + "/edit"; + } + + /** + * 修改保存回调事件 + */ + @RequiresPermissions("system:back:edit") + @Log(title = "回调事件", businessType = BusinessType.UPDATE) + @PostMapping("/edit") + @ResponseBody + public AjaxResult editSave(DingtalkCallBack dingtalkCallBack) + { + return toAjax(dingtalkCallBackService.updateDingtalkCallBack(dingtalkCallBack)); + } + + /** + * 删除回调事件 + */ + @RequiresPermissions("system:back:remove") + @Log(title = "回调事件", businessType = BusinessType.DELETE) + @PostMapping( "/remove") + @ResponseBody + public AjaxResult remove(String ids) + { + return toAjax(dingtalkCallBackService.deleteDingtalkCallBackByIds(ids)); + } +} diff --git a/snow-admin/src/main/resources/templates/system/back/add.html b/snow-admin/src/main/resources/templates/system/back/add.html new file mode 100644 index 0000000..54d1390 --- /dev/null +++ b/snow-admin/src/main/resources/templates/system/back/add.html @@ -0,0 +1,69 @@ + + + + + + +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/snow-admin/src/main/resources/templates/system/back/back.html b/snow-admin/src/main/resources/templates/system/back/back.html new file mode 100644 index 0000000..139ea0c --- /dev/null +++ b/snow-admin/src/main/resources/templates/system/back/back.html @@ -0,0 +1,98 @@ + + + + + + +
+
+
+
+
+ +
+
+
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/snow-admin/src/main/resources/templates/system/back/edit.html b/snow-admin/src/main/resources/templates/system/back/edit.html new file mode 100644 index 0000000..a3b6142 --- /dev/null +++ b/snow-admin/src/main/resources/templates/system/back/edit.html @@ -0,0 +1,63 @@ + + + + + + +
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+
+ + + + \ No newline at end of file diff --git a/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java b/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java index e536d52..6e2c57b 100644 --- a/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java +++ b/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java @@ -11,7 +11,12 @@ public enum DingTalkListenerType { DEPARTMENT_UPDATE(2, "部门更新"), DEPARTMENT_DELETED(3, "部门删除"), - USER_CREATED(4,"用户创建"); + USER_CREATED(4,"用户创建"), + + CALL_BACK_REGISTER(10, "回调注册"), + ; + + private final Integer code; private final String info; diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java index be34f4a..8c03103 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java @@ -46,4 +46,9 @@ public class BaseConstantUrl { * 更新待办 */ public static final String WORK_RECORD_UPDATE="https://oapi.dingtalk.com/topapi/workrecord/update"; + + /** + * 注册回调 + */ + public static final String REGISTER_CALL_BACK="https://oapi.dingtalk.com/call_back/register_call_back"; } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/CallBackService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/CallBackService.java new file mode 100644 index 0000000..a7d06ca --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/CallBackService.java @@ -0,0 +1,27 @@ +package com.snow.dingtalk.listener; + +import com.alibaba.fastjson.JSON; +import com.snow.common.utils.spring.SpringUtils; +import com.snow.dingtalk.service.impl.CallBackServiceImpl; +import com.snow.system.domain.DingtalkCallBack; +import com.snow.system.event.SyncEvent; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/11/3 17:05 + */ +@Component +@Slf4j +public class CallBackService implements ISyncDingTalkInfo { + private CallBackServiceImpl departmentService=SpringUtils.getBean("callBackServiceImpl"); + + @Override + public void syncDingTalkInfoEvent(SyncEvent syncEvent) { + log.info("调用创建钉钉注册回调传入的原始参数:{}"+JSON.toJSONString(syncEvent)); + departmentService.registerCallBack((DingtalkCallBack) syncEvent.getT()); + } +} diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java index bcce8f6..a942aca 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java @@ -3,7 +3,6 @@ package com.snow.dingtalk.listener; import com.snow.common.enums.DingTalkListenerType; import com.snow.system.event.SyncEvent; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; /** * @author qimingjin @@ -19,12 +18,19 @@ public class SyncDingTalkInfoFactory { public ISyncDingTalkInfo getSyncDingTalkService(SyncEvent syncEvent){ Integer eventType = syncEvent.getEventType(); + if(eventType.equals(DingTalkListenerType.DEPARTMENT_CREATE.getCode())){ return new DepartmentCreateEventService(); } else if(eventType.equals(DingTalkListenerType.USER_CREATED.getCode())){ return new UserCreateEventService(); - }else { + } + else if(eventType.equals(DingTalkListenerType.CALL_BACK_REGISTER.getCode())){ + return new CallBackService(); + } + + + else { throw new RuntimeException("不存在的监听类型"); } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/CallBackService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/CallBackService.java new file mode 100644 index 0000000..8182de6 --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/CallBackService.java @@ -0,0 +1,16 @@ +package com.snow.dingtalk.service; + +import com.snow.system.domain.DingtalkCallBack; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/11/3 11:18 + */ +public interface CallBackService { + /** + * 注册事件 + */ + void registerCallBack(DingtalkCallBack dingtalkCallBack); +} diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/CallBackServiceImpl.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/CallBackServiceImpl.java new file mode 100644 index 0000000..9507fae --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/CallBackServiceImpl.java @@ -0,0 +1,92 @@ +package com.snow.dingtalk.service.impl; + +import cn.hutool.cache.CacheUtil; +import cn.hutool.cache.impl.TimedCache; +import com.alibaba.fastjson.JSON; +import com.dingtalk.api.DefaultDingTalkClient; +import com.dingtalk.api.DingTalkClient; +import com.dingtalk.api.request.OapiCallBackRegisterCallBackRequest; +import com.dingtalk.api.request.OapiGettokenRequest; +import com.dingtalk.api.response.OapiCallBackRegisterCallBackResponse; +import com.dingtalk.api.response.OapiGettokenResponse; +import com.snow.common.constant.Constants; +import com.snow.common.utils.StringUtils; +import com.snow.dingtalk.common.BaseConstantUrl; +import com.snow.dingtalk.common.BaseService; +import com.snow.dingtalk.service.CallBackService; +import com.snow.system.domain.DingtalkCallBack; +import com.taobao.api.ApiException; +import org.springframework.stereotype.Service; + +import java.util.Arrays; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/11/3 11:19 + */ +@Service +public class CallBackServiceImpl extends BaseService implements CallBackService { + + public static final String TOKEN="call_back_dingtalk_token"; + + @Override + public void registerCallBack(DingtalkCallBack dingtalkCallBack) { + DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.REGISTER_CALL_BACK); + OapiCallBackRegisterCallBackRequest request = new OapiCallBackRegisterCallBackRequest(); + request.setUrl(dingtalkCallBack.getUrl()); + request.setAesKey(dingtalkCallBack.getAesKey()); + request.setToken(dingtalkCallBack.getToken()); + request.setCallBackTag(dingtalkCallBack.getEventNameList()); + try { + OapiCallBackRegisterCallBackResponse response = client.execute(request,getCallBackDingTalkToken(dingtalkCallBack)); + if(response.getErrcode()==0){ + syncDingTalkErrorOperLog(BaseConstantUrl.REGISTER_CALL_BACK,response.getMessage(),"registerCallBack()", JSON.toJSONString(request)); + }else { + //记录获取token失败日志 + syncDingTalkErrorOperLog(BaseConstantUrl.REGISTER_CALL_BACK,response.getErrmsg(),"registerCallBack()", JSON.toJSONString(request)); + } + } catch (ApiException e) { + syncDingTalkErrorOperLog(BaseConstantUrl.REGISTER_CALL_BACK,e.getMessage(),"registerCallBack()", JSON.toJSONString(request)); + e.printStackTrace(); + } + } + + + /** + * 获取token + * @return + */ + public String getCallBackDingTalkToken(DingtalkCallBack dingtalkCallBack){ + //创建缓存,缓存默认是7100S + TimedCache timedCache = CacheUtil.newTimedCache(7100); + if(StringUtils.isEmpty(timedCache.get(TOKEN))){ + DefaultDingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.GET_TOKEN_URL); + OapiGettokenRequest request = new OapiGettokenRequest(); + request.setAppkey(dingtalkCallBack.getAppKey()); + request.setAppsecret(dingtalkCallBack.getAppSecret()); + request.setHttpMethod(Constants.GET); + try { + OapiGettokenResponse response = client.execute(request); + if(response.getErrcode()==0){ + timedCache.put(TOKEN,response.getAccessToken()); + syncDingTalkErrorOperLog(BaseConstantUrl.GET_TOKEN_URL,response.getMessage(),"getCallBackDingTalkToken()", JSON.toJSONString(request)); + return response.getAccessToken(); + }else { + //记录获取token失败日志 + syncDingTalkErrorOperLog(BaseConstantUrl.GET_TOKEN_URL,response.getErrmsg(),"getCallBackDingTalkToken()", JSON.toJSONString(request)); + return null; + } + } catch (ApiException e) { + syncDingTalkErrorOperLog(BaseConstantUrl.GET_TOKEN_URL,e.getMessage(),"getCallBackDingTalkToken()",JSON.toJSONString(request)); + e.printStackTrace(); + } + return null; + }else { + return timedCache.get(TOKEN); + } + + } +} + diff --git a/snow-system/src/main/java/com/snow/system/domain/DingtalkCallBack.java b/snow-system/src/main/java/com/snow/system/domain/DingtalkCallBack.java new file mode 100644 index 0000000..8e10fe2 --- /dev/null +++ b/snow-system/src/main/java/com/snow/system/domain/DingtalkCallBack.java @@ -0,0 +1,148 @@ +package com.snow.system.domain; + +import com.snow.common.annotation.Excel; +import com.snow.common.core.domain.BaseEntity; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import java.util.List; + +/** + * 回调事件对象 dingtalk_call_back + * + * @author qimingjin + * @date 2020-11-02 + */ +public class DingtalkCallBack extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** ID */ + private Long id; + + /** 加解密需要用到的token,ISV(服务提供商)推荐使用注册套件时填写的token,普通企业可以随机填写 */ + @Excel(name = "加解密需要用到的token,ISV(服务提供商)推荐使用注册套件时填写的token,普通企业可以随机填写") + private String token; + + /** 数据加密密钥。用于回调数据的加密,长度固定为43个字符,从a-z, A-Z, 0-9共62个字符中选取,您可以随机生成,ISV(服务提供商)推荐使用注册套件时填写的EncodingAESKey */ + @Excel(name = "数据加密密钥。用于回调数据的加密,长度固定为43个字符,从a-z, A-Z, 0-9共62个字符中选取,您可以随机生成,ISV(服务提供商)推荐使用注册套件时填写的EncodingAESKey") + private String aesKey; + + /** 接收事件回调的url,必须是公网可以访问的url地址 */ + @Excel(name = "接收事件回调的url,必须是公网可以访问的url地址") + private String url; + + /** app_key */ + private String appKey; + + /** app_secret */ + private String appSecret; + + /** 删除表示 */ + private Integer delFlag; + + /** 回调名称 */ + @Excel(name = "回调名称") + private String callBackName; + + private List eventNameList; + + public void setId(Long id) + { + this.id = id; + } + + public Long getId() + { + return id; + } + public void setToken(String token) + { + this.token = token; + } + + public String getToken() + { + return token; + } + public void setAesKey(String aesKey) + { + this.aesKey = aesKey; + } + + public String getAesKey() + { + return aesKey; + } + public void setUrl(String url) + { + this.url = url; + } + + public String getUrl() + { + return url; + } + public void setAppKey(String appKey) + { + this.appKey = appKey; + } + + public String getAppKey() + { + return appKey; + } + public void setAppSecret(String appSecret) + { + this.appSecret = appSecret; + } + + public String getAppSecret() + { + return appSecret; + } + public void setDelFlag(Integer delFlag) + { + this.delFlag = delFlag; + } + + public Integer getDelFlag() + { + return delFlag; + } + public void setCallBackName(String callBackName) + { + this.callBackName = callBackName; + } + + public String getCallBackName() + { + return callBackName; + } + + public List getEventNameList() { + return eventNameList; + } + + public void setEventNameList(List eventNameList) { + this.eventNameList = eventNameList; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("token", getToken()) + .append("aesKey", getAesKey()) + .append("url", getUrl()) + .append("appKey", getAppKey()) + .append("appSecret", getAppSecret()) + .append("delFlag", getDelFlag()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("callBackName", getCallBackName()) + .toString(); + } +} diff --git a/snow-system/src/main/java/com/snow/system/domain/DingtalkCallBackEvent.java b/snow-system/src/main/java/com/snow/system/domain/DingtalkCallBackEvent.java new file mode 100644 index 0000000..4c1ede5 --- /dev/null +++ b/snow-system/src/main/java/com/snow/system/domain/DingtalkCallBackEvent.java @@ -0,0 +1,96 @@ +package com.snow.system.domain; + +import com.snow.common.annotation.Excel; +import com.snow.common.core.domain.BaseEntity; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * 事件表对象 dingtalk_call_back_event + * + * @author snow + * @date 2020-11-03 + */ +public class DingtalkCallBackEvent extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** null */ + private Integer id; + + /** null */ + @Excel(name = "null") + private String eventName; + + /** null */ + @Excel(name = "null") + private Long callBanckId; + + /** null */ + @Excel(name = "null") + private String eventDesc; + + /** null */ + private Long delFlag; + + public void setId(Integer id) + { + this.id = id; + } + + public Integer getId() + { + return id; + } + public void setEventName(String eventName) + { + this.eventName = eventName; + } + + public String getEventName() + { + return eventName; + } + public void setCallBanckId(Long callBanckId) + { + this.callBanckId = callBanckId; + } + + public Long getCallBanckId() + { + return callBanckId; + } + public void setEventDesc(String eventDesc) + { + this.eventDesc = eventDesc; + } + + public String getEventDesc() + { + return eventDesc; + } + public void setDelFlag(Long delFlag) + { + this.delFlag = delFlag; + } + + public Long getDelFlag() + { + return delFlag; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("eventName", getEventName()) + .append("callBanckId", getCallBanckId()) + .append("eventDesc", getEventDesc()) + .append("delFlag", getDelFlag()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateTime", getUpdateTime()) + .append("updateBy", getUpdateBy()) + .toString(); + } +} diff --git a/snow-system/src/main/java/com/snow/system/mapper/DingtalkCallBackEventMapper.java b/snow-system/src/main/java/com/snow/system/mapper/DingtalkCallBackEventMapper.java new file mode 100644 index 0000000..b1a0270 --- /dev/null +++ b/snow-system/src/main/java/com/snow/system/mapper/DingtalkCallBackEventMapper.java @@ -0,0 +1,61 @@ +package com.snow.system.mapper; + +import java.util.List; +import com.snow.system.domain.DingtalkCallBackEvent; + +/** + * 事件表Mapper接口 + * + * @author snow + * @date 2020-11-03 + */ +public interface DingtalkCallBackEventMapper +{ + /** + * 查询事件表 + * + * @param id 事件表ID + * @return 事件表 + */ + public DingtalkCallBackEvent selectDingtalkCallBackEventById(Integer id); + + /** + * 查询事件表列表 + * + * @param dingtalkCallBackEvent 事件表 + * @return 事件表集合 + */ + public List selectDingtalkCallBackEventList(DingtalkCallBackEvent dingtalkCallBackEvent); + + /** + * 新增事件表 + * + * @param dingtalkCallBackEvent 事件表 + * @return 结果 + */ + public int insertDingtalkCallBackEvent(DingtalkCallBackEvent dingtalkCallBackEvent); + + /** + * 修改事件表 + * + * @param dingtalkCallBackEvent 事件表 + * @return 结果 + */ + public int updateDingtalkCallBackEvent(DingtalkCallBackEvent dingtalkCallBackEvent); + + /** + * 删除事件表 + * + * @param id 事件表ID + * @return 结果 + */ + public int deleteDingtalkCallBackEventById(Integer id); + + /** + * 批量删除事件表 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteDingtalkCallBackEventByIds(String[] ids); +} diff --git a/snow-system/src/main/java/com/snow/system/mapper/DingtalkCallBackMapper.java b/snow-system/src/main/java/com/snow/system/mapper/DingtalkCallBackMapper.java new file mode 100644 index 0000000..f481cbd --- /dev/null +++ b/snow-system/src/main/java/com/snow/system/mapper/DingtalkCallBackMapper.java @@ -0,0 +1,61 @@ +package com.snow.system.mapper; + +import java.util.List; +import com.snow.system.domain.DingtalkCallBack; + +/** + * 回调事件Mapper接口 + * + * @author qimingjin + * @date 2020-11-02 + */ +public interface DingtalkCallBackMapper +{ + /** + * 查询回调事件 + * + * @param id 回调事件ID + * @return 回调事件 + */ + public DingtalkCallBack selectDingtalkCallBackById(Long id); + + /** + * 查询回调事件列表 + * + * @param dingtalkCallBack 回调事件 + * @return 回调事件集合 + */ + public List selectDingtalkCallBackList(DingtalkCallBack dingtalkCallBack); + + /** + * 新增回调事件 + * + * @param dingtalkCallBack 回调事件 + * @return 结果 + */ + public int insertDingtalkCallBack(DingtalkCallBack dingtalkCallBack); + + /** + * 修改回调事件 + * + * @param dingtalkCallBack 回调事件 + * @return 结果 + */ + public int updateDingtalkCallBack(DingtalkCallBack dingtalkCallBack); + + /** + * 删除回调事件 + * + * @param id 回调事件ID + * @return 结果 + */ + public int deleteDingtalkCallBackById(Long id); + + /** + * 批量删除回调事件 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteDingtalkCallBackByIds(String[] ids); +} diff --git a/snow-system/src/main/java/com/snow/system/service/IDingtalkCallBackService.java b/snow-system/src/main/java/com/snow/system/service/IDingtalkCallBackService.java new file mode 100644 index 0000000..b5bd517 --- /dev/null +++ b/snow-system/src/main/java/com/snow/system/service/IDingtalkCallBackService.java @@ -0,0 +1,61 @@ +package com.snow.system.service; + +import java.util.List; +import com.snow.system.domain.DingtalkCallBack; + +/** + * 回调事件Service接口 + * + * @author qimingjin + * @date 2020-11-02 + */ +public interface IDingtalkCallBackService +{ + /** + * 查询回调事件 + * + * @param id 回调事件ID + * @return 回调事件 + */ + public DingtalkCallBack selectDingtalkCallBackById(Long id); + + /** + * 查询回调事件列表 + * + * @param dingtalkCallBack 回调事件 + * @return 回调事件集合 + */ + public List selectDingtalkCallBackList(DingtalkCallBack dingtalkCallBack); + + /** + * 新增回调事件 + * + * @param dingtalkCallBack 回调事件 + * @return 结果 + */ + public int insertDingtalkCallBack(DingtalkCallBack dingtalkCallBack); + + /** + * 修改回调事件 + * + * @param dingtalkCallBack 回调事件 + * @return 结果 + */ + public int updateDingtalkCallBack(DingtalkCallBack dingtalkCallBack); + + /** + * 批量删除回调事件 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteDingtalkCallBackByIds(String ids); + + /** + * 删除回调事件信息 + * + * @param id 回调事件ID + * @return 结果 + */ + public int deleteDingtalkCallBackById(Long id); +} diff --git a/snow-system/src/main/java/com/snow/system/service/impl/DingtalkCallBackServiceImpl.java b/snow-system/src/main/java/com/snow/system/service/impl/DingtalkCallBackServiceImpl.java new file mode 100644 index 0000000..b7758a8 --- /dev/null +++ b/snow-system/src/main/java/com/snow/system/service/impl/DingtalkCallBackServiceImpl.java @@ -0,0 +1,125 @@ +package com.snow.system.service.impl; + +import java.util.List; + +import com.snow.common.enums.DingTalkListenerType; +import com.snow.common.utils.DateUtils; +import com.snow.system.domain.DingtalkCallBackEvent; +import com.snow.system.event.SyncEvent; +import com.snow.system.mapper.DingtalkCallBackEventMapper; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Service; +import com.snow.system.mapper.DingtalkCallBackMapper; +import com.snow.system.domain.DingtalkCallBack; +import com.snow.system.service.IDingtalkCallBackService; +import com.snow.common.core.text.Convert; + +import javax.annotation.Resource; + +/** + * 回调事件Service业务层处理 + * + * @author qimingjin + * @date 2020-11-02 + */ +@Service +public class DingtalkCallBackServiceImpl implements IDingtalkCallBackService +{ + @Autowired + private DingtalkCallBackMapper dingtalkCallBackMapper; + @Autowired + private DingtalkCallBackEventMapper dingtalkCallBackEventMapper; + @Autowired + private SysDictDataServiceImpl sysDictDataServiceImpl; + @Resource + private ApplicationContext applicationContext; + /** + * 查询回调事件 + * + * @param id 回调事件ID + * @return 回调事件 + */ + @Override + public DingtalkCallBack selectDingtalkCallBackById(Long id) + { + return dingtalkCallBackMapper.selectDingtalkCallBackById(id); + } + + /** + * 查询回调事件列表 + * + * @param dingtalkCallBack 回调事件 + * @return 回调事件 + */ + @Override + public List selectDingtalkCallBackList(DingtalkCallBack dingtalkCallBack) + { + return dingtalkCallBackMapper.selectDingtalkCallBackList(dingtalkCallBack); + } + + /** + * 新增回调事件 + * + * @param dingtalkCallBack 回调事件 + * @return 结果 + */ + @Override + public int insertDingtalkCallBack(DingtalkCallBack dingtalkCallBack) + { + dingtalkCallBack.setCreateTime(DateUtils.getNowDate()); + DingtalkCallBackEvent dingtalkCallBackEvent=new DingtalkCallBackEvent(); + BeanUtils.copyProperties(dingtalkCallBack,dingtalkCallBackEvent); + List eventNameList = dingtalkCallBack.getEventNameList(); + int i = dingtalkCallBackMapper.insertDingtalkCallBack(dingtalkCallBack); + eventNameList.forEach(t->{ + dingtalkCallBackEvent.setEventName(t); + String addressBook = sysDictDataServiceImpl.selectDictLabel("address_book", t); + dingtalkCallBackEvent.setEventDesc(addressBook); + dingtalkCallBackEvent.setId(i); + dingtalkCallBackEventMapper.insertDingtalkCallBackEvent(dingtalkCallBackEvent); + }); + // 同步到dingding + SyncEvent syncEvent = new SyncEvent(dingtalkCallBack, DingTalkListenerType.CALL_BACK_REGISTER.getCode(), dingtalkCallBack); + applicationContext.publishEvent(syncEvent); + return 1; + } + + /** + * 修改回调事件 + * + * @param dingtalkCallBack 回调事件 + * @return 结果 + */ + @Override + public int updateDingtalkCallBack(DingtalkCallBack dingtalkCallBack) + { + dingtalkCallBack.setUpdateTime(DateUtils.getNowDate()); + return dingtalkCallBackMapper.updateDingtalkCallBack(dingtalkCallBack); + } + + /** + * 删除回调事件对象 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + @Override + public int deleteDingtalkCallBackByIds(String ids) + { + return dingtalkCallBackMapper.deleteDingtalkCallBackByIds(Convert.toStrArray(ids)); + } + + /** + * 删除回调事件信息 + * + * @param id 回调事件ID + * @return 结果 + */ + @Override + public int deleteDingtalkCallBackById(Long id) + { + return dingtalkCallBackMapper.deleteDingtalkCallBackById(id); + } +} diff --git a/snow-system/src/main/resources/mapper/system/DingtalkCallBackEventMapper.xml b/snow-system/src/main/resources/mapper/system/DingtalkCallBackEventMapper.xml new file mode 100644 index 0000000..2a77dc3 --- /dev/null +++ b/snow-system/src/main/resources/mapper/system/DingtalkCallBackEventMapper.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + select id, event_name, call_banck_id, event_desc, del_flag, create_by, create_time, update_time, update_by from dingtalk_call_back_event + + + + + + + + insert into dingtalk_call_back_event + + event_name, + call_banck_id, + event_desc, + del_flag, + create_by, + create_time, + update_time, + update_by, + + + #{eventName}, + #{callBanckId}, + #{eventDesc}, + #{delFlag}, + #{createBy}, + #{createTime}, + #{updateTime}, + #{updateBy}, + + + + + update dingtalk_call_back_event + + event_name = #{eventName}, + call_banck_id = #{callBanckId}, + event_desc = #{eventDesc}, + del_flag = #{delFlag}, + create_by = #{createBy}, + create_time = #{createTime}, + update_time = #{updateTime}, + update_by = #{updateBy}, + + where id = #{id} + + + + delete from dingtalk_call_back_event where id = #{id} + + + + delete from dingtalk_call_back_event where id in + + #{id} + + + + \ No newline at end of file diff --git a/snow-system/src/main/resources/mapper/system/DingtalkCallBackMapper.xml b/snow-system/src/main/resources/mapper/system/DingtalkCallBackMapper.xml new file mode 100644 index 0000000..1685df0 --- /dev/null +++ b/snow-system/src/main/resources/mapper/system/DingtalkCallBackMapper.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + select id, token, aes_key, url, app_key, app_secret, del_flag, create_by, create_time, update_by, update_time, call_back_name from dingtalk_call_back + + + + + + + + insert into dingtalk_call_back + + token, + aes_key, + url, + app_key, + app_secret, + del_flag, + create_by, + create_time, + update_by, + update_time, + call_back_name, + + + #{token}, + #{aesKey}, + #{url}, + #{appKey}, + #{appSecret}, + #{delFlag}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{callBackName}, + + + + + update dingtalk_call_back + + token = #{token}, + aes_key = #{aesKey}, + url = #{url}, + app_key = #{appKey}, + app_secret = #{appSecret}, + del_flag = #{delFlag}, + create_by = #{createBy}, + create_time = #{createTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + call_back_name = #{callBackName}, + + where id = #{id} + + + + delete from dingtalk_call_back where id = #{id} + + + + delete from dingtalk_call_back where id in + + #{id} + + + + \ No newline at end of file From 5a1a61aa227eed6a5d9ec604a1ad8a94fdd57e98 Mon Sep 17 00:00:00 2001 From: jinqiming <45981669@qq.com> Date: Thu, 5 Nov 2020 19:15:32 +0800 Subject: [PATCH 09/82] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E5=8C=85=E5=92=8C=E6=99=9A=E4=B8=8A=E4=BA=8B=E4=BB=B6=E5=9B=9E?= =?UTF-8?q?=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 11 +++++++ .../controller/dingtalk/DingTalkCallBack.java | 21 ++++++------ .../system/DingtalkCallBackController.java | 4 +++ .../resources/templates/system/back/add.html | 2 +- .../resources/templates/system/back/back.html | 15 +++++---- .../resources/templates/system/back/edit.html | 29 +++++++--------- snow-dingtalk/pom.xml | 7 ++++ .../snow/dingtalk/common/EventNameEnum.java | 16 +++++++++ .../main/resources/lib/lippi-oapi-encrpt.jar | Bin 0 -> 12350 bytes .../impl/DingtalkCallBackServiceImpl.java | 31 ++++++++++++++++-- .../system/DingtalkCallBackEventMapper.xml | 3 +- 11 files changed, 99 insertions(+), 40 deletions(-) create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/common/EventNameEnum.java create mode 100644 snow-dingtalk/src/main/resources/lib/lippi-oapi-encrpt.jar diff --git a/pom.xml b/pom.xml index 0f7a263..1fb9ba9 100644 --- a/pom.xml +++ b/pom.xml @@ -251,6 +251,17 @@ true + + sonatype-nexus-staging + Sonatype Nexus Staging + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + true + + + true + + diff --git a/snow-admin/src/main/java/com/snow/web/controller/dingtalk/DingTalkCallBack.java b/snow-admin/src/main/java/com/snow/web/controller/dingtalk/DingTalkCallBack.java index 07dcb2a..4dc5333 100644 --- a/snow-admin/src/main/java/com/snow/web/controller/dingtalk/DingTalkCallBack.java +++ b/snow-admin/src/main/java/com/snow/web/controller/dingtalk/DingTalkCallBack.java @@ -1,6 +1,9 @@ package com.snow.web.controller.dingtalk; +import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; +import com.dingtalk.oapi.lib.aes.DingTalkEncryptor; +import com.snow.dingtalk.common.EventNameEnum; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -13,11 +16,10 @@ import org.springframework.web.bind.annotation.RestController; * @Description: * @date 2020/11/3 17:11 */ -@RestController +@RestController("/dingTalk") @Slf4j public class DingTalkCallBack { - /** * 钉钉回调 * @param signature @@ -36,7 +38,7 @@ public class DingTalkCallBack { String params = "signature:" + signature + " timestamp:" + timestamp + " nonce:" + nonce + " body:" + body; try { log.info("begin callback:" + params); - DingTalkEncryptor dingTalkEncryptor = new DingTalkEncryptor(Constant.TOKEN, Constant.ENCODING_AES_KEY, Constant.SUITE_KEY); + DingTalkEncryptor dingTalkEncryptor = new DingTalkEncryptor("","",""); // 从post请求的body中获取回调信息的加密数据进行解密处理 String encrypt = body.getString("encrypt"); @@ -45,19 +47,16 @@ public class DingTalkCallBack { // 根据回调事件类型做不同的业务处理 String eventType = callBackContent.getString("EventType"); - if (EVENT_CHECK_CREATE_SUITE_URL.equals(eventType)) { - log.info("验证新创建的回调URL有效性: " + plainText); - } else if (EVENT_CHECK_UPADTE_SUITE_URL.equals(eventType)) { + + if (EventNameEnum.org_dept_create.equals(eventType)) { + log.info("部门创建回调数据: " + callBackContent); + } else if (EventNameEnum.org_dept_modify.equals(eventType)) { log.info("验证更新回调URL有效性: " + plainText); - } else if (EVENT_SUITE_TICKET.equals(eventType)) { + } else if (EventNameEnum.org_dept_remove.equals(eventType)) { // suite_ticket用于用签名形式生成accessToken(访问钉钉服务端的凭证),需要保存到应用的db。 // 钉钉会定期向本callback url推送suite_ticket新值用以提升安全性。 // 应用在获取到新的时值时,保存db成功后,返回给钉钉success加密串(如本demo的return) log.info("应用suite_ticket数据推送: " + plainText); - } else if (EVENT_TMP_AUTH_CODE.equals(eventType)) { - // 本事件应用应该异步进行授权开通企业的初始化,目的是尽最大努力快速返回给钉钉服务端。用以提升企业管理员开通应用体验 - // 即使本接口没有收到数据或者收到事件后处理初始化失败都可以后续再用户试用应用时从前端获取到corpId并拉取授权企业信息,进而初始化开通及企业。 - log.info("企业授权开通应用事件: " + plainText); } else { // 其他类型事件处理 } diff --git a/snow-admin/src/main/java/com/snow/web/controller/system/DingtalkCallBackController.java b/snow-admin/src/main/java/com/snow/web/controller/system/DingtalkCallBackController.java index 20f2cdf..1ff1857 100644 --- a/snow-admin/src/main/java/com/snow/web/controller/system/DingtalkCallBackController.java +++ b/snow-admin/src/main/java/com/snow/web/controller/system/DingtalkCallBackController.java @@ -1,6 +1,8 @@ package com.snow.web.controller.system; import java.util.List; + +import com.snow.framework.util.ShiroUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; @@ -86,6 +88,7 @@ public class DingtalkCallBackController extends BaseController @ResponseBody public AjaxResult addSave(DingtalkCallBack dingtalkCallBack) { + dingtalkCallBack.setCreateBy(ShiroUtils.getLoginName()); return toAjax(dingtalkCallBackService.insertDingtalkCallBack(dingtalkCallBack)); } @@ -109,6 +112,7 @@ public class DingtalkCallBackController extends BaseController @ResponseBody public AjaxResult editSave(DingtalkCallBack dingtalkCallBack) { + dingtalkCallBack.setUpdateBy(ShiroUtils.getLoginName()); return toAjax(dingtalkCallBackService.updateDingtalkCallBack(dingtalkCallBack)); } diff --git a/snow-admin/src/main/resources/templates/system/back/add.html b/snow-admin/src/main/resources/templates/system/back/add.html index 54d1390..b871fd3 100644 --- a/snow-admin/src/main/resources/templates/system/back/add.html +++ b/snow-admin/src/main/resources/templates/system/back/add.html @@ -46,7 +46,7 @@
diff --git a/snow-admin/src/main/resources/templates/system/back/back.html b/snow-admin/src/main/resources/templates/system/back/back.html index 139ea0c..504e8ed 100644 --- a/snow-admin/src/main/resources/templates/system/back/back.html +++ b/snow-admin/src/main/resources/templates/system/back/back.html @@ -24,9 +24,9 @@
- + 修改 @@ -62,7 +62,7 @@ { field: 'id', title: 'ID', - visible: false + visible: true }, /* { field: 'token', @@ -72,14 +72,15 @@ field: 'aesKey', title: '数据加密密钥' },*/ + { + field: 'callBackName', + title: '回调名称' + }, { field: 'url', title: '回调url' }, - { - field: 'callBackName', - title: '回调名称' - }, + { title: '操作', align: 'center', diff --git a/snow-admin/src/main/resources/templates/system/back/edit.html b/snow-admin/src/main/resources/templates/system/back/edit.html index a3b6142..dbf3480 100644 --- a/snow-admin/src/main/resources/templates/system/back/edit.html +++ b/snow-admin/src/main/resources/templates/system/back/edit.html @@ -10,40 +10,35 @@
- +
-
+
- +
-
+
- +
- +
-
- -
- +
+ +
+
-
- -
- -
-
-
diff --git a/snow-dingtalk/pom.xml b/snow-dingtalk/pom.xml index ad0bbf0..7ecc733 100644 --- a/snow-dingtalk/pom.xml +++ b/snow-dingtalk/pom.xml @@ -25,6 +25,13 @@ 1.0.1 + + com.taobao.top + lippi-oapi-encrpt + dingtalk-SNAPSHOT + system + ${pom.basedir}/src/main/resources/lib/lippi-oapi-encrpt.jar + org.projectlombok lombok diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/EventNameEnum.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/EventNameEnum.java new file mode 100644 index 0000000..312d292 --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/EventNameEnum.java @@ -0,0 +1,16 @@ +package com.snow.dingtalk.common; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/11/5 15:04 + */ +public enum EventNameEnum { + + org_dept_create, + + org_dept_modify, + + org_dept_remove +} diff --git a/snow-dingtalk/src/main/resources/lib/lippi-oapi-encrpt.jar b/snow-dingtalk/src/main/resources/lib/lippi-oapi-encrpt.jar new file mode 100644 index 0000000000000000000000000000000000000000..f11222355357d5167c83fa41d21aed712ad34db3 GIT binary patch literal 12350 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 dingtalkCallBackEvents = dingtalkCallBackEventMapper.selectDingtalkCallBackEventList(dingtalkCallBackEvent); + List eventNameList = dingtalkCallBackEvents.stream() + .map(DingtalkCallBackEvent::getEventName) + .collect(Collectors.toList()); + dingtalkCallBack.setEventNameList(eventNameList); + } + return dingtalkCallBack; } /** @@ -66,6 +79,7 @@ public class DingtalkCallBackServiceImpl implements IDingtalkCallBackService * @return 结果 */ @Override + @Transactional(rollbackFor = Exception.class) public int insertDingtalkCallBack(DingtalkCallBack dingtalkCallBack) { dingtalkCallBack.setCreateTime(DateUtils.getNowDate()); @@ -77,7 +91,7 @@ public class DingtalkCallBackServiceImpl implements IDingtalkCallBackService dingtalkCallBackEvent.setEventName(t); String addressBook = sysDictDataServiceImpl.selectDictLabel("address_book", t); dingtalkCallBackEvent.setEventDesc(addressBook); - dingtalkCallBackEvent.setId(i); + dingtalkCallBackEvent.setCallBanckId((long)i); dingtalkCallBackEventMapper.insertDingtalkCallBackEvent(dingtalkCallBackEvent); }); // 同步到dingding @@ -96,6 +110,19 @@ public class DingtalkCallBackServiceImpl implements IDingtalkCallBackService public int updateDingtalkCallBack(DingtalkCallBack dingtalkCallBack) { dingtalkCallBack.setUpdateTime(DateUtils.getNowDate()); + dingtalkCallBackEventMapper.deleteDingtalkCallBackEventById(dingtalkCallBack.getId().intValue()); + DingtalkCallBackEvent dingtalkCallBackEvent=new DingtalkCallBackEvent(); + BeanUtils.copyProperties(dingtalkCallBack,dingtalkCallBackEvent); + List eventNameList = dingtalkCallBack.getEventNameList(); + eventNameList.forEach(t->{ + dingtalkCallBackEvent.setEventName(t); + String addressBook = sysDictDataServiceImpl.selectDictLabel("address_book", t); + dingtalkCallBackEvent.setEventDesc(addressBook); + dingtalkCallBackEvent.setCallBanckId(dingtalkCallBack.getId()); + dingtalkCallBackEvent.setCreateTime(DateUtils.getNowDate()); + dingtalkCallBackEvent.setCreateBy(dingtalkCallBack.getUpdateBy()); + dingtalkCallBackEventMapper.insertDingtalkCallBackEvent(dingtalkCallBackEvent); + }); return dingtalkCallBackMapper.updateDingtalkCallBack(dingtalkCallBack); } diff --git a/snow-system/src/main/resources/mapper/system/DingtalkCallBackEventMapper.xml b/snow-system/src/main/resources/mapper/system/DingtalkCallBackEventMapper.xml index 2a77dc3..cf2dbbc 100644 --- a/snow-system/src/main/resources/mapper/system/DingtalkCallBackEventMapper.xml +++ b/snow-system/src/main/resources/mapper/system/DingtalkCallBackEventMapper.xml @@ -22,11 +22,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" +
diff --git a/snow-common/src/main/java/com/snow/common/constant/Constants.java b/snow-common/src/main/java/com/snow/common/constant/Constants.java index 3715ad5..fbf76a5 100644 --- a/snow-common/src/main/java/com/snow/common/constant/Constants.java +++ b/snow-common/src/main/java/com/snow/common/constant/Constants.java @@ -108,4 +108,9 @@ public class Constants * 钉钉企业内部 AGENT_ID */ public static final String AGENT_ID="agent.id"; + + /** + * 通讯录事件type_key + */ + public static final String ADDRESS_BOOK="address_book"; } diff --git a/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java b/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java index 6e2c57b..c7e2ae0 100644 --- a/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java +++ b/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java @@ -7,24 +7,40 @@ package com.snow.common.enums; * @date 2020/9/18 10:18 */ public enum DingTalkListenerType { - DEPARTMENT_CREATE(1, "部门创建"), - DEPARTMENT_UPDATE(2, "部门更新"), - DEPARTMENT_DELETED(3, "部门删除"), + DEPARTMENT_CREATE(1, 2,"部门创建"), - USER_CREATED(4,"用户创建"), + DEPARTMENT_UPDATE(2, 2,"部门更新"), - CALL_BACK_REGISTER(10, "回调注册"), + DEPARTMENT_DELETED(3,2,"部门删除"), + + USER_CREATED(5,2,"用户创建"), + + CALL_BACK_REGISTER(20,10, "回调注册"), + + CALL_BACK_UPDATE(21,10, "回调更新"), + + CALL_BACK_DELETE(22,10, "回调删除"), ; - + /** + * 一级code + */ private final Integer code; + /** + * 二级code + */ + private final Integer type; + /** + * 描述 + */ private final String info; - DingTalkListenerType(Integer code, String info) + DingTalkListenerType(Integer code, Integer type,String info) { this.code = code; this.info = info; + this.type=type; } public Integer getCode() @@ -36,4 +52,9 @@ public enum DingTalkListenerType { { return info; } + + public Integer getType() { + return type; + } + } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java index 8c03103..97f6a1b 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java @@ -51,4 +51,18 @@ public class BaseConstantUrl { * 注册回调 */ public static final String REGISTER_CALL_BACK="https://oapi.dingtalk.com/call_back/register_call_back"; + /** + * 更新回调 + */ + public static final String UPDATE_CALL_BACK = "https://oapi.dingtalk.com/call_back/update_call_back"; + + /** + * 更新回调 + */ + public static final String DELETE_CALL_BACK = "https://oapi.dingtalk.com/call_back/delete_call_back"; + /** + * 获取回调失败 + */ + public static final String CALL_BACK_FAILED_RESULT = "https://oapi.dingtalk.com/call_back/get_call_back_failed_result"; + } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/CallBackService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/CallBackService.java index a7d06ca..e8ffc9b 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/CallBackService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/CallBackService.java @@ -1,6 +1,7 @@ package com.snow.dingtalk.listener; import com.alibaba.fastjson.JSON; +import com.snow.common.enums.DingTalkListenerType; import com.snow.common.utils.spring.SpringUtils; import com.snow.dingtalk.service.impl.CallBackServiceImpl; import com.snow.system.domain.DingtalkCallBack; @@ -17,11 +18,19 @@ import org.springframework.stereotype.Component; @Component @Slf4j public class CallBackService implements ISyncDingTalkInfo { - private CallBackServiceImpl departmentService=SpringUtils.getBean("callBackServiceImpl"); + + private CallBackServiceImpl callBackServiceImpl=SpringUtils.getBean("callBackServiceImpl"); @Override public void syncDingTalkInfoEvent(SyncEvent syncEvent) { log.info("调用创建钉钉注册回调传入的原始参数:{}"+JSON.toJSONString(syncEvent)); - departmentService.registerCallBack((DingtalkCallBack) syncEvent.getT()); + Enum eventType =(Enum) syncEvent.getT(); + if(eventType.equals(DingTalkListenerType.CALL_BACK_REGISTER.getCode())){ + callBackServiceImpl.registerCallBack((DingtalkCallBack) syncEvent.getT()); + } + else if( eventType.equals(DingTalkListenerType.CALL_BACK_UPDATE.getCode())){ + callBackServiceImpl.updateCallBack((DingtalkCallBack) syncEvent.getT()); + } + } } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java index a942aca..7053489 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java @@ -17,15 +17,15 @@ public class SyncDingTalkInfoFactory { public ISyncDingTalkInfo getSyncDingTalkService(SyncEvent syncEvent){ - Integer eventType = syncEvent.getEventType(); + Enum dingTalkEnum = (Enum) syncEvent.getT(); - if(eventType.equals(DingTalkListenerType.DEPARTMENT_CREATE.getCode())){ + if(dingTalkEnum.equals(DingTalkListenerType.DEPARTMENT_CREATE.getType())){ return new DepartmentCreateEventService(); } - else if(eventType.equals(DingTalkListenerType.USER_CREATED.getCode())){ + else if(dingTalkEnum.equals(DingTalkListenerType.USER_CREATED.getType())){ return new UserCreateEventService(); } - else if(eventType.equals(DingTalkListenerType.CALL_BACK_REGISTER.getCode())){ + else if(dingTalkEnum.equals(DingTalkListenerType.CALL_BACK_REGISTER.getType())){ return new CallBackService(); } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/CallBackService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/CallBackService.java index 8182de6..b0d3caa 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/CallBackService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/CallBackService.java @@ -13,4 +13,21 @@ public interface CallBackService { * 注册事件 */ void registerCallBack(DingtalkCallBack dingtalkCallBack); + + /** + * 更新事件 + * @param dingtalkCallBack + */ + void updateCallBack(DingtalkCallBack dingtalkCallBack); + + /** + * 删除事件 + * @param dingtalkCallBack + */ + void deleteCallBack(DingtalkCallBack dingtalkCallBack); + + /** + * 获取回调失败结果 + */ + void getCallBackFailedResult(); } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/CallBackServiceImpl.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/CallBackServiceImpl.java index 9507fae..d27017d 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/CallBackServiceImpl.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/CallBackServiceImpl.java @@ -5,10 +5,8 @@ import cn.hutool.cache.impl.TimedCache; import com.alibaba.fastjson.JSON; import com.dingtalk.api.DefaultDingTalkClient; import com.dingtalk.api.DingTalkClient; -import com.dingtalk.api.request.OapiCallBackRegisterCallBackRequest; -import com.dingtalk.api.request.OapiGettokenRequest; -import com.dingtalk.api.response.OapiCallBackRegisterCallBackResponse; -import com.dingtalk.api.response.OapiGettokenResponse; +import com.dingtalk.api.request.*; +import com.dingtalk.api.response.*; import com.snow.common.constant.Constants; import com.snow.common.utils.StringUtils; import com.snow.dingtalk.common.BaseConstantUrl; @@ -53,7 +51,65 @@ public class CallBackServiceImpl extends BaseService implements CallBackService } } + @Override + public void updateCallBack(DingtalkCallBack dingtalkCallBack) { + DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.UPDATE_CALL_BACK); + OapiCallBackUpdateCallBackRequest request = new OapiCallBackUpdateCallBackRequest(); + request.setUrl(dingtalkCallBack.getUrl()); + request.setAesKey(dingtalkCallBack.getAesKey()); + request.setToken(dingtalkCallBack.getToken()); + request.setCallBackTag(dingtalkCallBack.getEventNameList()); + try { + OapiCallBackUpdateCallBackResponse response = client.execute(request,getCallBackDingTalkToken(dingtalkCallBack)); + if(response.getErrcode()==0){ + syncDingTalkErrorOperLog(BaseConstantUrl.UPDATE_CALL_BACK,response.getMessage(),"updateCallBack()", JSON.toJSONString(request)); + }else { + //记录获取token失败日志 + syncDingTalkErrorOperLog(BaseConstantUrl.UPDATE_CALL_BACK,response.getErrmsg(),"updateCallBack()", JSON.toJSONString(request)); + } + } catch (ApiException e) { + syncDingTalkErrorOperLog(BaseConstantUrl.UPDATE_CALL_BACK,e.getMessage(),"updateCallBack()", JSON.toJSONString(request)); + e.printStackTrace(); + } + } + @Override + public void deleteCallBack(DingtalkCallBack dingtalkCallBack) { + DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.DELETE_CALL_BACK); + OapiCallBackDeleteCallBackRequest request = new OapiCallBackDeleteCallBackRequest(); + request.setHttpMethod("GET"); + try { + OapiCallBackDeleteCallBackResponse response = client.execute(request, getDingTalkToken()); + if(response.getErrcode()==0){ + syncDingTalkErrorOperLog(BaseConstantUrl.DELETE_CALL_BACK,response.getMessage(),"deleteCallBack()", JSON.toJSONString(request)); + }else { + //记录获取token失败日志 + syncDingTalkErrorOperLog(BaseConstantUrl.DELETE_CALL_BACK,response.getErrmsg(),"deleteCallBack()", JSON.toJSONString(request)); + } + } catch (ApiException e) { + syncDingTalkErrorOperLog(BaseConstantUrl.DELETE_CALL_BACK,e.getMessage(),"deleteCallBack()", JSON.toJSONString(request)); + e.printStackTrace(); + } + } + + @Override + public void getCallBackFailedResult() { + DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.CALL_BACK_FAILED_RESULT); + OapiCallBackGetCallBackFailedResultRequest request = new OapiCallBackGetCallBackFailedResultRequest(); + request.setHttpMethod("GET"); + try { + OapiCallBackGetCallBackFailedResultResponse response = client.execute(request, getDingTalkToken()); + if(response.getErrcode()==0){ + syncDingTalkErrorOperLog(BaseConstantUrl.DELETE_CALL_BACK,response.getMessage(),"getCallBackFailedResult()", JSON.toJSONString(request)); + }else { + //记录获取token失败日志 + syncDingTalkErrorOperLog(BaseConstantUrl.DELETE_CALL_BACK,response.getErrmsg(),"getCallBackFailedResult()", JSON.toJSONString(request)); + } + } catch (ApiException e) { + syncDingTalkErrorOperLog(BaseConstantUrl.DELETE_CALL_BACK,e.getMessage(),"getCallBackFailedResult()", JSON.toJSONString(request)); + e.printStackTrace(); + } + } /** * 获取token * @return diff --git a/snow-system/src/main/java/com/snow/system/domain/DingtalkCallBack.java b/snow-system/src/main/java/com/snow/system/domain/DingtalkCallBack.java index 8e10fe2..ce872d1 100644 --- a/snow-system/src/main/java/com/snow/system/domain/DingtalkCallBack.java +++ b/snow-system/src/main/java/com/snow/system/domain/DingtalkCallBack.java @@ -45,8 +45,13 @@ public class DingtalkCallBack extends BaseEntity @Excel(name = "回调名称") private String callBackName; + /** + * 部门事件集合 + */ private List eventNameList; + private Boolean flag=false; + public void setId(Long id) { this.id = id; diff --git a/snow-system/src/main/java/com/snow/system/domain/SysDictData.java b/snow-system/src/main/java/com/snow/system/domain/SysDictData.java index 3aa4f77..9f40c25 100644 --- a/snow-system/src/main/java/com/snow/system/domain/SysDictData.java +++ b/snow-system/src/main/java/com/snow/system/domain/SysDictData.java @@ -52,6 +52,8 @@ public class SysDictData extends BaseEntity @Excel(name = "状态", readConverterExp = "0=正常,1=停用") private String status; + private Boolean extfalg=true; + public Long getDictCode() { return dictCode; diff --git a/snow-system/src/main/java/com/snow/system/event/SyncEvent.java b/snow-system/src/main/java/com/snow/system/event/SyncEvent.java index bdf6aec..d38a761 100644 --- a/snow-system/src/main/java/com/snow/system/event/SyncEvent.java +++ b/snow-system/src/main/java/com/snow/system/event/SyncEvent.java @@ -15,11 +15,25 @@ public class SyncEvent extends ApplicationEvent { private T t; + public SyncEvent(Object source) { + super(source); + } - public SyncEvent(Object source,Integer eventType,T t) { + public SyncEvent(Object source,T t) { + super(source); + this.t=t; + } + public SyncEvent(Object source,Integer eventType) { + super(source); + this.eventType = eventType; + + } + + public SyncEvent(Integer eventType,Object source,T t) { super(source); this.eventType = eventType; this.t=t; + } diff --git a/snow-system/src/main/java/com/snow/system/service/impl/DingtalkCallBackServiceImpl.java b/snow-system/src/main/java/com/snow/system/service/impl/DingtalkCallBackServiceImpl.java index 39eaf69..561fb94 100644 --- a/snow-system/src/main/java/com/snow/system/service/impl/DingtalkCallBackServiceImpl.java +++ b/snow-system/src/main/java/com/snow/system/service/impl/DingtalkCallBackServiceImpl.java @@ -1,12 +1,15 @@ package com.snow.system.service.impl; +import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; +import com.snow.common.constant.Constants; import com.snow.common.enums.DingTalkListenerType; import com.snow.common.utils.DateUtils; import com.snow.common.utils.StringUtils; import com.snow.system.domain.DingtalkCallBackEvent; +import com.snow.system.domain.SysDictData; import com.snow.system.event.SyncEvent; import com.snow.system.mapper.DingtalkCallBackEventMapper; import org.springframework.beans.BeanUtils; @@ -38,6 +41,7 @@ public class DingtalkCallBackServiceImpl implements IDingtalkCallBackService private SysDictDataServiceImpl sysDictDataServiceImpl; @Resource private ApplicationContext applicationContext; + /** * 查询回调事件 * @@ -89,13 +93,13 @@ public class DingtalkCallBackServiceImpl implements IDingtalkCallBackService int i = dingtalkCallBackMapper.insertDingtalkCallBack(dingtalkCallBack); eventNameList.forEach(t->{ dingtalkCallBackEvent.setEventName(t); - String addressBook = sysDictDataServiceImpl.selectDictLabel("address_book", t); + String addressBook = sysDictDataServiceImpl.selectDictLabel(Constants.ADDRESS_BOOK, t); dingtalkCallBackEvent.setEventDesc(addressBook); dingtalkCallBackEvent.setCallBanckId((long)i); dingtalkCallBackEventMapper.insertDingtalkCallBackEvent(dingtalkCallBackEvent); }); // 同步到dingding - SyncEvent syncEvent = new SyncEvent(dingtalkCallBack, DingTalkListenerType.CALL_BACK_REGISTER.getCode(), dingtalkCallBack); + SyncEvent syncEvent = new SyncEvent(dingtalkCallBack, DingTalkListenerType.CALL_BACK_REGISTER); applicationContext.publishEvent(syncEvent); return 1; } @@ -107,6 +111,7 @@ public class DingtalkCallBackServiceImpl implements IDingtalkCallBackService * @return 结果 */ @Override + @Transactional(rollbackFor = Exception.class) public int updateDingtalkCallBack(DingtalkCallBack dingtalkCallBack) { dingtalkCallBack.setUpdateTime(DateUtils.getNowDate()); @@ -116,14 +121,18 @@ public class DingtalkCallBackServiceImpl implements IDingtalkCallBackService List eventNameList = dingtalkCallBack.getEventNameList(); eventNameList.forEach(t->{ dingtalkCallBackEvent.setEventName(t); - String addressBook = sysDictDataServiceImpl.selectDictLabel("address_book", t); + String addressBook = sysDictDataServiceImpl.selectDictLabel(Constants.ADDRESS_BOOK, t); dingtalkCallBackEvent.setEventDesc(addressBook); dingtalkCallBackEvent.setCallBanckId(dingtalkCallBack.getId()); dingtalkCallBackEvent.setCreateTime(DateUtils.getNowDate()); dingtalkCallBackEvent.setCreateBy(dingtalkCallBack.getUpdateBy()); dingtalkCallBackEventMapper.insertDingtalkCallBackEvent(dingtalkCallBackEvent); }); - return dingtalkCallBackMapper.updateDingtalkCallBack(dingtalkCallBack); + int i = dingtalkCallBackMapper.updateDingtalkCallBack(dingtalkCallBack); + // 同步到dingding + SyncEvent syncEvent = new SyncEvent(dingtalkCallBack, DingTalkListenerType.CALL_BACK_UPDATE); + applicationContext.publishEvent(syncEvent); + return i; } /** @@ -135,7 +144,15 @@ public class DingtalkCallBackServiceImpl implements IDingtalkCallBackService @Override public int deleteDingtalkCallBackByIds(String ids) { - return dingtalkCallBackMapper.deleteDingtalkCallBackByIds(Convert.toStrArray(ids)); + List idList = Arrays.asList(Convert.toStrArray(ids)); + idList.forEach(t->{ + dingtalkCallBackEventMapper.deleteDingtalkCallBackEventByCallBanckId(Integer.parseInt(t)); + }); + int i = dingtalkCallBackMapper.deleteDingtalkCallBackByIds(Convert.toStrArray(ids)); + // 同步到dingding + SyncEvent syncEvent = new SyncEvent(idList, DingTalkListenerType.CALL_BACK_DELETE); + applicationContext.publishEvent(syncEvent); + return i; } /** @@ -149,4 +166,5 @@ public class DingtalkCallBackServiceImpl implements IDingtalkCallBackService { return dingtalkCallBackMapper.deleteDingtalkCallBackById(id); } + } diff --git a/snow-system/src/main/java/com/snow/system/service/impl/SysDeptServiceImpl.java b/snow-system/src/main/java/com/snow/system/service/impl/SysDeptServiceImpl.java index 2892004..095025f 100644 --- a/snow-system/src/main/java/com/snow/system/service/impl/SysDeptServiceImpl.java +++ b/snow-system/src/main/java/com/snow/system/service/impl/SysDeptServiceImpl.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import com.snow.common.enums.DingTalkListenerType; import com.snow.system.domain.SysDept; import com.snow.system.event.SyncEvent; import org.apache.commons.lang3.ArrayUtils; @@ -211,7 +212,8 @@ public class SysDeptServiceImpl implements ISysDeptService throw new BusinessException("部门停用,不允许新增"); } dept.setAncestors(info.getAncestors() + "," + dept.getParentId()); - SyncEvent syncEvent = new SyncEvent(dept, 1, dept); + //同步钉钉数据 + SyncEvent syncEvent = new SyncEvent(dept, DingTalkListenerType.DEPARTMENT_CREATE); applicationContext.publishEvent(syncEvent); return deptMapper.insertDept(dept); } diff --git a/snow-system/src/main/java/com/snow/system/service/impl/SysUserServiceImpl.java b/snow-system/src/main/java/com/snow/system/service/impl/SysUserServiceImpl.java index 7eb4fbf..f7c7f6e 100644 --- a/snow-system/src/main/java/com/snow/system/service/impl/SysUserServiceImpl.java +++ b/snow-system/src/main/java/com/snow/system/service/impl/SysUserServiceImpl.java @@ -3,6 +3,7 @@ package com.snow.system.service.impl; import java.util.ArrayList; import java.util.List; +import com.snow.common.enums.DingTalkListenerType; import com.snow.system.domain.SysUserPost; import com.snow.system.domain.SysUserRole; import com.snow.system.event.SyncEvent; @@ -209,7 +210,7 @@ public class SysUserServiceImpl implements ISysUserService // 新增用户与角色管理 insertUserRole(user.getUserId(), user.getRoleIds()); //同步用户数据 - SyncEvent syncEvent = new SyncEvent(user, 4, user); + SyncEvent syncEvent = new SyncEvent(user, DingTalkListenerType.USER_CREATED); applicationContext.publishEvent(syncEvent); return rows; } From 33390e4e83516425140d780f2928009df7051082 Mon Sep 17 00:00:00 2001 From: jinqiming <45981669@qq.com> Date: Fri, 6 Nov 2020 15:06:23 +0800 Subject: [PATCH 12/82] =?UTF-8?q?=E9=87=8D=E6=9E=84=E7=9B=91=E5=90=AC?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/DingtalkCallBackController.java | 7 +- .../resources/templates/system/back/back.html | 1 + .../templates/system/back/detail.html | 74 +++++++++++++++++++ .../common/enums/DingTalkListenerType.java | 2 + .../dingtalk/listener/CallBackService.java | 15 ++-- .../listener/SyncDingTalkInfoFactory.java | 10 +-- .../dingtalk/service/CallBackService.java | 5 +- .../service/impl/CallBackServiceImpl.java | 19 +++-- 8 files changed, 114 insertions(+), 19 deletions(-) create mode 100644 snow-admin/src/main/resources/templates/system/back/detail.html diff --git a/snow-admin/src/main/java/com/snow/web/controller/system/DingtalkCallBackController.java b/snow-admin/src/main/java/com/snow/web/controller/system/DingtalkCallBackController.java index fa65b1a..6a26ab1 100644 --- a/snow-admin/src/main/java/com/snow/web/controller/system/DingtalkCallBackController.java +++ b/snow-admin/src/main/java/com/snow/web/controller/system/DingtalkCallBackController.java @@ -2,6 +2,8 @@ package com.snow.web.controller.system; import java.util.List; +import com.dingtalk.api.response.OapiCallBackGetCallBackFailedResultResponse; +import com.snow.dingtalk.service.impl.CallBackServiceImpl; import com.snow.framework.util.ShiroUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.beans.factory.annotation.Autowired; @@ -35,6 +37,8 @@ public class DingtalkCallBackController extends BaseController @Autowired private IDingtalkCallBackService dingtalkCallBackService; + @Autowired + private CallBackServiceImpl callBackServiceImpl; @RequiresPermissions("system:back:view") @GetMapping() @@ -132,7 +136,8 @@ public class DingtalkCallBackController extends BaseController @GetMapping("/detail/{id}") public String detail(@PathVariable("id") Long operId, ModelMap mmap) { - mmap.put("operLog", ""); + List callBackFailedResult = callBackServiceImpl.getCallBackFailedResult(); + mmap.put("operLog", callBackFailedResult); return prefix + "/detail"; } } diff --git a/snow-admin/src/main/resources/templates/system/back/back.html b/snow-admin/src/main/resources/templates/system/back/back.html index ff381c3..e2a1d66 100644 --- a/snow-admin/src/main/resources/templates/system/back/back.html +++ b/snow-admin/src/main/resources/templates/system/back/back.html @@ -46,6 +46,7 @@ + + \ No newline at end of file diff --git a/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java b/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java index c7e2ae0..7dcaa81 100644 --- a/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java +++ b/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java @@ -20,6 +20,8 @@ public enum DingTalkListenerType { CALL_BACK_UPDATE(21,10, "回调更新"), CALL_BACK_DELETE(22,10, "回调删除"), + + CALL_BACK_FAILED_RESULT(23,10, "获取回调失败结果"), ; diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/CallBackService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/CallBackService.java index e8ffc9b..0f695f1 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/CallBackService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/CallBackService.java @@ -24,13 +24,18 @@ public class CallBackService implements ISyncDingTalkInfo { @Override public void syncDingTalkInfoEvent(SyncEvent syncEvent) { log.info("调用创建钉钉注册回调传入的原始参数:{}"+JSON.toJSONString(syncEvent)); - Enum eventType =(Enum) syncEvent.getT(); - if(eventType.equals(DingTalkListenerType.CALL_BACK_REGISTER.getCode())){ - callBackServiceImpl.registerCallBack((DingtalkCallBack) syncEvent.getT()); + DingTalkListenerType eventType =(DingTalkListenerType) syncEvent.getT(); + Integer code = eventType.getCode(); + if(code.equals(DingTalkListenerType.CALL_BACK_REGISTER.getCode())){ + callBackServiceImpl.registerCallBack((DingtalkCallBack) syncEvent.getSource()); } - else if( eventType.equals(DingTalkListenerType.CALL_BACK_UPDATE.getCode())){ - callBackServiceImpl.updateCallBack((DingtalkCallBack) syncEvent.getT()); + else if( code.equals(DingTalkListenerType.CALL_BACK_UPDATE.getCode())){ + callBackServiceImpl.updateCallBack((DingtalkCallBack) syncEvent.getSource()); } + else if(code.equals(DingTalkListenerType.CALL_BACK_DELETE.getCode())){ + callBackServiceImpl.deleteCallBack((DingtalkCallBack) syncEvent.getSource()); + } + } } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java index 7053489..7a499f9 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java @@ -17,15 +17,15 @@ public class SyncDingTalkInfoFactory { public ISyncDingTalkInfo getSyncDingTalkService(SyncEvent syncEvent){ - Enum dingTalkEnum = (Enum) syncEvent.getT(); - - if(dingTalkEnum.equals(DingTalkListenerType.DEPARTMENT_CREATE.getType())){ + DingTalkListenerType dingTalkEnum = (DingTalkListenerType) syncEvent.getT(); + Integer type = dingTalkEnum.getType(); + if(type.equals(DingTalkListenerType.DEPARTMENT_CREATE.getType())){ return new DepartmentCreateEventService(); } - else if(dingTalkEnum.equals(DingTalkListenerType.USER_CREATED.getType())){ + else if(type.equals(DingTalkListenerType.USER_CREATED.getType())){ return new UserCreateEventService(); } - else if(dingTalkEnum.equals(DingTalkListenerType.CALL_BACK_REGISTER.getType())){ + else if(type.equals(DingTalkListenerType.CALL_BACK_REGISTER.getType())){ return new CallBackService(); } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/CallBackService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/CallBackService.java index b0d3caa..3b6d47e 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/CallBackService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/CallBackService.java @@ -1,7 +1,10 @@ package com.snow.dingtalk.service; +import com.dingtalk.api.response.OapiCallBackGetCallBackFailedResultResponse; import com.snow.system.domain.DingtalkCallBack; +import java.util.List; + /** * @author qimingjin * @Title: @@ -29,5 +32,5 @@ public interface CallBackService { /** * 获取回调失败结果 */ - void getCallBackFailedResult(); + List getCallBackFailedResult(); } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/CallBackServiceImpl.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/CallBackServiceImpl.java index d27017d..7325168 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/CallBackServiceImpl.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/CallBackServiceImpl.java @@ -16,7 +16,8 @@ import com.snow.system.domain.DingtalkCallBack; import com.taobao.api.ApiException; import org.springframework.stereotype.Service; -import java.util.Arrays; +import java.util.List; + /** * @author qimingjin @@ -38,7 +39,7 @@ public class CallBackServiceImpl extends BaseService implements CallBackService request.setToken(dingtalkCallBack.getToken()); request.setCallBackTag(dingtalkCallBack.getEventNameList()); try { - OapiCallBackRegisterCallBackResponse response = client.execute(request,getCallBackDingTalkToken(dingtalkCallBack)); + OapiCallBackRegisterCallBackResponse response = client.execute(request,getDingTalkToken()); if(response.getErrcode()==0){ syncDingTalkErrorOperLog(BaseConstantUrl.REGISTER_CALL_BACK,response.getMessage(),"registerCallBack()", JSON.toJSONString(request)); }else { @@ -60,7 +61,7 @@ public class CallBackServiceImpl extends BaseService implements CallBackService request.setToken(dingtalkCallBack.getToken()); request.setCallBackTag(dingtalkCallBack.getEventNameList()); try { - OapiCallBackUpdateCallBackResponse response = client.execute(request,getCallBackDingTalkToken(dingtalkCallBack)); + OapiCallBackUpdateCallBackResponse response = client.execute(request,getDingTalkToken()); if(response.getErrcode()==0){ syncDingTalkErrorOperLog(BaseConstantUrl.UPDATE_CALL_BACK,response.getMessage(),"updateCallBack()", JSON.toJSONString(request)); }else { @@ -93,27 +94,31 @@ public class CallBackServiceImpl extends BaseService implements CallBackService } @Override - public void getCallBackFailedResult() { + public List getCallBackFailedResult() { DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.CALL_BACK_FAILED_RESULT); OapiCallBackGetCallBackFailedResultRequest request = new OapiCallBackGetCallBackFailedResultRequest(); request.setHttpMethod("GET"); try { OapiCallBackGetCallBackFailedResultResponse response = client.execute(request, getDingTalkToken()); if(response.getErrcode()==0){ - syncDingTalkErrorOperLog(BaseConstantUrl.DELETE_CALL_BACK,response.getMessage(),"getCallBackFailedResult()", JSON.toJSONString(request)); + List failedList = response.getFailedList(); + syncDingTalkErrorOperLog(BaseConstantUrl.CALL_BACK_FAILED_RESULT,response.getMessage(),"getCallBackFailedResult()", JSON.toJSONString(request)); + return failedList; }else { //记录获取token失败日志 - syncDingTalkErrorOperLog(BaseConstantUrl.DELETE_CALL_BACK,response.getErrmsg(),"getCallBackFailedResult()", JSON.toJSONString(request)); + syncDingTalkErrorOperLog(BaseConstantUrl.CALL_BACK_FAILED_RESULT,response.getErrmsg(),"getCallBackFailedResult()", JSON.toJSONString(request)); } } catch (ApiException e) { - syncDingTalkErrorOperLog(BaseConstantUrl.DELETE_CALL_BACK,e.getMessage(),"getCallBackFailedResult()", JSON.toJSONString(request)); + syncDingTalkErrorOperLog(BaseConstantUrl.CALL_BACK_FAILED_RESULT,e.getMessage(),"getCallBackFailedResult()", JSON.toJSONString(request)); e.printStackTrace(); } + return null; } /** * 获取token * @return */ + @Deprecated public String getCallBackDingTalkToken(DingtalkCallBack dingtalkCallBack){ //创建缓存,缓存默认是7100S TimedCache timedCache = CacheUtil.newTimedCache(7100); From 1541b160b6d10f7dd2c2624eaec17eaa7577ee80 Mon Sep 17 00:00:00 2001 From: jinqiming <45981669@qq.com> Date: Mon, 9 Nov 2020 18:31:46 +0800 Subject: [PATCH 13/82] =?UTF-8?q?=E9=87=8D=E6=9E=84=E7=9B=91=E5=90=AC?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/FinanceAlipayFlowController.java | 152 +++++++++ .../resources/templates/system/flow/add.html | 168 ++++++++++ .../resources/templates/system/flow/edit.html | 169 ++++++++++ .../resources/templates/system/flow/flow.html | 271 ++++++++++++++++ snow-common/pom.xml | 7 + snow-dingtalk/pom.xml | 12 +- .../snow/dingtalk/common/BaseConstantUrl.java | 5 +- .../snow/dingtalk/service/UserService.java | 44 +-- .../service/impl/UserServiceImpl.java | 66 ++++ .../main/resources/lib/taobao-sdk-java.jar | Bin 0 -> 5063022 bytes .../excel/FinanceAlipayFlowListener.java | 72 +++++ .../snow/system/domain/FinanceAlipayFlow.java | 289 ++++++++++++++++++ .../domain/FinanceAlipayFlowImport.java | 289 ++++++++++++++++++ .../java/com/snow/system/domain/SysUser.java | 91 ++++++ .../mapper/FinanceAlipayFlowMapper.java | 61 ++++ .../service/IFinanceAlipayFlowService.java | 61 ++++ .../impl/FinanceAlipayFlowServiceImpl.java | 96 ++++++ .../mapper/system/FinanceAlipayFlowMapper.xml | 155 ++++++++++ 18 files changed, 1968 insertions(+), 40 deletions(-) create mode 100644 snow-admin/src/main/java/com/snow/web/controller/system/FinanceAlipayFlowController.java create mode 100644 snow-admin/src/main/resources/templates/system/flow/add.html create mode 100644 snow-admin/src/main/resources/templates/system/flow/edit.html create mode 100644 snow-admin/src/main/resources/templates/system/flow/flow.html create mode 100644 snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/UserServiceImpl.java create mode 100644 snow-dingtalk/src/main/resources/lib/taobao-sdk-java.jar create mode 100644 snow-framework/src/main/java/com/snow/framework/excel/FinanceAlipayFlowListener.java create mode 100644 snow-system/src/main/java/com/snow/system/domain/FinanceAlipayFlow.java create mode 100644 snow-system/src/main/java/com/snow/system/domain/FinanceAlipayFlowImport.java create mode 100644 snow-system/src/main/java/com/snow/system/mapper/FinanceAlipayFlowMapper.java create mode 100644 snow-system/src/main/java/com/snow/system/service/IFinanceAlipayFlowService.java create mode 100644 snow-system/src/main/java/com/snow/system/service/impl/FinanceAlipayFlowServiceImpl.java create mode 100644 snow-system/src/main/resources/mapper/system/FinanceAlipayFlowMapper.xml diff --git a/snow-admin/src/main/java/com/snow/web/controller/system/FinanceAlipayFlowController.java b/snow-admin/src/main/java/com/snow/web/controller/system/FinanceAlipayFlowController.java new file mode 100644 index 0000000..ca8ba5e --- /dev/null +++ b/snow-admin/src/main/java/com/snow/web/controller/system/FinanceAlipayFlowController.java @@ -0,0 +1,152 @@ +package com.snow.web.controller.system; + +import java.util.List; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.snow.framework.excel.FinanceAlipayFlowListener; +import com.snow.framework.util.ShiroUtils; +import com.snow.system.domain.FinanceAlipayFlowImport; +import com.snow.system.domain.SysUser; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import com.snow.common.annotation.Log; +import com.snow.common.enums.BusinessType; +import com.snow.system.domain.FinanceAlipayFlow; +import com.snow.system.service.IFinanceAlipayFlowService; +import com.snow.common.core.controller.BaseController; +import com.snow.common.core.domain.AjaxResult; +import com.snow.common.utils.poi.ExcelUtil; +import com.snow.common.core.page.TableDataInfo; +import org.springframework.web.multipart.MultipartFile; + +/** + * 财务支付宝流水Controller + * + * @author snow + * @date 2020-11-09 + */ +@Controller +@RequestMapping("/system/flow") +public class FinanceAlipayFlowController extends BaseController +{ + private String prefix = "system/flow"; + + @Autowired + private IFinanceAlipayFlowService financeAlipayFlowService; + + @RequiresPermissions("system:flow:view") + @GetMapping() + public String flow() + { + return prefix + "/flow"; + } + + /** + * 查询财务支付宝流水列表 + */ + @RequiresPermissions("system:flow:list") + @PostMapping("/list") + @ResponseBody + public TableDataInfo list(FinanceAlipayFlow financeAlipayFlow) + { + startPage(); + List list = financeAlipayFlowService.selectFinanceAlipayFlowList(financeAlipayFlow); + return getDataTable(list); + } + + /** + * 导出财务支付宝流水列表 + */ + @RequiresPermissions("system:flow:export") + @Log(title = "财务支付宝流水", businessType = BusinessType.EXPORT) + @PostMapping("/export") + @ResponseBody + public AjaxResult export(FinanceAlipayFlow financeAlipayFlow) + { + List list = financeAlipayFlowService.selectFinanceAlipayFlowList(financeAlipayFlow); + ExcelUtil util = new ExcelUtil(FinanceAlipayFlow.class); + return util.exportExcel(list, "flow"); + } + + /** + * 新增财务支付宝流水 + */ + @GetMapping("/add") + public String add() + { + return prefix + "/add"; + } + + /** + * 新增保存财务支付宝流水 + */ + @RequiresPermissions("system:flow:add") + @Log(title = "财务支付宝流水", businessType = BusinessType.INSERT) + @PostMapping("/add") + @ResponseBody + public AjaxResult addSave(FinanceAlipayFlow financeAlipayFlow) + { + return toAjax(financeAlipayFlowService.insertFinanceAlipayFlow(financeAlipayFlow)); + } + + /** + * 修改财务支付宝流水 + */ + @GetMapping("/edit/{id}") + public String edit(@PathVariable("id") Long id, ModelMap mmap) + { + FinanceAlipayFlow financeAlipayFlow = financeAlipayFlowService.selectFinanceAlipayFlowById(id); + mmap.put("financeAlipayFlow", financeAlipayFlow); + return prefix + "/edit"; + } + + /** + * 修改保存财务支付宝流水 + */ + @RequiresPermissions("system:flow:edit") + @Log(title = "财务支付宝流水", businessType = BusinessType.UPDATE) + @PostMapping("/edit") + @ResponseBody + public AjaxResult editSave(FinanceAlipayFlow financeAlipayFlow) + { + return toAjax(financeAlipayFlowService.updateFinanceAlipayFlow(financeAlipayFlow)); + } + + /** + * 删除财务支付宝流水 + */ + @RequiresPermissions("system:flow:remove") + @Log(title = "财务支付宝流水", businessType = BusinessType.DELETE) + @PostMapping( "/remove") + @ResponseBody + public AjaxResult remove(String ids) + { + return toAjax(financeAlipayFlowService.deleteFinanceAlipayFlowByIds(ids)); + } + + + @Log(title = "财务支付宝流水", businessType = BusinessType.IMPORT) + @RequiresPermissions("system:flow:import") + @PostMapping("/importData") + @ResponseBody + public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception + { + + String operName = ShiroUtils.getSysUser().getLoginName(); + ExcelReader excelReader = EasyExcel.read(file.getInputStream(), FinanceAlipayFlowImport.class, new FinanceAlipayFlowListener()).build(); + ReadSheet readSheet = EasyExcel.readSheet(5).build(); + excelReader.read(readSheet); + // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的 + excelReader.finish(); + return AjaxResult.success(""); + } +} diff --git a/snow-admin/src/main/resources/templates/system/flow/add.html b/snow-admin/src/main/resources/templates/system/flow/add.html new file mode 100644 index 0000000..a45c080 --- /dev/null +++ b/snow-admin/src/main/resources/templates/system/flow/add.html @@ -0,0 +1,168 @@ + + + + + + + +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+ + +
+
+
+
+ +
+
+ + +
+
+
+
+ +
+
+ + +
+
+
+
+ +
+ +
+
+
+ +
+
+ + +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+ + +
+
+
+
+ +
+
+ + +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+ + +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/snow-admin/src/main/resources/templates/system/flow/edit.html b/snow-admin/src/main/resources/templates/system/flow/edit.html new file mode 100644 index 0000000..a44e3f2 --- /dev/null +++ b/snow-admin/src/main/resources/templates/system/flow/edit.html @@ -0,0 +1,169 @@ + + + + + + + +
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+ + +
+
+
+
+ +
+
+ + +
+
+
+
+ +
+
+ + +
+
+
+
+ +
+ +
+
+
+ +
+
+ + +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+ + +
+
+
+
+ +
+
+ + +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+ + +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/snow-admin/src/main/resources/templates/system/flow/flow.html b/snow-admin/src/main/resources/templates/system/flow/flow.html new file mode 100644 index 0000000..026f609 --- /dev/null +++ b/snow-admin/src/main/resources/templates/system/flow/flow.html @@ -0,0 +1,271 @@ + + + + + + +
+
+
+
+
+
    +
  • + + +
  • +
  • + + +
  • +
  • + + + - + +
  • +
  • + + + - + +
  • +
  • + + + - + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • +  搜索 +  重置 +
  • +
+
+
+
+ + +
+
+
+
+
+ + + + + + \ No newline at end of file diff --git a/snow-common/pom.xml b/snow-common/pom.xml index 2fe1641..8e94e94 100644 --- a/snow-common/pom.xml +++ b/snow-common/pom.xml @@ -101,6 +101,13 @@ 5.4.2 + + + com.alibaba + easyexcel + 2.1.6 + + \ No newline at end of file diff --git a/snow-dingtalk/pom.xml b/snow-dingtalk/pom.xml index 7ecc733..d1ba17a 100644 --- a/snow-dingtalk/pom.xml +++ b/snow-dingtalk/pom.xml @@ -19,11 +19,11 @@ snow-framework 4.3.1 - + com.taobao.top @@ -32,6 +32,14 @@ system ${pom.basedir}/src/main/resources/lib/lippi-oapi-encrpt.jar + + + com.dingtalk.sdk + dingtalk-sdk-java + dingtalk-SNAPSHOT + system + ${pom.basedir}/src/main/resources/lib/taobao-sdk-java.jar + org.projectlombok lombok diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java index 97f6a1b..ca83223 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseConstantUrl.java @@ -11,7 +11,7 @@ public class BaseConstantUrl { /** * 创建用户 */ - public static final String USER_CREATE="https://oapi.dingtalk.com/user/create"; + public static final String USER_CREATE= "https://oapi.dingtalk.com/topapi/v2/user/create"; /** * 获取token url */ @@ -65,4 +65,7 @@ public class BaseConstantUrl { */ public static final String CALL_BACK_FAILED_RESULT = "https://oapi.dingtalk.com/call_back/get_call_back_failed_result"; + + + } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/UserService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/UserService.java index b5c469b..d803d2c 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/UserService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/UserService.java @@ -1,18 +1,6 @@ package com.snow.dingtalk.service; -import com.alibaba.fastjson.JSON; -import com.dingtalk.api.DefaultDingTalkClient; -import com.dingtalk.api.DingTalkClient; -import com.dingtalk.api.request.OapiUserCreateRequest; -import com.dingtalk.api.response.OapiUserCreateResponse; -import com.snow.dingtalk.common.BaseConstantUrl; -import com.snow.dingtalk.common.BaseService; -import com.snow.dingtalk.model.WorkrecordAddRequest; -import com.snow.system.service.ISysConfigService; -import com.taobao.api.ApiException; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; +import com.snow.system.domain.SysUser; /** * @author qimingjin @@ -20,33 +8,15 @@ import org.springframework.stereotype.Service; * @Description: * @date 2020/9/22 14:29 */ -@Service -public class UserService extends BaseService { - @Autowired - private ISysConfigService isysConfigService; + +public interface UserService { + /** - * 创建工作待办 - * @param workrecordAddRequest + * 创建用户 + * @param * @return */ - public String create(WorkrecordAddRequest workrecordAddRequest){ - DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.USER_CREATE); - OapiUserCreateRequest request = new OapiUserCreateRequest(); - BeanUtils.copyProperties(workrecordAddRequest,request); - try { - OapiUserCreateResponse response = client.execute(request, getDingTalkToken()); - if (response.getErrcode()==0){ - syncDingTalkErrorOperLog(BaseConstantUrl.USER_CREATE,response.getMessage(),"UserCreateRequest",JSON.toJSONString(request)); - return response.getUserid(); - }else { - syncDingTalkErrorOperLog(BaseConstantUrl.USER_CREATE,response.getErrmsg(),"UserCreateRequest",JSON.toJSONString(request)); - } - } catch (ApiException e) { - e.printStackTrace(); - syncDingTalkErrorOperLog(BaseConstantUrl.USER_CREATE,e.getMessage(),"UserCreateRequest",JSON.toJSONString(request)); - } - return null; - } + String create(SysUser sysUser); } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/UserServiceImpl.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..0df92e6 --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/UserServiceImpl.java @@ -0,0 +1,66 @@ +package com.snow.dingtalk.service.impl; + +import com.dingtalk.api.DefaultDingTalkClient; +import com.dingtalk.api.DingTalkClient; +import com.dingtalk.api.request.OapiV2UserCreateRequest; +import com.dingtalk.api.response.OapiV2UserCreateResponse; +import com.snow.dingtalk.common.BaseConstantUrl; +import com.snow.dingtalk.common.BaseService; +import com.snow.dingtalk.service.UserService; +import com.snow.system.domain.SysUser; +import com.taobao.api.ApiException; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/11/9 10:51 + */ +@Service +public class UserServiceImpl extends BaseService implements UserService { + + @Override + public String create(SysUser sysUser) { + DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.USER_CREATE); + OapiV2UserCreateRequest req = new OapiV2UserCreateRequest(); + req.setUserid(String.valueOf(sysUser.getUserId())); + req.setName(sysUser.getUserName()); + req.setMobile(sysUser.getPhonenumber()); + req.setHideMobile(false); + //req.setTelephone(sysUser.getPhonenumber()); + req.setJobNumber(sysUser.getJobnumber()); + req.setTitle("技术总监"); + req.setEmail("test@xxx.com"); + req.setOrgEmail("test@xxx.com"); + req.setWorkPlace("未来park"); + req.setRemark("备注备注"); + req.setDeptIdList("\"2,3,4\""); + List list2 = new ArrayList<>(); + OapiV2UserCreateRequest.DeptOrder obj3 = new OapiV2UserCreateRequest.DeptOrder(); + list2.add(obj3); + obj3.setDeptId(2L); + obj3.setOrder(1L); + req.setDeptOrderList(list2); + List list5 = new ArrayList<>(); + OapiV2UserCreateRequest.DeptTitle obj6 = new OapiV2UserCreateRequest.DeptTitle(); + list5.add(obj6); + obj6.setDeptId(2L); + obj6.setTitle("资深产品经理"); + req.setDeptTitleList(list5); + req.setExtension("{\"爱好\":\"旅游\",\"年龄\":\"24\"}"); + req.setSeniorMode(false); + req.setHiredDate(1597573616828L); + OapiV2UserCreateResponse rsp = null; + try { + rsp = client.execute(req, getDingTalkToken()); + } catch (ApiException e) { + e.printStackTrace(); + } + System.out.println(rsp.getBody()); + return null; + } +} diff --git a/snow-dingtalk/src/main/resources/lib/taobao-sdk-java.jar b/snow-dingtalk/src/main/resources/lib/taobao-sdk-java.jar new file mode 100644 index 0000000000000000000000000000000000000000..ad4f9f7fbbcc85d36074efcd27a4d7c4b02cf628 GIT binary patch literal 5063022 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 z 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 z

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

v2`sG~!TL8+TWgaRXV6 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 z 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%0ALRLm7Kc_v>^1oPmFdeEI5WsSndc&Bi8hnx38R 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

Xmk?(USU7o`Mb!Y5S{OK6K)7wPf} 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�P3BW#aP4p2F?L^{ip#o?DqguRPm}(0|uS> zr5|S6Q%R~Hbx56LL$PH&!4|VJucgQztdQ-9Z{KY(!X303qz39AtFmCeU!qHd>mP+! zlO1GNryfNJV&5hrrDbN~#7NAxoktBTR=s!s8)h8WRORO-+O>a=-oF%I+78-3L!EPHhHHom7j3O*Fr!RKcQCPT z?#QocMu}CA?YgDpu&g8+xbu_%KEx^fT+!LYS$8O8qkCP-H(U1!I-T?Zy?^%01oZbf z#VMv*L-l_#l}%%jUz0%+a_(G1I1kqaefPNk!*&qc2Tzt|_RZY@zpt-97&-q(s&>UaVW1_z;YcK$0gtJf9=oI` zbU@0TGg&jP7E5zk=z_#X5F{cK!zc((=uR)F{BG?xMcd{bkrjcNMpOlM`YKDK|FJCnKe}N5DE|LSGWjp; z1Mk=#iGDixkWcl+s`j>gR=8}gLw-u?j@TOc{0RA8eD=lM+AV&m*%bhf0VsrbY<)`Z?NabI#`(eT>mZ@BNJe7P)_WfV&%eh!W1={7YtuwNL7ehA)!7{VA&Y5-krY?DoMCno|^F8Wqow*GBeIE z<1viaNVS4ugx}W^S~+Vmo^&Jr^QLVU20ejNv-H40oZ@y(3wg6$E01>gfqj zI!z`9CMV=l&iw36!rcB` z>9t>c#n6wRy!BIphDCmSvFW~aTcjyxv(UU7chsML`yM@M>7qMq4x|Q44*ix(XssJ1 zrf*#M_A-%Az-)K`pz4JszEaJ^3;0Fh{dVU4tnIg-v9=ABbbG9i9EsK9-MY((ppGYu z#XKWXJ8Qh(yG}{YA*;0x6?eBSV(f%8pXd&&9&|=^2oybKzQcd$Mu~#haE>?S^6xvr zQUol{d%apeoicSyw~y(qlogv%(49fKk{0C{VjpXwb=8u+dj;1Y=Cc)X$8mk zTP$Zu4Z_Ir>C9%nLmn-X4Mg1w3dU%BnAoRc=-V8w<+{jakh!J<6R(&9I-Y&q%q_{I zDU)3cv-+;SD4CjH39lHRg_RYbdj-O2{dS>`%Sv+^R-W3UM7xV_Lx|eq{8qmvcI5$Y z>;g5Cnlw(t&EF0ffzRYD)EB)1>Mu90N&fdN^WR;TvQ?(+7X%S=e`MLAW5R1Jbum1|R$Ve@Xr@soSp{5@I?V;8xVYp}pUn(BMMc*=s z5l4Vbr~nD;pi^?8v{0!uU_sS<*L?r*^bu-d9nGJW}+GeR~e%HRFm3XWyod15N z^C8_CKI4kG6lTAT+%eyIWCl&jzUk6tch%UwVFF<(@hS*a&ZKLMTbsi5_oh9|kB?OmA_M?7%N z17b4~{%5J6-QXCz1>hD&qQRYvC%c{CT$n_PFBe056KD56>H@}a2siS8)?$sL!hMIq z+HqQbE;PujKvY=~@cL7PJs7zF073Kc2jz8`Bi?|+W+)Wz=n$UlKG1#Ak|bKN%6x80 z87Is-RP<>pvaZSzgCPHS67YH>Y)+_*WfLKg`7Uz}sJW4S-U|vTzi1>(-H^tvwWe<0 zWymN!gD*g|#Z6t@qRw2N_%OH%QOGk88T8mBg0xWd>sL35A|V=?%1G`NmH73?s2k?^O2gZ~vi`(H~A6)OvSBUd-)e;Sl!t82NSs-b>zH@I3@0=q&oUdn_g3StUE z{s3i#0wP`;4Ivz?UT7nSOT5l6g}~y_Roq14Kt&tE*rr{qKrAYH9HRbEI`{A)pXe1- z;-A!;<~!MR>3+!O`S>N!vkg=Ww_;o-VvP^(q&hUqi#w1={XFQ1OTh|T=}8R^N5#d9 zH-OArxTjVAu1m&I0zmRI9zyId<3-2Li8F#dpteP$V9QF7IK#ANBsz-4-Na<(#0w6q z0yhwmKhK)G4FWV^-(%}9-X=t*qFH8l;rYFFcq33Vwku>EF8p5-wR6%>%j5n8=iHWqG$CZFS z-(Zt|Mzqjy)J+NdcHpkww{Aa?Etz4(lk1XTJ}lo1Hj%`4oaR4`5^Y4p#>{0fIf{BI ziyAcb>dw7pVy=B1)77oZov%VXL&{uYArEQbsfA@fBkpl#<-4h(JJiqu`) zGsW>;egs-mM}s`5{+HPFsJ!AGwO_OLnK8tmvVH6){AxXA)Xn}a`kD9$xvjdB{K%Ie zQBn6sQzVCLXT$^b_WT_?J*DC~Ds2~no@-~Yhns7#7LAWvXV@<{R>D3#LY4cf%OqXYps5ju{XDTEpUC!aZ{M(lnVUer>Lx{l;B-e zckCW`6BWdXnOZJj;+qyz|ZY7NPYE!T6r8AmN{Nj^W zlj`DQ+F6-4^^YY#cSg4}n<+FVJXIqm3B)=-Vf&julsfO@A#E`)l?Ns=Sv1n|7^Z< z56dx-$)A*wYhP0^xDYJg!Q{mnprL8TO8f{2`fb>P%Cz>OD?xc6GEf)aL24l;jbktT zN~O5f&x8#LhY#W{1f=s?4yXB7GIqF- zBTbZ2@*RpC&R8P`ZO|4?!=^5^YK?B% z12PrVAz;V6x@r{u+yjeLd7mLEzaLEq?^@ z`HnSm#5|I?i*LFuriYR2>J(DCHFxQFU^=<#j!av^v^wS-zt9^x$_K}x@YplB&J}qg z`aCmS!Px7d#E>TfZEDXmt@dXp(*S@h&SQ?ON7{J_z2eu*<1gY*5+$dbM zDpW&lsT3x1T0jbv{Efi8tO01`&_I=Gmgs!6(HiG-kQ=}esy1wGGDW(KeG&cSyl%MY z+#XxYjH8EEO$w^^*c|vkYhg2oBg*EdLm)FNAo8&k2;XLJ`wpg-@HUQnz2eA=yvcM+ z@HZSLE}uF4{5bd->ZGh|3411vj6fOvNy8*j}#>c|00f^k)xxPy~TeNkNe+< z_s@oeu!E`BSG&#K%=zno|D!vRt-hgxqJjAb&tDT&2BLDCHN_XzL*KTsCjerJ#Q3m6+Wm*j|2 zgU#t}bIH)>Oku=)i zNGhy_wD>%!G&4wdE5I?X@vRt+IM%z9i?UhS54>KafA!} zBM(c))a-UHs|r(%4Gb2^@Pf813+@tgE56K~t2RrCiO6|dv^CGx@uBc0>#=IoX*Mj{ zLWPQ;F(=|x?vV>`i3>7!PMTVxyaf>RrDjoeLq4Xl;h};YP`(9!c?sSWYq)v};Z;{g zg#vS9>ooVKtYbrCL)e10M^0`Ch)RxOkziY~{Mn%n?M%bmLTZ$lX(c6We06A}w}9Qy zTb@mbbDNzn9?Lvziv_r6M*jN2IA;bv&v~He&#oRxQ+kcE;Gs*sA$wFFzwo4Sn)F7p ztYSuGU6xUG*G^G0Q5Ywi4B&ElA#^Uq6Dk3rg(ZdYu&L-|RUfuJvm({ZMo2p7^Sd-) zJSr#vFiKL8oEQ-k>qqLkG-qjVP<5{mz~};7>%P~$bx)DD`!$K)NWRZ&QU$i5SxTPP zFh0j^${m$OOIuXOAEc%IS9n2%Qm2fX1NZ~F$ zWCqPQkOAxYPi|YEVpFpMR`bs>oFy-^9$2Cb7N_iu0=mM`g#oZ~I+_*1MLkkyQMvO? zWeOh`4;P6>qppp%BOp?2grdt@qcr$m?`s5f_xZCl-Tl})$;c|hD=I|g;_DcKIjH@Vm) z;rbEvT2lF7N>AgNX{_88sIO*m1c`leJV%)x_Nsnb4U!$QQtih^r@eNs>QSF7$G(+$ z5&ZttVz?h?rSbsaWNf>$}=cR;%xJwss&WoJoU0PjndaSVyX6 z^sjAh$g`MG@Ghi`t7N}oxd_NcxP2_dK)Ci(`iU*h8NB-%8gI}4=FB#3WLXD^;pqJ$ zn1k~Q+024*7;{udjs#F36?ehHS(4Htn}0{7UeI6jgaC4{W{QH-dI7iZ`+f`#94v?T z8UDxJr*{Rv3Thd&WO zmnT&x6Y_6#G+5WpAjekcCr>Orq=-rNkC1Y6AP3{th+DHHi6YvHRH75XIGU&_4y8n~ zt24946R^xb*?AOX9!X;3^{d`YqbYyv?Wc*I#a_H&Hl|;EKXF#&XJc)WayY+qB>l=` zc56D`HXF%nlb5M~dv1tQ)rfbwC_y8H7O>oweTBgeS zTi*@^PDtUcHaAkY4>L!Y$IBq9=a%)0T>{|(w@ZW<;)=XaQ53~05G>NhpFv1PaJ952 z@%xuz0z~)lG&zS|T#dV08t7gHpX{{j0@roB&Pl|+mUMvSEOh})m@p+p4SRz5AXOvo z>)%IM(aCJcSzo!y<}Y*8*L>^0uVDO*%l}`w>0deJzb^iN4qA#eynIog(Efb7lc!Hz zAFh-3g2p>K(4!+Mr9guBXM;)uW0o(CnJ2(r4qXE#tod$xsh@;nfYs@SE7U?VL=J1M zYs=Iwww4Q1m+_zL!_b;;I9S%E$Ymr2wgk+-KltDLs@d_``E~q~s(=sf2>!sS7|?-N z)=LlJZW4#`YqtY_GwSW-;1hOn&qw}p2n3m%b0rwQz}KK(1fF(qKz`Iyv>zdBbeKe* zH*$p2D>r21b;2JCqVU{->z>p1m zXDr9dfgF^BQ^R)3Z7hoZyKMhVn^(_noCjIwNOI3ic1P}pFfjja^XGho!QKk8|A2@8 zgaLojZ9IsKV@t>mS1qi^#vN1K)XmjPFy8mZ0|j?q;=LKzHE&n{%43}#R&3~H2PhlZ zOJHz`LhL2<^Nb!UY1*ZW#h8jxx{^0OH*H&X5%KJ8WK|P8B;(v4ojOL{zn2W7O6k$( zg6SGgW}zflFxU;AnyklwZ5A2rG)PsHAG1(-HVV-xk(29&!>AHP$Y^CaLd@cA$o zh=rDJpvv|b(|6MepzRllMWYj>$1J*;7F*xe*mr)47dF5tF|jR{0hFV(%gg1oP2HV( z5+`t0;#EkwrXbORot0A~EDFyZSa79@2)npYp~_6xAYC|0>|(tt7Soz%^IQ%J?P8A2 zPT=da`>t0CnG(c>#?Cw#mPC&{2-HcedwKb&LL+Ein#DiQb(+Yh#Vroe=_El3zLS-Y zucMyOF2fG^sJxdYHbCVMyB$(dS;Hw+L8~|}WBP0o@RfjBkCh#IYDJj6+FV;y6*6mD z4)+`;wP<23ztNL^SyCX?!zntXZ^e}#EeKtyRt*R?Mz z`vqSU!xb#Ogvxa3&4#+B)7WjJpHlD~2Jd!VAYwB%3m-|u%oE0IMfs9( z=wKps#7(2~(J)%@Aei;Y6qO=<=+YOUKi8@@v-D}}bko~f8N6t71Gt@Rp+fUQSMr%p zi<;CX5zt8SGBBWDsl38dI8Em`AHs{uR72OJ?=Mfpvyyh1-N>Du;_H#0CU6jdTnkW^ z&H`%ujbG zVNp6r{?34$f@WJ*bjsjCs~8@Ej(C|WC*q>NYa?c{VkE~c*@!OZc2EGj?hB+XY2%TI zQx`AvZ7ng@!Gr>9z3o#XnUi$|A<0K=}EfTNCEg0-<$~|8q&?k&6Wlc37>kh<9|h5H#JFwIl$W<>THQ z5K+n)@(W^K;0V=LodpxTbP4jMn#{RbAHfnMBq&2`ID+HXSSVRGiPdX)w}7O6V^3%N zwQ86b;R0k=!TOK8@RqbSb07w3UrWUWDXrdR3{Z$fX@e@cCl_I}qR{I;ORmBL!-R88 z4P`rj0;J?sjAF?yA}Xn&^hYzXf;Z@+%lu+^`dd%#xbyGz-E7F~gLQ-976O9Izr$wx zji|zM)Uc;skgCTju2j_e^ZM8}#e=4?)Jc`G>B{8fFvGY}zajqUlVH?FyH`pyFL|)C z69MT`36AOcjz`RAWllCOCd!rgX*DRUErqdq06sDF=sGLlh|V+WoL zS(E@OX+z`$B1%w6brw=xQiLOH=Y=2&{4{Q>k-~4 zO!!`R+g2kd!LF=p({QGxFSGEFH>T5_Qd&IS6A}zAC}AN2$t@eRtpud<*+i9xoSLf( z(+5#{KnRuH)u?g*bkM4X>G5>%Ob^p1grz9u2S#aoq-?^s70!uh%X+MXgelHQr<5N< zBI!)sJy=_5jH9XcvaCm|HBNHU)n4<0Q;C2=ulsT~g*w&=`j%p@tg1CW#fFXfPD9G6 zArU|~4p|9e^Maanxn6QrvuobEvW(rBqV)u_HP0%ohL`o)5r|nTg2eNpfBjv}mwLRu zBjN(K?m~wnImUIyTucKu6H5)F#u(eYhpRxSH2qK>iiM80gL}5gnDwz4;{@ycMy$7e zW@^+aP=4%6ajQ3zh7;a)uvVl@+9xaZ`rck;VcG4mk{A^{*-wa*$lGI@*RBs|ow1fA zIns%wOZ-WsXhYJwLrmTc(&f9?3B1v&BO=P1elLmfXC%nAL2oCxW8@b^*}CcwlU`on zN-$6n7^o6-A_5skG#RMQl)fnItf-^1e(3dblFiC6`Ipu}$2;ZzAsQ&G9=Syx$!Yqa zhAvRYH^}{1=>+uU9K4U1L<%3ggVUVOyyS)$3_ z;C^LZ(yIP}esErDUBF1l)hfkimtAVr-#`Cz@VA&nY^;VB9TJ4l4hU z(4Gu0nKUOU`fjaeIEgV-4%)hRL^9_+K(*l$gTV#HlcaMYEr=D%Ke*Oltx~b2OHIKPs)yjf3MP{;(u6lT%_%zG1%~je%^&e_^2v4h=v4ke^v$%(&l<;ZOu{lqYQWdwGsvf=bKA z_-)Tej)Z{=%JyBM>fmHkvl`Q2`ez1%oa_kw@%x-?dT$FR_Ob9qZ=1&C4nXS%islX{ z3-Ojg5abRwYpmc8pw58PW#cPrGJ-RpSD@7(O)-$6)yRH%Dt$|TXY9RLsR`Ql!q^<^JRHCM z-BlWmoGaEP3o<(K`@G$4%@S}6MiiQzq_%SmtqN<6k^s4jj9q1<*wsoxmDgETk>TN# z`ZZN#`j zIUd7XxZqvoB&WZN=~0F-BcB5SBIldEmu8J?Ht6)5CvgvH&jwrC&mA~0Q1H{ZQBe3F zbv&l2cfR3SOW!1_By`w5|GxCC{rHXS?CTl%|0P@FUm_*{jji!tg`%U8vx}MYf7E;Y zA7<14cQ{YG|ExXA_80H@pa1Z0AvNu6|Er+=$J?$}`%?E8Lj43Z(=JkDzz{hlvtytz!vEE(sw z(U59eb!Gb*)W{*g+GPYS)?1N%@v6SgGX1STzZzF$v0*vXMyEuE^C$8UU-yh!a3-1C zfQxHG5>Ly1)D#(xmj3Sr7Sw)Nt{S>zb|WTH)?flWrbo6uW%O7xFIW(<3952}6E?S0 z&lFfC^b(1U;2sNq%Um;o)$rt<%}F#3PX8HRNq-yv({w&7-R&;sN0TGkQ8{Z3C~a1`5{npTxi(0JHL@u|h|t+Xv`E z-Gz_~d2?ng078UJ%Y=aGg42(95p{T%BGZ8i&J4}vBcSJOiuB|@rp-Q4SSDSyTUG!V zV*e?DLR9;ogf&@nG9mrG225zr={$YpfczFFC4ec<59Ss-z2!1|equj9`zuG9(a~ia zya~poS{;!J&vu4GI<596kwy0lSC@*DFR^z^b>xMD;6%HcmGSS^5U<|F^tzz)KP~$p z2CNIpQzNe;9RZE>FZ5DYb1sX*dXI=IKj#*3$z`@g57>Syk1^NBFG6wi&lQ32vAX|` z8aORxLg&mw_%Ow)A&LD#pi7QJzLCf;W=Y4!;s^W;w`Zaa{mQ5m1R_r5ITVGJ7y7avpFL((5x+Cz9x zpUf|GLY35BVADMVy0=+OTI#EIAfzj&mh}wqJN8sl)063pNg3Ow7w(W?DL0EiBr8df zp2)y$sj?BQ-1SdZ7b=jhBs^PKmf|jRMJ9=%@z*-L8HnrqyMjmiceF*MFN%rdUs6ms z|GhJ(U~Fw>;`(*+6#srx{BwYys^##-JNaZ!jll69BBi2JtVt+boV^E*AXWp*=_f)) z^W4Ow*&45-+bCcEr2Zj@MtBGEq7<&h12qLi=cjpdiMuoD+pwM6)BW-77Ey;9wW>J2 zpASq7&8ccCFQh&wGRO_=7ghpbC@u~Q9sBJ)-~zpc=XdOoU(fgt`^ea-;2aC)!{MtY z^-67uQdPNC;xZP?A*k?qdJ*H1SHU|MIHODkpRMMzCeIDxDdT}JM*IXH(TtxN@hS@c zKp|ky)y+PlFsIr@N#HFPduuS0l40)uZ3 zv%B-62JvF-sjvfB&GK)oAPTG5)>gbH?v&k3ek*l;i9ZfJVh(B2CNQ zn_lQW^oT04IaP{&U(Paa2`a*a;lRFH6)S^CI5=Yf2m583NVb9L7NSg`G%4KKIgo8@&Gdsm9`YNAK(ip@LB9w0lMFd942af;j zz!undk^zpsKQ6X_Z(6xf)VCXRQnW*gd8JFA;Iq`BaDoJ3eJRe~9rkz*r#U9(K!L%g zS`Lv`HqOklAd3L-;l)j75_lyt*sqw@m+ql7+wQ^Y6kH=sa=IHDL82rHWiYYPPm`iL zr82>Usf1U=Z8ZSRlZ-C0MZC}pTE%IEGA=&2?SFJi!-{=4EJ%4%m^}+bsN_47 z$zu1By-778#mFM|Z5N zv>E=f?W^j-67p@NKW+qw^sJ^|?x-&u6#S{H@5&SHVNF zUM3~YX-~oC5_gQb&!+$j{YF+6oKnowRdU?UZNP(JEw2KxrNvv**5S%^bjL*L@})>N1u1W~oNvf9bx(j6w{vQI1LcOG$d2s0^yn@O8>v4y%ACrSy1 zx_f-g=NZSPE_l&Tm4Nb2#KLYjjcp78tj!ha@)tZ6_it76C29PQC3}jtSVcd;!Db(( zjfpStwZ&hC3a^#pZ;VfSiqPZ_H)JSQ;0_|MPXls#OwCxb? ztflN5V~@Vy+2N-?->4@}neTJpEnz!K>m)jmLvz@(L%Z448&8Ewjr?`n9gU#s8=gqp zfz{=-fvs|f#9u^8c+YwxS^r+{Kz{)keY}irO!`$|`)(s6JXDK$jlP1$5>KLj-PSE%(Q@;R z(wsMZpo3IJFF1cCB_wd;-I^e_*jy~-?hPnu4@hmi!6{d-pI0wn`9`sBPXn}6G2OBQ zlFJjjua^T%cW6W#VU8E<`Fyh+*d4@Ph=NH?dRzJfZF2{(@u1EApqHg#(WshDSJzfO zYTgu3dF=E$6~ciZ2OiL4KuRZ*6LYY?6 z)U=9O*$b)1K=A3)1#&1Tew;lwf3SjB?L=u{n_lAZL6IzL5UWmybWejeR!yc(vB(>` ziHQu?_79L7MZRc~<|%6|AoXw?LoA6Z1dIwzUt6>SqbPgNOsoi8=p4!*m83~m@Zj_I z-bE9sGGb9QiJ(^b*2d%#@Iq~jQ*LkJXeAxq7Yj;~|DdTC*j4&RN;Jp< zD}W`fA51qFp)(ZC*M46oI`DE|q1hgALBH&b0FGJvhFPn(8W~)5u4Fra^hgxt&l}<6 z7=-L#gh+6p?<+UPB8lh&F&B1=(tN;iIY^fCiAVB+(s76JT`97Nf1LGW5P4HtHn|i# zVj~Qj*jMyWKE(4FZy!O?{99?65#9IT=3R{Qwz$yIBsA!K=Ka^8R@tj;e}w2D&Vxd-3-z`^!5oA1^A0=bu@F-MfE2 z{$5Zwa&H?ne=#F9zU0;ZcRtJiz>fUCYd32bhyP5^?XS2f|194A9`heaQu-_W{|P1S z6c!Xw{jayj$BP)ZA&9$Uy1t29+b#}g0pm$X90Ud=Lu{;h zIwC>~qlt7Y*-I_bSV9vP1}jp`XJ!!ZHdHpD)4tCM2JqCX#EIN!R0Gsqd)6sa*(xgM z7P8Umy*c*wx?>rOP0en?0pev5jNQYC>dm?-ILnK$&L_+ZE7sA9D-tQRm~A4v3sgwfnvS~(ADT|+9GCI( zAk<-69q9(uXA=3kUXiwUEgg0`Hgnr|qcNhr)v!`#$dmPSSk6OjIhN#Rd<(f#tT?Gx z%FVIgD&*i84;gH$@-6um&x1tt*bKRYiJD0Cx{%N)WKYZcBD` zci1MF)21`&r4jlL7vekUG#9ClZBEBk46xe6a4Gdr^F+&gb@@_ zq>dzkLaeFp8gj4^US$4`Dty#46lM%Z+i8{g!j2k$xFoyv|fU zWjJ2RgSTimKR#FNzP0&?)L%N3sEQ7XmM`oSL_nx0Z@4V5Oil;}+B$>-o1IVGR4$39 zYM;OstP?U=?pu;a{nl%V8>|MT&2hSo;)P3{R5CPwcw8!YrG9lU(@LZ5Yya0!O(-zA#xwyUfOeHKpm3 zBb0k{0r9>tM91be6gL`LoO3S2+$*o$~0l@AZJmOkTb{80traRp`#Wy^=U$#gF2(Uar(thic{8i~_w+z+!A6*vT_py}OYfd45< zWHZ}Mv7^5{Tqxs_{%qbUf895ANENqw$rWd zP`f#v`w!E4rkG&3RWXO6*({)&#tTMhND37!P8LMyl2#k1BP@Fy|C!Sljvp7_A7iJ# zE>cM#p_)|)&Y{UJ%0FssBjUhNor0TSc_33Ny{RZzrQ~4|7kN%|tu$4#mUea1uu-re zoKpUod;vvY84Fj#$zwm9)okiFv(yQaT1@bBHz|9JOKf6WHhnuKamk4%nyo5q4$xqf zC1itn^}-v?a|(SxPj6{iWr?9)!wjtKRF&qaS4Yug^u@b!^Fzdq&>Lvhvsnv zx6{8sq!w73So&bgOt zrn~-x>`{e7a803SBD_-cry~AfSTSm&!z;W}&(Ctp2`$odlBXFX+}<}lIFB6Sv|EYu z+&)QA;y{rQ&Yh=l|L|G>$Yz2viJJJJVw(gBK(@vv5X{)>&v||>~6PmlYTB6`Gqb^T) z_6HDE2S5}_q^=-B);w#()$cTJahxJWw32^tB6))?fe8*!)N@&J=elP2Dd)Q46sTU4 zSY`JwUc3T8`QAm}azc4$3dWEJ%c!!KMjE7B3(Yo-&<{dSFs~{mn5VmJq}yYmnnwNv zc!nweP@keEfB!p<;WInlEBV^M75GbMxPPO>|NEu*e_V$D>|Lqp{B76#vsn%*Bq%RP z9Z^YWBPaxT+p?M%Bb4e?5rBoCip(S{#hjU>^e5tvu)$zF7KFivQmh3B*d-VkLA{Ur z%oWeh_1gRU(-ltuYznL^aiNLuNKqgqGdOV?vm*h5D=+J8paeJmMH;&yp$%ae1@}F7 z&bj9>qJb-}%w$U2jSjzv%(VL@;S8c&$ud@>mdAu~t70vlO>upPRRmkNR!MdgSj*tV zh3=}e-qvDJ3;R$SZPKP*V(Qf|w2{LcyLEX(sIXMIIG7#ePWdTR!`gwgx+N5F?(AH34_jP1_3onP}v=0>w%7z4ky^QW?eT_%ctt&hf?k1F zQ=3X=5_^@h;Q6+;^p1~2qkctbj!fypcqhD$y&WA5+VFcv!Vws|Q=SPRzuMA)hqnw8 z`iZ-R{R3h7-Xf1*Hn||4)1PE>>&HR4Dc+b|Y?ajBdhGp|JrDNct7+o-AHWD@JDO5G zx~-d>js04hYg8c)1{QwS)$MXb867?%ROOP%_eY131CTU~el)NR1ln_^^q02SHO^zk znOP+jbzBlmv)0d*hWur24+}Um(`_(3hJDWnF~DS-2&3x~0gT9bBV)(rgRK`M#kHSX z(v;^jlbERGeRPcKfVn!qLgC4oV7q0#8`d>z+nyZ5vG2WretkRo55@(H<4AplE>wEV zltj1>7itxW_=-5WL}$muPtfeV)E}SNN*U#FmYt$BiRR)iU+W*w=^>Ex3#$d}K64@_ zysUXkXc<^F#6m(v4<44LP_np$^-ck&!~BhYgX-5YzCsg?DYO29f5LM@+#&tAQ{)H5 zd-9$T?Q&PYXe#FICB&qV>ulq*VL*>2m@7=NIMhBlj{}wzb_7Owx@x$}=M+38ML_kj ziqRXGMaG4u3voJ)^NdC3;i@LE8YZy2@K;-8T7{5OMXE6elvCM-5RB~e zByW~~B442He-t8xIx{x%4lhUegrrhY4Z4SrEW#07Wb9!U&Zy3Fwp+4GT9mcE!2PW! zmn!c*F8kGOe)~%l!}V{XnE&Iz{tLZit8clWsG2Pbn@!-JweHzWs{W=bN5PbkLy$iyvT*7(K%c%nKhrnQIrweDE zJm#J$eUs1UnybfU`U}D&3jFbZ#0emxZ7M)XG)|W;fLWj#bW*21QO#1=XPt(83MDmn zRH98)ovdih3L&>uX-()?(?yvW*?($}R8ZYiyekhHOfV|N@LN%u8&4ETE0H`yGd_(Sc5ER>gC#v@rlSHDRe#$nMn3!p^?aG|mF2jJm0=BkAxl!7C=uWb7g0?L!4i49j3ii7-r_ z0EKD7@8&u$OLd7I9h5P|L6o^yYuylv^&bd`WBj6z6cxmt*)~}KL4xhwbvZn_x=bKK zGNAI?2lQukAc4G?T4}TILPZW}b&&qH-*8sHrBnnK*CJSbNeJ`(0a`}x`v9-aKMClH zfrUXe+|48?xHHAh(_J0s#e{527+h>#&SRkW0LWsFMVSPx2M9 zZ~{502lHpl@6yQ0W^J)4dI6H6I74Yvdj4#ifp= z+#RA#qZ40L()vN^?;LjFvi9J(BN)nGu@_#zEu0`uZtmdu=|P4 z$0pp9=%O@k523p!zVk#s;_DP3oq_6Ph$pmy#~P)%cie$&m+ED4`9>XVs)0Qri%26;#ni4T`7eiaPO3K_Akj!QIDsq$LLDG5`(s|1(k&C3gkrW~4`VW6hZ$%2 zlomZAVIldv+eGsvB{ZHVt?e27?V@f&deRpD8l0&AC97QE-@K^*$8z%@2&?!DVQq+` zexgsPD@H>Vkulkg76+~m3;iHZT8-7|FNR|KVGO{^;f_)Y$JCmyI+Ps~IO~x#5Y{p0 zKC}6wV8FxIksx(R2_;9+_=UC1dLFX*DtkU(KM=mTSYl)L>ES(aceDTK*8>63WOPJ8 z!&Ad+a%ugJ&wUO~zl(#nbFRtC7y<#FQd?yrHc}CLgIOP^yMinOj{r<#IJ#)N0)GKp zF6rc2@dl}@up@3L`fVhlx2YbHaumBkr<+8Mx@haVifb^C>%SA=7oNF^PG~ogxgA7s zIEc4f+(Gf1r3vVCxrf*K;Ui<|I2B{?UwUeXqj_CmyCZ5Ze!t(9;9jnO!G{Cn=R9JP zBTtB|ewh>#HR;N4?GcFS*3vH5#fL^{0cdXM=-e(OI4-8RpnOzD4ru**(FeNX;D;RZ zd&XghJVI?;c3RA`4LZIrkGvN+S7uc~ zndcP$J4kDHg?)yB0%;XB5x3LtH^Xj-2fD{BO}7W;FD0CRb+CMd0L`GlT;&t8{)M^D zG>_9#VnD1icfX!H`+e9~-v_KKVY*ZT;(IVtfHZloQbxQozevTsOxE|%%P3|3EwnY5 zP*vgde!`do%#z@d(^DwjKGK+m)<`hj0cv|i7g_2u1gL4!aZ@It01K*{O4ImwM3Wcg zc6oeRDT7^dGTvyj`wV5Nt&!Bj{CvURO!H!Mk*IX_40GG8W7uMp2Pwq108?)$W92Wh zX5_K%E2v0E@tMh?|IqD)FR}Fr>b6b%5mhtpl>((7{qXV-(ph9_J1K6<*_*VKhhw~X zu&W3){XcBEhw=BOn!m8z3gllkk@5cGig0ta`p>98V*jsT|4`=9Ff&&B3hhGrPn{W6 zXEzsDIU{=`i+?RO7OPCyqcEZJQOlMvAO>X*bzi$j6k0s9hV<7c(zHFq26OA`TAB~D-HxCZ( zv#p^+i&El(S^>-IL|?%x|Ewp8yMmSnZl?0cm=eq2nBG21@Z>Tr_1oS<$UI#1(K!(% z$-?(oh=w0!G|c-3@E0zXbt0J2{@ivG+X?g}C(Fa6VGpOO*0saa+=FTm{N#yV){jMf z$#tpSH}j5tQMm;Hw7Qt+VHclW#$me#N}J73B^Fp;r_r%yR$jPw&0l*t6WH^FiM}M% zg9{br79Pyt1ZH0PR@JJxP1pAQvl~?J>L;pOgZ0Sd4_E5CeEMT6bGI;Gq+t%&> zvVw8Rn|`EUL07PUTSD;f3J?Dl@qeUJ*52Yj^3=h`Sp zw)5d9R^E`SDi6(JQXGO|6CA$)LK+X9jnR8y0kdbXq=!KnAoO%;%CIOg7pC3)MGiKfjt?4ksU};YqROa1FA{ zDjL749rx$%D1mYhx#2UXvv`;fva9FDsNVADs;J(I=gue&RoyZp@=e+Sf$JHPH(2}e znO^j+8W=RASftzJvM3+9wh$e3@GQlU$|zwu%R))y4wA3kv)`df!_ZEKbyLS=C}ta@ zkpk=DELt3eZT$rPi-APDuv;c_#nuEv6xCKdpL*MhYm#%c92$4XvUOLKOj)0b!a;F} z)f~svTK(m?h%4tSz+IRLe(?9m^)Mg5<#559CeD zArYrsu#RfFf{=jT(5XeNomoNukn=EWVdTjei5LgDUUZnHUn{tPl6`aSfu_}wo88Le zl&4N_xvI={0$rs{8I*pRviKECUJlEVYDLxoKKB7G?r!5ZDJku;Qk?Rk5f9!8Se|cA z^NsvfEQ!VII)c2JFwO&c3K(QK@ahwB^`4?7E zE|3*H0L-Kq<1UM^Xq4#yaFDad(dUoM?1+s&0C6hqM&hL7_~AlFnN>=x3u1sK{?XIu zAV~LB>?vNv1#^w~REw6-R0OUs^hrWyHV6wdz7tWJ(}W4LQo7vXDLR?vGQnvqmb!lq zE4{A(Sq_E@>YGztzSJq7n&3j++Ip-D?K^Ux^VqryIWalU${X(5Sp3AhC55=}oz%j?C z|2{X+%zTCf${}~AELhx_8qvrB=7Wv1VG;6W8Az$?L8aJbhDhz$xRUElTR-jQ8(@es zH!T0}9=vXCWCE)P~HnBZCx>k=E4neR*A-WBYRft zNV*ngN++*Q4I`zvg)bUzi(lC%n>S(giIN$SF8N6)_3I-^Y)vyi(y9c5U^^5o0`#MuR*I%4sx^a z$l{mn!Qqz`$RMk@Fsb1cN27#bxpV!DqUYsI-mrOGRGkZpTMYcdG%7ub*e3bYuKB}< zxh6JF=GqZoV_Q1#=N#S&!D)2p^qed;Bg>?a__1%G(HOMa^$t5h!yt;Hne+(A zjcAVL^yV^pDe~KqQz&xy_-E{FwFbRz?-Y7d$j+{g8JxO+ILV5Hd5$_c*l&zxzj~B8 z^-`ie?`v4t=iqdZ=I0{m^`_FF4$;5cbV}VxDi!RR<`hOq>ph3$AL5lHxv1)?-ZVi) zSQGHt_Rw1of#m7eMuc`~lEuwC(#RL6#85Db;nhT&?2CDES3LXhGxyLFG@FJmt>)LC z59O90d?RB=sEi)o)db$!ACwxcX^U-A=BSR1)mKEBgg|Ma$AAqF3j3vpqm+!0G~lo# z;SFK!+8~No1{EhW%q&K`Gz`M}=`rIl9{c?$Kdg+%_>FwPu_BG-w8ruZ{wMJhwBOS9c!S#24m z9R*bu05WsKibKroBQw)0-He#|v<_B9)N(Mjd6yiPZ&JdVK z?(NA8P)WVSp|Ty|u!fVApyHQiZz}osB)>S^(O@uy4SSQ_p~T$BB=Pf9S06umPbVdf z3-uzsJnD*aJdO8g79deXrh9mqN;h!`FK3hXQg4e)(}1I#BB!(`(*1T1^%lI(^o zETV)PQj`(2ZOINvXMwb5vgb#faJcoz0k~#A1)bC>&hRAUFqFM{>9~F_?06uB*!VoN zwN>s=?R##~M_lCW7i4dN;Ces>y`3U}co{m;4w>ImAQGl>>$aeJ7KO9L_3^eb3Iqo@ z`xjK-N`Z(c^%3(VeDdM(!Yv`K^CSvDxyITwW0z0u~_8eobWu=nzBCQe_?@jA&u^u}$%tW1a{gNZ|_alW_{T|u<9L~B3U zm6v(xy3uNCWr-+NR41p_#KRW@rJo7g_><0zn-7{os&xTP6UX zAk%#lmWuc=6#&Tue#M%&f&H?!2#XTAELihw+>K{=Ie~nnkCUk-sT&k^Ph=>`SXWTn zE-tSai@%p>tJX+1wPm`s{r;NO<7dEc)nkA1`}ZHVwy&mHhzi=dd8~wAgTM#tC~;n5 zev_E^2=!KJEt=o_&b43E2l^At#}$=DvPbr|*%PEk`NfmNM^AG4hAoNpmC_^oSC7Q4 zQvz$F!#QtQ9X0y~qvt890&;d4I-o-8tTLYklNxPhy?tSwE8z}0QCE)_Sz|x|SObIl zKDo-7V%z#ND+^A;CxVN8s*2POnW(E%$*Iy}l^%~4w4cQnizQ6)G*fF*U+2N&JM6o+ z(gC6H3KBwvn!CyGicW`ei$|nGBu;mzaQL0;)d3;dnnf&GH9#hrcFo~p7kH-Zl;OJL^c&;=Y4ug}kHR;=--p9<1#~nWP;Y^1heg^D;`h9G zV{xxxeF$D1il_$Uj465yc_gNo^e4DDWjbgrbnuV1X?HjwEz&OVoDMl95;KG^`K2)T zWU%vhYlXEoNy_vTspqoyTcd^ixi86=(&t>~i7girF84#W57ze<_%m@nrgT)}x;q;J zCiItg*P<&_pGYb$i)zEydZ&-Lyr4##)Gx$D)N~AIj5R)tpIn|?mTWm`7&p4d+y;k- z%GJ6i^gX&K2%hM!pSz_$Na}XAS%XaO9B;+!n4TYtK5S2*D$`(g)>MXVGa?y&M)+kO zcI0Y#CX^f_q~+DkV!1Q(ATZ-@qyogMmcewzK&ggk%8)zG%g>q{nIvtKYZ!&JtE}>> zsLiF30h@nvxT4y^PCMB3qOJ-_Om$nxoK3l>wBIU-WL`|ZrwXu$R^o-%+;Z`^7hC@# zS3%#9C;@d()=)R(mV=hj$G+^}S&kKBU2$wf{MHb@c;=@w-;TiGLPMnCt(W`Lmj zJQjJgY#jg0EpqjkNpW?G)Wb8=t1H0oUGx>~V*Lv)Zozig z#*eTV`*9u)QK@0844c4w#3Q8SUFp#z-sp?(xcXYeJa}}4_AP?^Wt28lff1Kiit-g2 z{zheFMul~H!DYcB13a%pD4(=B|7K_g+Ba|R6GY#Fzyq`wE!0D4s;^Ewx`N8gk8=h9 zQqqRZvBIQ1!AsmI7)ezxm#dKXVVvzH%har}IhDHC*E(BaXZFmA&=rq_4U=1Y;4*}| z3PNg$k^n&noIkcyBm|I0Q=QAweyYY*Jb!AE)Po<$?OnfejsKxW_CUGk85h!2LPUw! z!^d1HQMTw6$p;ORp z^%h#0E41GaLL!uIHTRjuK9PBbXo%|%Tc<#Zx4}`~grOWCruO+ym=y2d2qqiys^0QH zN67~@udE1#N99#v*q3Veg9Vr0X6m`PQc}$C{xGFeA25D3Y#;34wwSjvVUM%xG7>%Q z$bg4_0{`VkO0q>EwP2Dfi<;_$l^PSMjU=kZqx@Vro1HHGY~%vlbd=J%>C@(DvSLg-^>)C zZcD%qWO;ZH<8)clfur9%$Q#a?AyvsQzMyC0go(A|QI(n2Y+|f6S;-)cP}BhRt3g=! zIFCy0`dj@@_ykka78dDbEe1f!$y0q98B<$N77o*7IQ8ZytMFZw)lx*4HFdqYSs zvRgV1m#qQI^hF**4eR+sSf?so#)rUzHQ86i@=Wqk@}+=J&Y?FJa@l$h;t(rOugWUy zK&#>E#p35RoK89{Z#DN>=nj<@GjI0@E?hL|NoSg$+|C{lzuF-D%ji|(eU#ECWaO=c zagLigO!#KJl-Z+T6#g&EPD?t=MeF-H-7%T5U6;lH-aiOmao}v1Fvews!*M$W)LD{f zLE2q&F+VYPJ_j6wPvf45DTxKkVYuHYX+_%bt@S9;+OeBBb_*MQ+?R%d)fi@rBxU~q zw+w)ZH#C3s;*osC(Ej@(Os4;xRQw|o)Bl%^l`=E)iP=*t18JL>h-8>}9H}IV6IyW~ zO%Nra9!t?tlE9QTGm-@rxV7VVi+YXia8QkRtXr}jaYWQceT}Puw$7P)v*pFDuU_^0 zi?7e8^Hw$oi%}u)#g)eM!N%*Q)1}tu(K?5~Yws%oSt0843=ZU*3$}(OulA9&0QxPK zXUw8UPCjex>`IDT7jIlrCbVDWVdQ*v@y(nc&E7aSA?cOM+pm$)36n}*{@o)hpB!1R z5)QqQ%Bc3N@20e5@z}TJ4|g{{L9_W4cM`7rN=L~qc_nw_KRw)-@&|T|Yxlf7r{+BD znBS+Z8-EPK=j==S4JM-`^7aF)(EUiia{y#%XYJq;Rdq{4OQnA60ht zW<~7Z%*$W2KsT>X8vi|X+4YulYbO8TjJ0P|0rN%+#~+|Tcm&fhaK!cjqB1P}U8T5= zrgnfxAl{R8DsX~&rnPPs!f(gBqR(r9{XD1AOa;<*&s*5i1z30V}HY;mV z6)UGFY`l?ZGZNlxdM;yeb*XVqx;o0{yk$SfL!#JQjtn`~-C{QRG%Bb{(OIIajC~$| z<2Pni?7jH+qK1^z2(gauugY_mtADJGYnmO|Hj@lzmaq+w6-qPY5eO!_`3l)vM7_?k zvPzGV>+2cj;Dx&rMT;fwnN2ZOtR(QV&LnH19yM?HbB5(+MFyf=I!H~N#8!W2W1JQ1 zT0aajW%4m&TD)M|UetT3C{g8Cl+$%^VMslY3tq=Or8-cgc-S97+5|~RL4n9oSHIgJPs>IM6=DAq7gF+U__UZ#F562uja0h z=KUnbADtARnvj$|NSrmxGMpK%R<$*uS?u&Oy941V?oT5MKpnJJV%6{LVpv>D2SNTe zPr49EM(cZt%={>H{?nsa{>=~TXbbJ4MV%8$fY&J4d z#3e7$#?*oSbqnf;1pI37!AU*iJJ_6D)tp4slk@u}R|)W%^Xx;f#<|E%k0675y>iO7 zZtp?BiY&S?)#p_L6Q z(lrxU{Je$d4##6I6)1+rRh^A&^Cr~A;#<@$-Dz?gyrw2122HqZ5rbp9G107q#H54u zrFg#&Wv_(P4a_una&O3Yr761wCidaW9|$qb_e*;AC8c}2QoKHV4|F!~qzxx!%?6r? zGpKbHoAAPj!%zL&=ELbQtI?33R*78|B&@$Jc(8S0{F-inTpMEQVMapD0 zEx;l83P9Hiwz)rOR@8Eyj(iiSuMR(A8MG?)CC1_bA;T)uKH0d3Qz`lA8vK-GYVWT4wth2X5}rE@`G_?l`Fc5aBnK}J~CD?<+d!m2l|>Wf7fM>KS*7A?{U-;rmRHfk$t5-!ystCpyL zTp^-o{Jk}-#byO%6;0tjaXQ=wivP-X_JJepR^^Q?#1_CE>t5p}yWf3&5yC&T_V+V=@arEt zBTq$wCu|pijj|g)2>;YxiZcJ)NQa$^z`!DhO4S z>gJ^+tNJb`_ecsiwekGfWO%IxPQdj&Z@1xW_B{rYwC~Kln-m1gv)|4QupiQ1Ro2>9 zIP+TM&DX=!u1Ck**15MiZYFo)9f{|Pk=NBaPoaI6SHJ;KE~ky}8)<2cE3M;Fotmg= zfj99^{7GfoxZagVFf9g7{Kq8t>26Rqd5a+y_YL)kVtm^m^|tq+fygZIq)|#6#4x;Jl-`tW(@IMD!;q@`c>Wm0m@jUGNu&?9N72vN{Q? zf8z_BMe%NTf$0$!F|JsQ&BFJ$n2?1=2!T-pQJ7qdYldenms0FE89#ztE}YK^!`x`N zk7f@cU`(7hkk65A%$pzXC;1S)Lku$8-9ZON!3OBk=6RxK7Pw0H_H2IBeWy!iYq&U{ z2=Cm%h}YQ=z2s$Y`kLH*_PEuKi6j1!-(|Jt|8%99%_?Qi+Qg7`BIQARCVr-%W=wMA z!GnwB_A#%28nz)H)J(C7C=4$|dblv!cg!UcNgZdBV}m~m3R!s3H4P0to=U5X#!N?6(pO-V|j>uwQ+d+>DZC4Ic-&K2J^6P_?Z z-YU9_B}aRCsjU4%#5;3xwAWGAJCz`YKy_d+Y9U|UpcAk%yiq1{ayap>TynZPDhgWB z`qeX#z7J=})ute-d=qla?d_S&62})PB0&sFGon5ejh0$D&Q^Lsp-d_`4#c`v39v=G zEy4`FL*sFme>JAEr@P#kg*$8wE!R@7l^jyJiEDe?H_lzdOf=2eLq~uu+$ILfZueYH z$x;QL4P>!^JDVC@*D;4cJaR9sprpFwyS>9$SlxahE@l}s;BcYAZOvV!WH7D*9Wje; zsQiY!MIt~_Q8CXs!2W8@$)DkUGS)trBJ&6DiW5>j%BAnJelNw4AauVv5rwdU-DQ~$ zcFUy9fyx_qZ#-pxg-xBLgPNxOGND@}y}bK?W@P4~@yE9#?&HzffwlpKz#!KN-(MLQ zYS&j&6wj)4sR?7ecBTi+5#Zry6zvFx3@%Z_UFFSyIQTLb@i#Y$gIA)q7_#c$9ut94 zO#Qszy*9ODEt@2262b;0kC;GGN^YFveTAYVd6FVa%e3{A-K?pV8DqljKhI&KJLG_( zv%sQneOLj8N{@VH!_pKxom4>*KCdYD)7{3@IeJ8tgt6>fm}gTv=$`WZey%Fx_M0c3 z_NoLfUPH0UR6+QYV0Y(s6TN(++^}?`+@TXU=0|~5yg+Wp2}f8o#gh@&cnTWxl#1mB zp{*dd+waL*S4Gz!71d8(%r`@9kfizjV-jZ@I_9Baap1mnVGkq;U@GC;TNZPs#x+yNM;DI$( zz6{%?H0i|Ul~$wF>pzAB#mPpTtNtus++`m(VYxyn&)kB;h|)cJN3;w1D^_?IU1zs5 zr5nPcaPR!U1{Nw^j$?#UiXym{_zCt1l{-~ zHO)xIun}Q68^W1)MK%7WJ^_{*T_r+@Z>jw*kXlBM^bAleyDz9J_U{z6k>89Ngbm zrSpE=?7A)-f2In3je3{iM{s{QmMVBH8*lD$Jm?v=L>wxCBG~*OuWYVqO9AnqxcXdSxgxZz`J~ZVICh++Zk)jd+Y%q|>lU zt74s0%Q~Q$cB--CQfB}wv7hhW9+tqh#Po$#X8>8W501(^xcSZ4@)7s*!5u$->txx> zdfJcK`f=6+B2rlhOjDl-n1A~|e!|18V)x=s739ld(q{oME~b93JeyWI@jgZ`*VnGC z&_d=O$&~r}`-FYViU9X-07!g5UC26$0r@tg>Pf}@fC42Pcsv93@55DCz2DNhe-G6$ z^vX>)i39Q|DSM1$a{6TQLB@6oCeQrA{dYrU5!@+tdr!4yV@=&(t>315y5#UGckA|Y z?13aN)tp#Yn{>H?YVm|L;(mOSm`x=;9wX*+B*{;*{MkrDr!<>5rcWNnq}tLQG4s0c z6J0;7U3%zb8bK3bz8ILBn{g#j23ivV({VW;V!?zFb-=(7h5#klTF;T9a@tr)80ffC zMo{C&jkN9=%95BB^Ju9%Wa%oIFvx)T1HlWFO4|_aipat&HJi-StYhI-{e6%u;@rJM zrdCUMWw8NWH_jp~yfT%p9Y$stkVK+ZTiS$?a;%0J-!$`abs6d)Rup!x|r8T328LlA1jup2Qd^48rI>ocQ`IsI6Q$ z+?n85jd@T>ZNz!4rg-*+ryV7MAjl7_p0<2~k$Oh<$0U{jHXoEMe1gIIy z-ydYu9T=gmWQ)2-rtb`X8&9=gj{3PbdSWPe0XZ}eRq2@PKfSFWv!&G)=2xKc=G7?z z)hvkir~gSOSoTKoMw;m4NjUUOzs~e`P9GJ~=f?+1WS8aAD}W*>3`!jD-Gg}r z@oQB4Oe$Z!ss63FP3G}yRWa2I!n~qXn{UTldCC-}Td%tdnrRaxxi`FWOFZ`mGE3Nh ziUzjoL<%yd@`Rc)UX5olT7GnXfziYWBirxK$XUHRp*C=dczAdH=>0NWRvt|!bdF8y zBH+xXv&KQ;{)CGek-Bq17XPz@?l;ep>C^0>t2B@^mBYdC$<(Z z_8wLuPQ0yEFO-d&o(MfiGDU9)ZSL;=8|0P}WaS0fd3qD9Wk1Rj3mto`ZH3JHd7vHj`-;XVO?EE!j3CQ)i2$DVWq+6L0SrV@91kU z13Img*7UXEa_O;ujQG*OzCO;+yDhY4r(J-C9)_2T!6>3qSGoqIWoPIIE|ww8N-tnO z-X|N?S)=xbfz~neUH@7wg?Kev;O1$1{DVXKQMM(wg4e91nb&~I4{j~&srPfVTArw@@99oeRL zaI^yk5v=3eE!0csvO<0E9)I9{leqxW{Vx zf^~N!twXt>@4d2heI3BMf%+v|176<@->JJoV#Ia$C^<&5RY=F9TMTv?LAd>W9&|XP z`p%^m2oLJ=8-Y1D0EMiwWzR}Wpay`G8mgtTQz^L5=SGm)&632HYEA)az_PzND5p9k zQ<0P2uU^9%m_A6U-lzV}3cjuszANnInYANKL4&)ss{I1UnkTNMYS~zG7pG(^2ye^_ zSI|yEJROvTr%JIvoeRA(-JNT_MU`5^hA!s-8va4z+bE%){Sf@r!)X1bZ$RZ5tXxga zhRLaIaFZjXnwpoJqExK%z^dP^r@5!~xmTG84I#exiK+^ueTY^R3lX=5*;!+G2O4`jzQ(ET<-erOQFPtN12E8Gv7d-1YT#xAa1!SAz;EEJ&`VtcML|?xezrxQg`aM`%J=pQ9z!J! zs5RXmbG$u&FqM1HxqJTDPDu&dhWcv;H&tL?9HwQ3qer<2kLhXC#|xJatyNXJtJuqQd|(|EymlKY?9kfB znqD}sS$Nu)-X@$-rw9uGNB5#D=W8cq%Wl=m+66gVBhh)r*9scZYZATDsoQ=rqs#ey zz=0fU2due5Wz7r-)s-bHY66ZfBqe#a$=0m6wvP4T-d&h!0{sJ}ftve2E4_wA9UuLv zrg$aQulk)BmTh#_NyUk;(1^xnhX#Uj{Mvz0k ztKs#HuXSNpvBbSJ1OSvvDQ7qdWV<1>Fn1Qf-!k4B1KHg=Po{D=r5YkGgIJaQT5$}+ z@I<(-lFM`>%ZYZA4t&!ZkgsF3yJon$W(BbYoY9+%^Zf1Ckb8mtaTyEK()d#cx+18{ zff0l7E+==UFAZIM(tcC}NGkuOVxO`ke%!fObvsIa02|1fc4`XW5#k^1A@83(qSiE< zP-_oHEe4D(uZVYcOKoE-^l>x=ERi}kuJIMZ#k$M$3gk83Cxwr*b{!rD)AZnBX7#tq z;V)#=(9cXM%<;jS$pI-A+gu7t-~#ZryhmXo;E&x?e&`6vId>%%X9Ymtqt$+*ByMJx z0g!L+VLZIh@AW|ydO;QHg3CA@0NE0K$^GQ=hCLy^yXj|7^P|Xd>8w>D;C1T?a%_m3 zvasQ8N0C-fQyzPM%(m%ps@d8*vNt1qE>^@fYJg`+SBNS#Xn;TP<{P~5TkgmWkHe6E zAM#d7=$iuP4$m(Dq#k6BoJ4~H*EU>8&S(YfQWY)5@d89(F+DA)aw<)k>{7sE&aVI% zjdnQygG!F5TB7zbw0Yq-y*NdK9klfYrJM6R^ml>35q|EUoCe?uLFDy~U`GNI-CvR(SEQ-uigA^2*HbTgb56v2;<=I&3VH<0v`f_OaY zBMb2zNI;smvr5^ezmNE6Dib^G?&GEf!Xa)D3z8`ePVZYzIvnQSurx2MK2+`<8E47e ziD_acB|Xf8wl#hA?vm>(RX5w}B=z9-BY84A6^=;^)=T6>GgJxb=pOqhEBPX0`p(*Z zDbgkjUMwZ3l0unwGNfZhPbdoMn%*E(J|B{o81>qo1I5ht~I** zW$W{Av_j0%J({<#2Q~1OA^Gng*wx>o_#~DowjlWyNA~!*hURM|i%(c-HLRC~MLW&(%Rufg$LB_LzJKN1F zCs(V?qWre(8P;P*sIm=R^=2%%cf^8_wl{BOW%9guLYUz2{vxODtBZo={YZd8A9>E~ zrB;+&n`!Kan(gnV3hPGwpo&z>U^~k@xkUEpCbi=1m^f9>PSkR}0`A%(FjD6Q#}JL? zc4c9vEX9H3bvq~psii-D&bi2I#;oe0tuy$&{TG7!t@$~v1|JVkSVe``U8UYYKO$fF z{PK0!-L=&>T(zTP!l9fC2GPtdNWxVbj=YzH?~9NughEfG`}O-0Lldo>QZ0rELdyyJFb1ZfUyy#s z;2o3Fn3%FEq}p9Gcd@K?I^95vYAL3}b!QwAAEw?E!btmNnF-NLC(pPWt!|R|EW`q<(_6ULiH)57C$+bEw+Nq#| z3;1WOPmsU1l(}!TEQMdGUT)}rx1mY?+b!jV8&n=Z=0lMr4rR#DmYvpsVCQ~znFjkA z+1rOJ$NH6j@;C|o92>%#v60bf`EI;BocD!#3gDUPYJA;$TCxW+ug?)i5l7L>P&X0} z?WBfjq@LQzgSo@G{O-{=dj=!n)JTMy1;w7MK@kYKQNmOS-`LP!S3aV zAzKJFPUR;exa(p3GZTlbU21HXZ7L>qnEUrM%5Q~4dRnZ*QD!RyPm)V!V+S&B!`E$k z`z`%d^9gB`c+uJ7p&C_5qUx1SDlm5mA-kj2I$>ZJ>W-6e@3z?&o^kiB3+vhyWV$GX zmNIp#E!1sde}uHP+Db7fhkEXH#K8CXUM7R zUYEn03Pz_f`P)d>Y4D}6)>zjZZ9?n!o<~C2Q5h z$%y5)Gqqgg4b-XO$)BgQDJV;h$b;NovsETYBHZ(BKlX5Hzk8IM07rADT}K!_eAm9{FWgn_xB$OC<#r>P(lvYzoLdzAAx#v9T=S8`Wwxh#HkTPI2N#;vCkDFU0Hi6}vRk z4ujhsideUP0F!QM;totLdscb{cVVS7YCe*cYuVeP&M%hBZ^dV7@Zb;X0`MvvOTf3t ziBG@@vQ%U6>u{iv5JH!VGy4XDri!mUzha)`j-xo zrT~TkUv`=6-?Dnj{*O8&XJ%^jg%0fGVEfkxC08>i&wr^7*&ga}ZW0A`FCK87`xgpM-sSns)|Nkz=FmIuPfaXwh!!ooOf#l%9`)eT?e}$4wM^Ld}bEJ<}I)X>r{H%^qWn z&6`SDNv_xvVWerPx2#J;c+4r4ax=|rPdMw1?F_aRO;Bj=HtDZDsFCrs7|3QV zawcIuzwAXM;P15CdPH*7bzV2{eNNh^x= zjj?C|i_kic+P@5&Xi`1q9C1m?9p`5l)gQ7<5h;_YF7Znrc%(qJ%owioqcPmot-qty z(vS!J92`_se6(VyZoYXVi?tsXoB@2X= z^!BX|l~qg(N5kTCcOqz~-T}vgR+CB-Yp^X8TK3Q(zTnn>-8>_*yQKNpv8I7KD{H4; zptYa8!(FQ*(Mpyy+~miks1l6l%N#EnVVOtBqf$n6WOB+6Y(z?VrJzIpoD3pkbG$;= zC}sAGm`B+Y+~uS4HP)Jy;~O*G6Lbb-ZnN2v zKXsB1I!8qda+NDlSQMS*1i_xC+Cp`pwG>d;QLv7vp}K<)WW*wl#Qck00>Y9@USTAM zC?Umr!ULkj>fMY)(S8IS!OoM})zD=x#eHo>20?6yxOI zHY)M{kBXsbWn}N+YGkMAWTtB7?85Xft@uX~a+9@GzTnqJXD%>sl}+t|l^idELc|i} zLa4XLTm*r65bRqIa2QIZ{)6P(i<-vI*S zR{~$vW_@JUo^Mmf65`3MHTOw5u@o&IUyEWZ|;LsUTY+3$`IB}YBScYxRIq? zGc^U2$~kaTBuOg7Wh52Ym*`D?Dh&~K39RwAS0}Loj9&ogT&WWM%sM^7QI0=lb~far zb*cB>xW+g1>a@*j&%U+Aw{^B0sjfhzgT#J(e{&rF(N6?tH4DChb3YgWVP(ZUzaEec zLu*|RhRCKFCIM#tsbB#@8fb4dvz7OUXXbkp%roJyN0~p$>>^|e^&A9j8v&bZsUqs= z(e1ui!@Uy20<;Jsv%ok%oIIigDfv0S<#}JP2YzSZ_odet-+#M^^K&U4#ItfS9l*mr zmo2Wg44*66lO~h-z)hIpA3<+|{$vIxwQLp#(hdFIhSC-X%9@nU#7$Ck7g~qJHL3o- z267nl2OR=OX&T092`hPQX&K@coFpHFXs>{%b=wU~k`;W)7JJtK&fY{2;b=x~%s+9L{ zZ4BT4s7lIaE=E>1DrPn|W={Xf!u-pqOgjA%N8{sDV2vmvWWoyPh=Hsp;>D{sVSL20 zfq-Mjih^Gx;7F#xu}aWZy}?~Mfc6~uip-L zShxpe4>;`k;_=?-xh88}3OSNl@~r2a=}W_Mn`)1%Yb*NQh9B`Z7*D#m&`a>#r-+uP z;m!dj_B-zebNy%gLcMkELWc2jD+;GH`*7C%K?j{V{-~NRGQFN^#o|V3Nn0mCFS@mu z9G{#wd`&&MRXa)0T*pZW#ydFRmf^k`4!oo0gahmGQMaX%7h7NBI)re!QiNP_zQuZ8 zLxtOH#i0#`SJ*RwGY_G{1}S3qk%1Un*cw^Rh;G4JjEeq3ve7&6TEDhQA>P#`C#!&m zf}fJy*CkSc3HKgPV^yMv{d3 zFp+}~5^J=gxd-fZu=$FnFfA)gp3?c676|Ok>VZl1>Y<|I*VYO@SzhzS@t#&_!be-b zs^1I4TCuMdZ8`ITj=tRbBH6_kkD0{pafr>UCNMg#pmp>Z#lNq{D6QlyMNuUjehmRZ z$i*1uN4{gRIYNcYT#YLK}n|)!(0%MJ!_^-V?tn%f*TU%kf*{1VyevWpEq+F?bfpTsYv;Fh)>B8ZBNruJ!@s zjao=RsRPB~z6Yko;?yUVVr7aYQG(AavWb16$Mt}aY3D+{-b{696Tyh**^GQoJCS{I zcuabWk+}p-B2bLN6&%S*vO<<9gT~Sho+xP{zLYOVoFs?Ro+G`FhddS1@9rJB&zfk1 zn3zvxZVpS*Q44p(bL?diW3E)fFndlyo^(=_A*0-t_T{u?7Iza;hoVj2N=+Y9w{(Cn zmN#J48q)mBX)BeArD~JLIcc1m@J9RS|6;N8FMK9g^Allu;&EEhfF9G~ODM7(gEK3> zP&?XH*F!-=aD(Vm$whlfVE|+9|8Gy zV|#f_&LdN}jfzB#ntcpy_OdGjNug1pW?>6z{ZGSyh0^jraE~3zB;_8waAIQ)^k{+m z`f^|e_ls9&Xfy0s097A!>spssZ@R?X=ZB9*f$BG?VDg~8hbJ&I_55q!OAp<}+{(IB zXSgCAx)L*yU#3*+RUg*H$+xdh50q zj%-9EC>5bV)efsuI&?{p53~%Vokb-?AU>q%-})*zm|4%rkUx-!bZ}~!jH!~y0n|%S z5Orepkk1{I`;eaWlG2mMny&E7@AH!q(iH;Om8e66>s&gSRbyI*XTSaO76xEazUrjg z2a6gbV!kf2Q~h}{nhGT)f}~?&)XA;2!Bps=(?i*S(GlGp;<4Xfzhw6>&X|3#Ere7W zlo;Z~OX`9{G`5r{P+D!-g3)cDnZ}a+)CgmNSRY~YF*AX}w9y?XkDbJ7bOhJ1^$9Nw zMaQl3Ff@TbgOm9*zzC~qU~r@K;=32%)w;ljh>Iil4V~kw|Fb;xAU^QxaA=F}GPEIa zW8IfTmyhEQ)Y6GE?d)(Sc>{z4hRgRk`cNS+Ny$~jg%8#m(tBOF6GpS4FOV4$Na)S0 zHdzE~;odzMHSge3mH-*Ns*}S5?s!sNLH9J>z6w#NeE2Af2i~ zGY4|VHit8hHD(E+UZQOFd;gB)Iw|ju|Ajaf`fpJxr2j{A{{Lw3Uk;*_otu@5nURT$ zm7Cd@fZ6>Q9Zr@~`EnRX4J_D<1X}`-9SxF@uz{7dM1{d%Y0N5toVR~xHZ?fTqgrtP zq4xvf^O&U(n+%pf#CwDDLz!Gk4rRnfQ1{GOT6k~SdVQL@$^XKbFhsa@j2IM#Gj=e@ z6f+~Bx?_wxRKiO$)XGeysutg23N#8|$;l!&=UGQ#Xvs$*;sJxWOLHJY|0y~R0effA zyKoiXs0E^Az80otl%d60ELWMWs`?N_Uil3ysS}>qGd8ttaFSvY+DM9~p;m-Qg|Rw| zzCx`uP5w;xNSIki@rww>E7v4ZH`m_LT)kegtzs1=;_IZWLe99lV56|QZj0HFxxh#s z*g$Xm`aZfb+7>pz-%*|!EI)4e4^g1q)!XfR#XLh zx)@CG8EzO!n>6SLBxTiYK-c@?TbOtuyK_-zmMa?7cbP4UH>rzUxbCYzZ^*^)Y`CX<0&RG!53(;~Xqp^s5wn&8+D@!^F`S~jZ#=>}G{p$zqI%Igmv2Sfp; zd;_!8w4{~yxcI;zdJdmAin!QB(w-Q5XZ+@W}J z*HS3KJ-AbxLV*Is-3i6rT?$27q)?!xlb-jy-^_2mnR8~XS&NnX$({W1WO46j@9Vm@ ze49n$JH_(Ca(fIz?gn0GfAl~Fs~I5r0}qi1ZXg^FkTTFd8o?EW!)oe^99Zkj@Xllj zjo|>r_&ZAbDK5b+q{c?`0syt8v|S=)I71nGgdBT(DCokFT^7y|g}}7PwAIci6_R&0 zOk<+9WLbXn>s}daja9jgi3&SC{S`2dX}?>~Ds#ab;&85B^QsY;4}&{<L)d`*Iv*6)aLM+ENteE^&43pUU`OpyX%|6~L40qCz z^B5zle1u&3bKSK5wrdW!`iU^=`_Xf9Q9RcwyJb@Sa>PMwZRaS}K`hj|UD+%&F5GhV z4E&V69`PM3@OL-CbTpkGl60T)M+?ZkJO`5;#O-}ylGd}l(6WcrZkDACweD8rGJ_DpRKGinwr@w%_Kv6*yU#HhbI z9FYnwt05gej*sR86RuRk{POJ$$pC3g?0jK0XfV5|7%8Q9@z&+Ldi z?X(jVtB6q$_URWR>SlOOG$(yne&If?z0Uh+e>YxhfAVJg z<|}MNrs>VNmlC(vqu*x6zdn);leX`AjB{S=U+5+H6y)DbqL*eG8|!W8Nu(5cDveb& zKIbo~xz5%8lB6>*-m!5PIejcU^h&^RhS5R0x@7kvZg70=GQtuSWmnzm4qOMO{ABG= z9YuJ0sXUU>^QxjGfg`r-<`BZpls*?lxeyT?E*m`f9dTLKrz+tak$(XJcUH<$4vQLP zunwj_em{kw>uSQo@1cgH^tl%TU&H2pvN>sTc>XTD#VeQOSU&9AURWbGL)Zd52D3h6 z$Ov$0B%WU0%56drtJKGzF<+9he218;RGx}TAZ+_^bqqG(rW?7)*V_vzZvu9S;vkTf zdw0B<^12~?{9?7ip~5m}znFKVh#<;dXO;eInWP2{VOBvq+q54=#o?jFB4w2``giFy zMsH@5B;lkZ%9pj8!89+8_;!}y&n_-K3<_=Lr>`Aq55RY6@bN^36*wbNPKxgyDKC_Q zbeq1Mzx*y7zQ(Vu-sfas*agW>Z@H3R*XMsJsq2%SRK}uM%etnu$tos;M(9&8JCyVl zy%Z@Wbiu4X-^7Rn#c0%T;hB{(Qw~h-*S$9v6V;{(cvakC&Z)q?AWAoBU|xDS2oM`6P%}2qjwU zglt3)y=dQufWK7NhvMDj)K}J9vAv%)N!~_Us1C0eEV20#MeVyE(4?ME=)6QPVF;i9 z{OvWq!WT^KMX;ZpptV4K=5S$I1Lnv4{x2NZZdKQkf(lhV)uxs5pR1?#DOrVT-V^Br zW4-lXe-6kS{KiXFEzdy1cvZ}mf+b*<43Fe~ZKo;NzLz+aQU z9hZ<}es?JRM-_l|43N>o9ZlCiIvVkRwM%{Ya6>sOADfr9{|{nXf$sPpTa+wdCXX^i zWTAs_gCRU6C0HEQc*Ux0jQSFdFP3wfiaq(@LEX=I%N;pVso6%=EUurpq5b8D=PC!h zv0P>o=RL2#O5SbEOKyk0e!_f#;E#O+d@DB#YT%5xrzo*ifb7`qT#>qr zMF+)hZxg1af#T5mMilKzt68pgR?vNbmE1^V~ zG}#1t%r ziUzZ3I{2aTaYAK)Rd1rkmv&7|@wEM05k;TJDh39n5>f=@MER*U*EO=_YRqeDDI3S5DDW*v(_rQ@G4yhDsGGs_c)r6-?-O zzj!obr39pdi`i40+qSqYO4;WcF8A;Wwt333CYTwLp+QMLdng2#hWM~{UFiNOblz%d z;;(LGK`g~cp>Y56_>ca_SKYvQEFUe022iKTcR-FQhZ2NYz0lAtg2q&kW(^`D>F`>zchhfDYWpbuVBu-OZj z?xVHq;_oaXq6J4p7d)oCnwIpo=X<xD}Au1s5PpI06PryJZ%;dH~o z^`rw_LAh>8bG^V(tUh=heEoDD?GIQDBlA(1ffiRBjeux99p06nW>4_R+gsie zFAvI;T}D_1jgnS7n&w()wE@~S$`zjb2a?4>i-l1e=8l7qDw*{yz3(yxU!Ne;-NYt( z__0*K3e(z98p?9E-jJyHNSei&lxSwbXj0x?Jm&>m<4dPDtYJTNT-PGXJOfX5Q(u7&oZ}lg*(z9N$2Ey~)RHZJ?4y#M2vE2JUeGFhQm+FuerFq0 zXrHqOFR^N13Y8J8%j>S}DHIg1eCzPB&Yw!$6UkZNW<0mMoj$_eH@dzJj0;LoTZi36 zx;^=V;toHZuwU-!T|sa}X$x)nO=*~Idov{j1EQzIx7&~7=46eoLmuMbL7R3ILD?pnrbPZ(cg)feIVXRG6K`z< zw>=@_DDgHmedfGg;H6_t;3@4SekaPO&B0$}wplI%KKjm9I8w9c?+GcDMuyM zWMcvLqk#BPUG)kX3xPv~*SNKJ=<~Mm2Z!3j@NS{<#I4Z#zq*Ah!qAl+;Rl}Y|0fmy z=fSRQ=c8cf;q#wE{a@tpx2&b728Zi-7i057icn<%pcEbm*$#nN0T?I2@eW85M%AW~ z%8TRXw|~K*U-*mIAn7SIDk{<&bFftFVUfBnA^gea;ZvMJ|T=##L z9rj&h=mi(5!wZYtS92Ugvm42SbQ~%lsUp>hXz-3bvnQ)k99jlBy+gedpRLl(G&|)a z6;;4=2kmwbWS7^^Pb@!RDCD@3))EX(oPi`uI%Fps3!5jd=)w-_oG~q|0x!Nn`VG|Q z3G{$)yk5X*LTvv0y$ol8LHm?Oze^fLP^7_oDp`Z-;BfxZ2$@}a<4hUk_xkyKVOyEj zqE_DeTwmz!CsXHl_AuR!jW5u<5)K1a%Lbb9?HByJ7m_mj)2l*@S*}k7=#x}OCJBVw zVR+~jOjpQq@15i}joliV-OBsUB;&53u11PfLc=Nh?MHyv&s49Bo-eA!Fu%K$TWrnI z9p2@Aji&Xua%RJ{WTfxHAKPx)sYvG;9s9k5=QV3DU#f1`2Eklj?n^`Nqp){@xMgd~ z4BFO*_UgYepiyk8<00nRVp$b@1dN_ufDhH*wG$o(#o6@TE49mKHBYg4mX0J8Z^`_< z+!|n1$|wGBc0|XU<6XklH0eXBpVA{1b_f8@GuV=UiD4LRMg7=h@dNVM20JOJ@84K1 z{S0MOf3b3Be^KRn{j{MXc)9-Ea%PI3wch}(f&Q#q4STfmMspWRtX+!K7S$V1_M{=l zgYGGUg)AU}QiMf&MmYWXlH*tRj~mfr0BmcW`{5GtbJ%T(9Ju<~3H1#k!FL#_M&*EI z)?$Q=+7RL_@(Tr~oDq!Tsvz3A%Vsi(CDTC<*Tis2n-2g=Xtq8k?ND@kZGdXZ>^7a(0 zF#;%02K_{u8fUyErW?h3jWjzWj*hbZSd?X26iu-`;XRbn7rjlB7xpbjC>#=}>@>xYyi z5CgG3X{5m^G(N&g=AZFc?>8Dei}m9&vEcC*#_yr4TLyG>xeWasYd5XCKj248I^^l; zmb#COW*C3)oNQ_*NoapfeQ0bW(T3ozDJO0(glJxSg2#u$^g81c;W}4!jV_VqmOW1< zrBlc6e0lpiD2*kqSSdQ)xU;V8f*ve>u3C4HPzczUuLJumiiZ-w7>w_Ob8DC>%% zY|i`j;AjVUW)t807X4g%@IiGZ`#2qU#s=STm)$CtKSma2xgnOH=)Tvh_;qrN6mrM* zfrhpm)@xNo0$8vjmx>h$21{4zIG@5h6XOgrF|s4K$gF+>O00(E?#AN zEQx-9SG9^l08L8}_`n^tk(HWTC=TK+fp@(!-&pQqKOr^OjnBe~^kLFXq$GSF7NB#> zK-s*&(l95heuoe3g*a!MnO`R!oW%EN+4PQx&Hlg@r%ZFIHDN(7@0#3XKv_Pk*2PoP z`D*^f@{Mw{1S+b>mJD+T;AS^J4EX^Yuxmnu3z*m|4ilZ=pD3)sh?3pjG`3YeIW~Gp4PGJ>Uw>9Xdl-RYXQ{m&Y zwG(<2$1RO(5{g&Hr}|A~Gu1+34=`C(VKD+d$cZFK99#!TOc?Qaz*AXz3_kRn;i8j3QA15<=ISOQ2#?MxFwF3llk1r;;ygF$D<6xY7UF zu+^n2wMf;pP?)*KF1y2f3d4~c>Y;0lKBiQV@BCwAz)D_P?|zxDRx(v+}dE^6>C-_p`J0_4+IR`>)~s;nDu= zEBw8$C?qT5mcjTvQ>I?@!PfU};BMU7mXTw3R>}B|73(Dnq1Uht8ixm4d*$mMl zzWg80rbc?pi_oQhAPx2ISmIA>5=1mfp+E3s@jseRiJslxUXL3-!}SnO7I5RV!D#hf znY7Y+!CCTLrB}_WEFomk2|cC~k=?hHp1t{8Rk~uLly?0?YtOhp;_0ABdS)@_>lz;y zR_nyuoP6+fR?tCnB8?=;id15=zRj0v@b}l%j;=MOyj^QF*$ocmCu;j+GJ&e5n9Voc z4FJSpx@H+c;(K|LPwJ`2$g1Akg>&7P8={X2j&`^xnQUn0VLqDx^3FAb+`{2~sYvRv z3&i0Ta*vc$wZnkh>=t(-XO|@iP=L^B0+7pemR;nGjLBKcTJy*kN5Fq_MdJlAcyKpA z0x2RaD{NsX3p%Udmeb7O8^1k>IM53$d^iDg|3*{hYL%c{7unvmKHLdT9-oa|(XqqN zZDRU8H?;dEm#ymOu4VZv=@j-C*rzB5o}$sO!?r@*BKxKWwB|gQ)1Jt&Yx-uTuSTh9 zq6Bc2F_)pTB#5G<=6l1#US>NYqJ{zHvGt#jQv|~A=t8f45Cz*;zXeH&xW(SpymBd; zcx8pzr|)t(HrQ_we~=9Bwgl2zg17p=lix#UtB}pR?=Y&imjdq|@g~*=jUhx&td)Z>iQQN z(Xn%dpF}Gcm;WBlzZtPVC|ny)Qdo-sEl?TZl9Nf63||4I3^OoYhqX$T$F8AMrS5Xi zmT5};iZCS1a%UvcfK`fw%lrpxNErKgPnyhtt(noG^@Ha2h1BbZn~CIY%U*=+Q4<1; zV~m^K3cl-48>*?sU~Bx=4CA z$>jI9A3|PRX_4;@w2T`lKDWDgBi!!h@v-_d$H$HVoN~3XCxY^)h{)+EY0ks)1%~&PY8lQXH5rIo^qEjZPGmwJ z`Szr;h8~JXJLG>)TzV|7xva z7i`Q1X3Xt;f%}KTnvYp=Sb$rT+&>~6xqp4utHbq3WiNMM_;5$~bNsIiB=|%Bf7(#9 z{$J|klNd%UM)(;Eu#N@95{~sq2QzrC&C!CSPa{^Gn3$F$G9TMJY`HTWZoq0nBN6az zC%G|L5@Veq9qk*>hsw_F$E~}b<@xK!X*hzvu;C38p&9l>7+gzu$)5}4&+HRnYRXBl zVv9Ni}aVlU7@* z>AFBlQg?G>U!MUv#S!(o?uNno23uT5*jsMZr}%_wmuZm{l}YMW5&gakJcL)ZlIK`PM_ z7s6tOk4Y4Z-S{ifs7#wNp>+0NKH7!>ifX(yk1L%`)otI`lq+iy4~dT`CY$)8%em2q z%bPhCf`-dmqk<@2tFGy!bnM#x7LvE!`q074>3Ug{J&o?4rkj|Xo5qMBItIS}WUbJh zs&_My6N4Wc!Mv~+wpTk=bdYOA=RZ--xN5nX89+Wn+9+vUTc#BIIVpHe^9|LfTB{}Y zICsWr%PS-bG*O}0k!^w;OlwRnT`ALR?%thov$pgz$* zEbrFTUY8g;=P$nt&^^c`6{&H~kxbD~`z78cOKO#WF^1kT6T`$KFwYS|67-H%;A>H! zWMbBF``N5D`0ia$X`0YG_eILhbjS%#TDOuZ6Fk!DSTL;D3TZjDEq$^k!BY&sDpz=*H zCL&xxJ&s%~5^OBlG0dtgnBoD2h36_<>{)Qqr2tdl)7B*;!R@AiaH%k03K$9t(4dpQ ziRVP)raSxUTY0N}hcy`#6DsdR+u$FgxJ6I!g!d+23U$>y44^%{CROJ9Xa0$7So)8Xi*8UORsQs%68oGNqd;d`*^{l*|;l^hj=&+!(7W|+s6L|7A%PV$9eM_efB+(=4}g3Vw~Y0GGfSo}R+ zv`$gea}yTMbP`p{Aj_LKB&uqr@U>*QcmDRZzw(vS&BgUMiSM`}g4ZG2IrkG2;vY(w z-G6>=UPjnK|0#~T+&8Y>MqvTEmgoDBdXJw&n--Wjp#}SyJ~0jJ(meWX8zOs@WgDV+ zv}_w9f7EIlqI`5``y_LeY`X=#X66fJx+didWxQ@h|0#+1dj`k|7+p|fkD^y!Hz}l9 zmdTqfvYBX!cyD?UXHiX7yKIqTe&%J#BLF@~NOdJ1b*YpvpDB8E3klKI%JO-iJ=K=v zNE|J=(r(mX<~?Y{8=1pSPM>Ml*%3dFg^lWPeXF##c%JW8`Mohmh;!M4qdR?TX55bI zEe&g4T7@>-jzTS|qc3*qQ^~4CU9O<#YD<1#pbEDWUcb^(xq+z#ouZRAb>QfX`MPn1 zq_s5b<7%AG5LOgS+&*XJxeyomy(+NhguN#xvNxIJn=tkwO6Zs8~QQBK+N1fN2 zKGS0G+iFs85UT48;9&jzjlIrTH4W{1+Xn|M3z??2-K5#V2I@gSA#QQcv;0P^qrmw- zb4KvmJ71d$GS4gLBgHQ_$Xo#nEoxDkWS+XV-%S8GMgmuP_XNIRFQ@LZe7{rm_epCx zEm^*!^=2I%@3wEaxQ#~ynZr97m0R3GsSiH2b?iTY3M^uP(FrfP#VgLUFYM2ox(X)N zEJ|ALKPOs+4BC9lqmkEhnWTQ7M$~rcz<@QCpwl%P$uV*I7jmu(8A(+{Ij|22Z`UUd~8(yig3!2atv31Ehfr7N ziz!&|Uc{RuL{iRb7aJERL-}j5;ow7y?!gCc1J>CcRqKTS^I?LxQY?C=bhaf%iq{z2 zbq1{@p1tc9)dVGOi4%Q(+_Gq!VU!pou@_$^QR1zm-{F2Ce{S=VO)RadHb~`1nA@CT zYn;6f3yxe4j^0#H2g6!*fdXN|Dea4a>Q{LZ%@e``qVmpOhM){ z)!95TCu>Hx)TEv3_VNy(>e#3MOM(anZw%HJ9#ad$vqv5T~a( zT1vs2vG2__#tPO~a33&7-ZlzG#pE3^p&j6l=oV#4z@vU7l4H8tf}D^_UI|s-@+kKN@>PyyfwuW_^sfp)-kB4kSKYXc_&>5x3D`2IlB^ubVOo zww?bjz^faj1uXAqWlPp$)kU7l$m7Zoc47bi7F6Gh`{?;|BRLca5vPa;hJmInGK3*q z#5089NQC1(U`3SVF_6ge!bAX5S-Vfqk!UM?fQOk%epiG!Uj|{mMw?95DxGlTIoW3q z=I7Z55v)X-Uh!I`JcAgmrEg9)Std$&Mr(Pa2PBv|iac^nZSW%jts?}O=|UY$ z+?3VT@BDIIqVgG`>j3T>tmgw-*g}0yWIy=?y59kwxW!kZ8mZJp7Zhg0(JaF%YRhd7 z7ITaAop0@r?@A8<3s>9usQw>;lbA6}pCBR<;E$MdNx)e=s4NDZ5tM|OVG7bF0glH^ zRe(<6LFEa`1|UtnjJLJH8c(X!c+c=bak>9~-Y%l<1g9ee0>+M%U4sa!=7knQXcdiP; z0fe34K~*rWRD_Im*}zdKfvH+c>6ncW;Cm2|*{)G)7~)d}^sfiL-IMLmgLKn7%6{Uey6F|>dUR>}ce4)}9ngMJl&4kO37@+Gm&!n{Jpy27UUbHM8LmPX`)w%!IXl;w#k@RR7hS~q}S9puSt8DnT^pA z&p|~;&t`~`gQSpSLe`zWS-TQn9j{y&24ei~`Pv-v?CZd^n@cz0Rz%*Lr}uXnM$yOr z;d#&atV*EpY{^KPe@b)tcR5|fRsN-wkF`5oclqCIQw!3@-R7U;Mg2|_!NB0^MqAT) z*`ChOO?HfJqKEOFt~u`ALMG7HKb2-~Ud*pv>w(H85K)Lj1_Cjvw+#y*p+Vps#po8{ z!Xhd3&dCYwAzzmc3H^n-gFwO$wxLT@%U-ZorDT^s3W@5%ZO+lOVv015;)3V6tTXQ3 z&-oU9_`p+-9hGFad`axD7rTy~5^#C?dBnL4mt1Gyn(d;nXkrgRdM|UbpjzLj;0xVg zpTVGZBa`Y}mYu1DFO{LEVuzG`v5}{9=AK(lC&>pjH8IryoYq>356g_P61C%ktY?x0 zs#GV90F`Qk>-PXjhd5VuE!4x*!f%uaFj$7*`)jV9H5rWgA>< z@LRK7n3N`->66}c#LdCgd8wMPBE^BE|6;{_6NG9vci6tv{?R}ox0huAYs8V-)wXUp|PtHPwqf|Y@h_+B^egr<8MKQ zsNI>-20|CDUxrh-2|a^5SgXNR%su$L(`5mRJ1w*nNA~wJdJEPeq@_3FWhd^uJTU;S z@cuGg0QJrDET4;tk3C_)G{Rr(e)QoWgC> z`t8u7V7Zge%tm=?0m2?1GrAOJd8y6Gen+f0`Z2Y2tBKl#$+eI#>dbW73#<3m2tku$ zx^cq}=w#h?{fNL406tmKG~dmd0icp@qH)g$eKHoLgJvNRiR{9p#ID7XJ(% zK5iTO^z?-EtZr~n;HEE;h+((F!tLa+#p2@l(2d}Nc^4rJVN61^fbW{YfB1F{6X7bm zuL{CmRw9>CHE(@+Z#g~wk#P0{a*(r`5OqhdCS^k3bI+^`?e*dkx2*J0MQXJq*OrJq zY=fgzL#h^zi1+UXzNE_Z82Q4_x?5z2kgHc7*06*ub*F5e#?bn>M$e}l-9foa$<6#X z#5WuGA@k{{i&Z;l6ZAa65qeZ=TtB^)$b@N!)9#`#dJ)rj7*puU~`A44IB30@3Mhc9I=6nmJekTO*#QB)Lqf( zXDcVE>sQq-8P18!onr!(7{(r`Bb>+KAy`T;79f8TL@2_a7&r)we!dl!c_DGL>vn&n zWS6B+92ObMjYIm4=61(i19(SNhQLi4gkS%yUv`F8rkC_iHaLm_VDl_moSdv*W+Xx+ zF{}n7WwI6`*~c&B2une%cK)eKA>oSMcFkB8#kF~u-h!R98JbC3@B{TAIX!_ohM5}q*W7*`^M3qh}8!qMR2SBGOivz zwe54baVh^J_?G`y@cqBB$@*^Aj&A=8dH-!)X@B&7qDZaJDto}MEWn;&26TGJyDp9c zZN>};8=`UjDTAv^{=`rY2D@S1Ppmrgw*RV&8;|}R?plZ#X~mz|NWEWmeC@96m6E(Z z{X>FPG~_EF1|gcay&q`8yh|mrPt6{FO?nzmI%4*^^x_^Yc7@hhG_E&Y;!n|+~>Nxa155)t}yQT9(68cnaH?t&S38Cl#f{6%a{NQK)LwjbGBI3_x9h?VX-!GjG-!i5#5{3NC9SdE6jDfHhbilT-j+CM`nq zX9#zcA_p(WuVqP|gnOx8^RLYr(xGeK4;@|Z9*;R4O_OifV`H;?-9&mGSGZ_mQahom zmGnNd?&u0U5QeER*-~Tl&6^oV$1P>=<}I!1H}dhILm3BaD8YfM1D&EN&mrwFzUqkp zA4TcvhZk?VHkDXMx`y4%O5O=#@9F`Gt=CG;bV zR%GW}s^T|9Phc!{c#543J&(}{QBOpJL`;L>$4^rn`aiKn4oMFN5UL4M_xiALezLGh zcA7{UoU+ATS-rB@+z$Tb`!)FK3htQ9!q7xv{TfIBqnV>jAw^db@0Y5gMi4t!HwP<5 ztoO!k@;k?gwRJk>FVu#hn`&2x<-)r**D_IP9%TNu5fGFUNk zt*m8qj{DZ4=ix`04iIWrXX@*R_pY}~?XB*3MTva|wRRpOPsatu@Tp6hT94~T6cCjn z@!pc_`bwz+1s>jl{B1!z1!Y>&BO@sjwgyDE#PcrN)i;dGonr#b5VT+*_h z#;Xs)$y0vpqTY*As6b$M$S}4HYPAkdAx%UP+3X!N{UR{SGLZx!dqN6B=*T|{& zRT_v@CEOvFIaq$v@7?+R!%G%SK$UU6Wkwoi!os>=$dwPAx6^qn3e(gx1|YZxrNqk- zUd=dJ`}b8_bv%f8y-D)-TXOJn)umhVGek#y)4>{HEE*k0L$h#zzuLDF{7?17zS8e- z(5s@mOz!<#_Vx=W!<}W!i&R%+2Jf?RFr62!D88h&ZoWj#;-o!m<^;SKDKxcHGjk4b z3bmf6n2Pwin}C7D^Kt+^A(sbrpD8~|g^+6i*O(>GgY+V&9`z1mB3SJSnTalRJxbd3 zEh(;yK`>vZI9aInZ$Xn+)sJq175)5YxXEjLbDPfVoi%ZZ?I>wK#6EvR(JEz9F2?=V zKcJ78v>P3?8-%_b?MXHAHDYKoVyXV_1v2h)!zSj}5g6N6cn;erI5x$fSvTY_Ux75~ ziA$U#Z#ig;MF=$NzHviarM`$Zk%xYyohlVXLTh^#NQI#;TTCvIyoGUY-u45RVQp44 zba^0qTx!5$XHjA1BhbC%RcSPA8yY|e@)FF1F=i*xrzQ}zNAWJ-fe4P(zdeleDx_-D z^$roVLy!qWzWvgqW7S|-l|2wn$k~pLsbdeLHH8(8-oc%S|%Qdk@ArYwci*s}jvvHI`m z4gM(jOGwi2cF={#tN&9%f}^)T${~7ZqJ13Z6yRYEz1cSkfug!yZbN=_f*cI>*?q60X#O}*#Xk78gZ;Wp#hYj}Nv71_q6x}kxhwwTv8p7UQata&sji`!U# z^KeP3)yE>OL%`fBZ)4_tmq8jsqd{7p4w)Un7ZE*I^1X%HFM4DTCb`6BrVr-?Nrr3~ z(L;}>1Id4M*s_41VFKlypYSF%iO8)_rTqOZa`)N|H%V`~m{l3wGGK_BN;40({6{^h zWnITMSyjd3iOW)LocR>gD#zv{T*lu^db6QeW%_GcFGwDu`|mH*Jh{wpDyCOA zmEG7euTg6(DF)-tt@;tBt2WL}kc-gId8jrJX-cC;;@W)alTP_0an@43)6 z?!P)qT}l7cG8>xBS9>F1Hc}MjcJq=<#zY=9OTcV25jj(U!$xrsNy0Y!H}^KV65`v{ zy5DOFmJ+ADuN9wKTYl-7&l$johlVMWDK-0kpZ`MA_A+F;Mej}v5e7zq$~+JN6t#56 zCDEEHrxqsfe@O*BP_HGtOKU|#Wsz}fLgQP2ux`JkDuHV9m$uX2p`4{{yJnBH^{z&; z3pjm8PS|0a1T6Ce>2#^C;%5}({Y(IV6g&L7Rg&vz3DTVw(|+#$eV)hH*cGT86AXA` zD=$0Z!4F`dKyH^8)cyQsVbca#oCc8q8*&V94}rn+R}Z1`+;;CjJ%xC}%+SFc=#6-o zd@2sLr0&2kqfy?Y$3Ma>1Q~njLK23=8LYqJ$A_SUxmv+E!VHx^Yfk>seQvFTxnOYL zN$`)p^WO_Z|BLGk_!Rx@+~B0gpY{*`H5c%iqRqpRJ2ed*s>)N5{zt#m}shurbi zv<+_X<>gHBUQnnMEq!(ruL@sZg=bNd{lRz8R8_4 zcB=a`Ji*Q3?(yq~?PoRCg7E^GBPnuY9OL%wj#k5vK@Ty!o&z`eA7M8OrIYZsLVZx~ zS8Ow8C#e39bl=Y|KD?Et`IRN{~sOOr6+qUnu=;_zQt?!U%<<|M3=`1b^U^`Dt zsT!E;T!Kxe+MK!UD{z;);T@nQrsKHFej#SQb&9{WdOTK53c1q7*wp?lJ=Gs}S!iKJ>VibuOc}YITJrZj=s^P69xW_v-iGgl?kN2)a3ki3 zi`#u#m5H$)o61(cpqpc0=W}rl8^1((MByLa59H6)Ao`AET9NcEA)z6hUNF+SX$bF7 zNkJaTyMLFZbN~CV%y+6b(|eZ6X1q5-6}&csN?Rig6)r^3R*$^mE9nWF>}0c|pdW3E z8^oNG^|!bh9+6uy0^RH?`Qed(<0I{KnamIY+~G==saYw6>rXRQ0}}xfyehGBR3$P) z6Cw(y9OYDNU7VN|9ak6OV)ufZtz`-6FE-j^v46_j$zE&HbSLqjgR+^_~U8 z&wThlav2u?U*bhwUu*c;w)($h8T?hs26rF2HZR@XU37imIcDBIjy6^{{BOx z+tdFLwD{=M++t!{Tf1c7{Jwc{O=|kAbNOR$*6sXsW#~7C$EQO7qfY*>Q$2n0(h^r~ zR%G-OzSIdAM?d6jx%2U*! z<2h!zZ35mHp2kylC|NvNBwYAh+FZ3}241nAo^5Srdu9g2*$%|n&g!KT7$b6i0aiRm z5hW=ozG)hR`EC@9&9gE4Yxw@f)JbU9T6JAt23c(^OdTl>{rYOL*OPQ9<4^|r*J8v= zW(CBSxmyia1>rtXZ{ORd7(6dBe=NpL<0;SC9|>Y!z{AmuQz)rBpEIVKC)1&gX<2CV zYwAy0TB$A0eLjReLg&|3G3@4AelM72BCjjo??F$^5=u<3UYa{~j{9xw7sA)GCz+w| z*Z1D~2Bmdx)27Cr92;JC>37Fg`@AB=txPJMcRlG4Jyz(a%Hx7iV+p*MH}vp!_Tuq< zvFfyIKyv{eybkv(5+zf!@OJYdl&_+lqhZWwz`$l`NfzgJBMP=yv zhrQP;<3`X3{T4o-Y0XCFfjDL@=9J6M^$#<}a{N#=`8~6wQ}fcc_52Vu3mcSVyKdGG z%^&^6oz9K+5t)5+suvK8v=MF1s`K5{md`gcWr70jsJhjbu0DxLWm}y%1o$)Z%6E?u zEM^D$ABHUuOgz(b;Oeir{(Nh?7NWU^Qqr&__E7#N^fH{$_7yF^=267CAUSF2+^Ji6 z|Ct)-6{m*#mo|=Ut>n6g7Ywh>zTW(lxsDD`x$)!=;?($X$6BHZHYIbF10wSS<1~?l=YJ<6I(MSZ$!leQw*#wKi`*RN&It zgvD}T`73ejE2F0B4rgW(`Db;G3?1gJ=W5d*RT_%S-3iMGv433ieqIjAiOIO-B}UgL8&b-Tc~gzu6WaM<|mZQbnIsV7B_TLpe?=`zi}{aEb# z&BLuVva?%Rzr@tVnOcBFoO9vi^(2!Rzffxu73{3uHu}y;)3>a(P4nWpUslF?#wE?L z(lSE$Rx{Eob2Oam*EJ~X<~_+CR5zx%Az#(l7r9%z7L$a+ygA^*see^ZZro;ySr@Ub zf?9j@lelE~IW_?}n1NA2Eu>;6+s4A8-nbJTXJHdKYJNtly2-Z#HT?*=Rwwoh(&gXV zA9pd)a6kK*wuxV_SZn2Kp!C~z@J8GH)%$E?QNH|!G7({=unU4J2m)t$dx2D@R8$J z&4I~Xu_XToGpZu;Ot+|3Rzv>AyU9Zws>ze)7w%Vi3uw1f8A zaOm;KV(r(t$Ce8TWimxFF=g|}fpuxpIDm`4ed35OD?WJ~kt@E9W4AGVoR2GnODOAE z7BGv63&h3V*5ncEWjr>#OYpfdcbtOjv@L(|P=brp!+6>bDNC)*<)ATkoY+jrdv)ND zg3GksW#0=a>)g!Gqdjt5ldH3Bqu)+AOVaFOw=rv6iVLlc>cA^z+=>gAG7W2@xuW66 z@9$aY9mRXJJ)d9oPPrM;0A{SozDwt?96KinGm%B{P958;3up?c?=u8tIH;FM`*fas zCkirGkglA2>zL$;iQ>zWt=SJCTF~VoMES^)od^*nno#VQzzk-|*6K$j;wXE8k4d6i zkBm~OQ%{6asa+31snp$3?k6W&VR=~ud;?L!gs_ODL70dHbn)c+y)X@mfa1viOu1i($V{sr zo24xUa?a8g3!!Fd%Ym3a_h3g6*Y==9>3r@Xj^bamqlxKPy2FKeTeRbbc_G{1O?0N% z|C;DbzCQ#Lr)UTMQnG`9iBr5Ii-}XZ1HzZiYv<-dQ-`I5|1UHq2m*95KC3J-1o zuJ_Z|bHA;f;C+nh;aJptmHpA1d4WRS!pR)lg%Di-XqseR|;RI_Afy4xa5H+ zy8b)b*HrY|63gOp`Xy@AVWDcl^VuU3b+?pC}67Py6swoRv0H+|4E?HsgcseYgR(Y5f zZ`pG>Kf(hpY}+u%Pk@{l7`BObg%jlig?1yiYatnz0l&(DQzFjb_i6)QsTg2L6fgpm zKwP;v#sgXOdz2_5HP|3>paPO{HLy1VN`MgvklPylvqFGcPQY=Z10;0T3}_|jz>rLb z4Kz(~Ac{To0Z1zcR>lZKkPAr!Q8OMeLb__gRxqz9(OJ`=hM)s_0DKijzp6kbcn(bl zm8C^=VS{>yp_&9&II>%dG7!uwj0m4h=pFFDpKQ)pZi^X)MgdNP{G^fl#CRZ&eorJ1 zU+E#iHDM7%2mI(&P^cF00GCV$1bRzwz>jSk2?@plWe{A6M*PH=XJb6Tf&^EEHL<|n z0?Sn8dLU44oVwi@1S8+0gHC8lL|#ZCVv;k@KpY(42d4>jzJy)6rhv~QiDB*0On=5 zoJn-nNMGI>>4jUluJZ_ZFoNggZ}b(4V?53~`0Vq?zX$UUgQjL=#8 zpdkc&VL(Dbs2Wk3WCRr>h*=g4ih{4r$T>A(E_zTLyg5s`3OO)-)J+yt45Gd)Bg6{k zjQ~KQLFlagPy_Fpn7i(~~lx!+3KT^6<4B zSyTgQwFFoIvV}(E1RxWtgkCiS?I)O1fZAi*zK7_^!tgMR zaX^b?d`g z+jc^3-au^_4qVVrVnL%|SRk^fCDLj!up4OG7GZ`C>gI*7EuS4p;l{ST!p633+qP}nP8v71tv0r8r?HzR4g0P3;rs5r@B90cxz=3ykt3NSwIv>1!X2fDI7K2RB|FrH#t8&o zP4R?kR|KyV6N8YMm4)p?6N{Kki$gB}qf@w}_7FJW#6@I>>d-i`z^f^iko}6_10_&$ zi9<*1Av~%G54`$7JGVhPCj`TXBp#3*>O*ruio~ZR`hl<21zo5m?jbvOhi)Pfvta|T z_#~qtxTE|KT$sYNFkaBY;)apr#0jW}ObCa8!Lgxzyw{xpMC0Qx>QRAY-iu~i4)%U^azE?q7;Sd;@bG*$=r|X|yw^fK!IUFA+n2umClvv`p3To+%LOBr9b08( zg0}lxTdTggPL&@m1ZJ?Ib6H0md7Bteu(*WOkZa3R2z;h}6c)x_|IP@(-Y zr%ENFmH0s%-6=C?)Yam6Wj!^f1OEv_JX->;v}9I~_T`;kbvhfvKZ-^7i*)V!SKJ~3 zrE|=kp;gcgvuA%HtgnWh$0-k_(VbYygX?MCYx#PzbM2ZBsqF&SKo5JJ`i zrD{+>hUKDRTGQt4G!DdiV^KD2^YIj{`USmXh@R!5^rZHRG^>O|AFTuyE6d%N!S=QU@~-HhW`lIJhq% z4uxuNB2%Z{!V+wT#L{8!V++0Dw|#No0Ok+-%;9nC{xWynFkUUF#>S{NZ8;TRC2m3c za=txv+WZ&+{$&Mv_-g-eS&P&8)Ml>P*?#@)24)%x8}u<9Qbo15y$` z8Jolj3ckt_zmYmN3H#&57Gps_SrnCWnH4M80F0+n(9^F2Zz@JWcgFdZV@LDUczf&V zFGd*ngKJHscM9`-BKu(dUQ!V{$cS4cjrix9a*w@7==UERK!+gvW^Q|tk^D)f$avz+ z19#V5`NHmn-0$Uhf-DK1ARZ7&BeUTfTiV9x1SZTQFs`u^6a*4bglbi!5%E%)2V~r( zrX{7bOmq|NPy{R-+N%{IVF#aEv>5#4S04=%wWi zHGm)t??^xNAa)m%^q0!=#k}*s!- z+#Cg{lNKUO3i6a)`0&qe(w4)kL z#wVi>*6quwLIH^Ik8*j!`;kaSK;OlK51#LWu1^m@^o&ZgC_;g>uz`F@=vW~MJn5vV z?-qd5ir*j2HiM8z7^pOzK_xkZn&;CQ;2~LS3T?L_GM<(|iQMKX>J3LPRsnw!g>9sQ zIz<=aAIg~_5ghhS{8+4)3Vi!1n3w9huo(Id;>Z^Vg!#&2PRvspG#ORsYkDv*!px|k zGRY`M#&FvyC2Eg6esnEIUYq5(cD zJ0Zh@=51x%yE#X$%epl13$p+ON%-#1)R2&~D@_SFF(gO+tAFGIe>*k&kCmc|rIoqs ze;bedYdo&wg2sXVez>tb0ZPmPOI%!FcDRev0-l#n^r5=Dw|QLNakJg=sPvED5_B~8(4Ag$tiKIt6`%fdm^HGeEKCrLE! z9#E*XPV*lA0-_<;gIRe5I?yo{&)i6UraX}=NK1o(YY(l#l4=uI{|%4u>Sp%X?o`H1 zwAgdE&9jRR#WvIVpAlqj1}*is^yA2A8lqer{~3 zw7Y*Nf31;8_|ka^`L@GGIeRKEz&;yfxCtP#mJ2qEEt##pdh_Tj zT~W!?9ydl8prH}1#K?+Hx`Atz#s7n;LIB)?Lwn2o?PC7t&V-jpWg-=)8dsgSXZdtx z*i8)whn2yg5TxgP${*W=)?vr!tr+fw;pNggryUA6o%T$8zCl_@Xc_m8gervehU)`j zlb#t8Ykj0hHkyw&Xx8wL@zo#$uKW9TBRych#+^ zE)IRsBAkBV7EV`}?>7%q$T|CN?_A?oY@^1mstChhog=2L1L2Xc;gc`mN!b;@1%$Xs zw#lP*(H$<(NwwARE0I@>zi)U{i280yk|xWbY87X^L?EB0C(SAKND%{XcqK|7>TF7r zCM%#;C{B(Oi+0)#NVf1$iQY+(EUA)sNLAS1P&YO>RKB8w1vm~P4hih}4qEi|j=e?e zKG=ae`w<fG`tahw8AgxL354aeU_i|z#aPa2a~x*Q&Q*yx5UkV>59txx23FZ zWorvGty3{^HZ!yTFIe`EI{x>XczOvQ%oz>@1*49bk`yp1M+Q(-PE|#j4Ax`$W8z>z zLFKa_2zp7K=NS0gS4p6k7OL&;U1{@BjJKOYJ5P?I8rBFI9VeAAkZIK) zKv!`m+uNg%>u3K3#$E8zrkTUYcCMP1E=EIi%r&fjC9G%5RoQ0>?ftC5mhY+F9#*O< z2j+A-q1igy3LR!~^hoEMq8fABLdLd>m^`bBS!;G<#mzy$kS4c!0|OE90n?F`>Vs~C zN(;+8PZV*V2UX4CqMk~%RLSv8&myi0gqv<(e!RTv>1d&XgnXty{7HM*h869ZXEZs1 z7%hwJubl=)_^_)3`5T|JYt8_0*NI@6jvvywd*XvIC4(E>ZQZlCwwDCZ3!jPBh8VvH z#_3xnx2`}E+>cvgia_}_Yh-yWbjJ-7K6~?N$5y2l7MWTDeT6PmpiOB}4-v1#g9ZlxXsIk-Ad({L;Xb1hfx!1FNdVG0KosLB z?YBw256L#c=p;g@Mu}mPiAt!vpkz3ZT7^0L5P&$Fftx^82MDQfA$1ZVcwSqIIugR4 zkZ=-`Z^EB&nRk--`%4}rKk@@meqmF0_?I5;N{!tDtoQ#opRTbWtK9?FYx{q>QWpQ) z>H;p&BpvL`Jb;SA-xfw9Kpmlr+5aO;08b2^uVw{cmdwe{PBxu_O)^28aw8eYDQ~+b ze*rCPI}&rT?o3L7GZlH7srU+o_cag!t~^+ z8b%8#+B9~11-&PwXAitM73RAV;|Z8Wf`+11vuWGuuq}8$6*Mp*1}l4|)=wm#=hE+u z)xJJGzclcy^yHw{t75l?5QxnzyF4j#=iT$j)7Zfyip%WwDK!y05`U-V zNcooczQ;taYj`j!=|u!Y;Cxe1Ij;mZ2AL8KSqpaa^-s@dXp%B>CB}_WU&>7=V#Z5sNXln$oF^636qr5 zM```82!zS#igwimMv0ZjQ9C}%9E$j+N)+di&lk_^6N}EbqD-z|;*)%%P5P!w;*n9Y z=mj$*%CY7dHon7YQhG*IufG>ZWSHhJTJci_(%FsZ(3Ge#Pyy`;N8Xw6+Znh)(v(y5 z0c+(yy5>}a=m%3^*IfL|t||4mb^X5_jsL4}k^!+Xkbh|hB#`_Q3a9>20*uV0>Ys$g zqy`6iC~g#1dn&M!6~p!+Gd4e@$+nTgUraCOQbqX_?Xb;d{50H8iTXV7Q6Tho@&eQe z$Cr`+;*{$+V0!X8=i=d|ZpPq)AqpWn01D1)G`MJr&JMGsBR8art6joSwJ}kpZc2Cz z?AG`a2ILON^Cv}CRw`IuJa38>xc{*+Lv%qGbRl!q&_W;7@Pp4=kRTzNpsYfe-klI7 zWBm+n$Zz>5*@L&0Ry4o7KZHE!xfAbae4$VTB;uu01l*9Y5Z_4I7s3ag3BIrWnJYsf z%uvtzpj>`i>?1FbEp0-6vPW{t*gM79uTx6exI4u{Nq3_dQz*=G5<$NJ1KJcoWG$qUW(Zp43)5l0{m-(LzRBV1?{EIvUAHu~qTAa;VG z?%Xh;?@WU^CoDu9c$yJVoc2v}X zaL|Y+20?3RQ$&Ct^mE;Ic6lLHPTx`0%Us?3-bst&>*zCVp?q{*`bAYSKIeb2lmM^Q z5`s(yOu{;EAu=a|uMH9U!%A{NR%i>&OC|czNKPRp%LhYWz{rDC3!v|>>2Q8X%Sw0TMjQ@fONy>?{82aXa(g#AkvMILxAplGA;&L zP_S7Mu+_bltTsxcqI)PoLO?@(Tr;4dK9F(fBOG{vd@`d|N?J}ezGzv0bJ2A-o&B`) z$D;3inSWsNm6)$IOK7Sxy>0RgH%PR>2v*<3?CK`Eud&n$hPwW@Mc+zI7Dc&QLAv<4 z?m?+xs}w?w__O%ox*%xxDlRq9fwHW$(5WqVlx!{p5oBzxZ(Gf@ zAxdalN@WG-lYQGs@EjeQACYBC$H9fUJOX39>>H2cw8PfAfacIxG7@x@)WI*yMw0lB z)k#iIj}1-v!$~|Kt#t>svNXH3qu}4fqkwZUICnOW-uohBnh!?k5m7a*uB1|R?x->q zd9XP0rQSc{*kanF2UETzk5V^SbC}=DCdJz~$~KU1Y0gV@x#zkozRKp-_B)p=>zGFE ztPQp=cuCAX&gwPdwobQpEV`Z_U9qytd?}} zdmQY0gAslMl4`F2q6Y|eFVykS8{^fBBSD|VV&6dEV*Uz>1k~C5IktpE|4dTvw5W8< z18gU&Zj`B10L0zcP=+X;6VeONeXj-Q!^$pqE%>cNYw`*cH=t-?!2mEjrM|gfHJRx| z6U$bljd7^sB1=-&2zAH;&hIUF##`!AS&+BD!fJ0{$G>k}C=E-+-ld^_Qh4 z{I{hhW#?#Q&Np# zvNYP2!Du@k!bfNgro)(Y6%M|u)DDxoaMqGbn3W^8rhgkAi`57V-hyqV6ANvfRgTYk z6t1-%OZVvYA6Ofxk7^~i-lyXLBi^EjThGug=%sadt(GVHxAsIOia0T+#;uIk+mKAQ z;iO*E{roY6A3W`LEKXpT09XB+#arTE`Z~O6Q}@*x3ia30QQgg|a)oW@r9Eu|hE8W7 zm*xiNm(ZyE)^y8)D=;Gkz8ki>SjGYWvd8c_pj^u00~gIhbEgttRX5}&3WQhnL)6_ z7jM8xN2DkJYu%QAok`q*OiY0?+^E=z5FYXp$mdN6 zFY#lz{NY99_ZE#vsvS7p`vHR42m{Buui4i$g3@$;+%oQ1An40u7eb2M&j>wiVw+}E zN1USO-%=R&TV}K0g0eGGl945=U-uMCvOl3S)z$HYd}^#R-Yp13`2lzIf@FBohurp| zC{d76vMN)PIHKBTOtENN@+5Nr6qeLc(RPvsKoVDFra*{fY0ao<`R})3iX>Wx>q9n? z&kaeh#QQt5Ri73u$Pkl!<4i9QjOW@wMu*T6NhK1!1Z>X!_$Y-VxKgzN%Vg^>iH&l9 zTP8pMw796OpK`1~toAz^k>E3VUM4-2ZP~35(Zl4ofa%N~ zE}ri$$G<&fL&CuC2TC{xcNB(6_v<d>yDare8M60giv97cn1SwftB6pk9kO@rSgU5}6lx~YZuGHCpzB1~1hCK&I#)9`2zLxwi(SFk zYV@^cX1A3eGcCeaKI5iSmA90fd1S5(PBXe-Xn4_zE)%P?!%rw$E&F~NlQ%C`Sjrr| ze!)4tXuk3&?#@4uY~4^;&fZK>c4I$pm2Zl8Ncwrn-tEUfu$CVq z8fjPvN)hXM$<%Pwyh*LI*EpaOa6MN&Y1Ipk&klg00-K*VE#?9*f{Y!ogttd&fBEbW z9u(CZMqhDiZI+^@l>6(G%Pu(olE3e?(qX&^=*`gqH8`ZdCP6Kf6JOwg&}%p^wm5MO znz-WVNhmz*YNovre3(-%V=d;YQL}_1vlAJoxU)f!ud=TMM$;y3A5*jV21xt>6;Pnk ze_FdcgZzvQ?O%+*52oUO1L_@7>|uWd7s@U1aj~{HBYiy4%I68^uzHIZREtj10Qs;1 z(^MO29t+$nm`TAWu-Gp#2a^mR+^ZBKb1ozlXd1wDB!-k2i{y+sZ6!z|l=w+IQ43=c z0u?5>yFX)vPjLNHQm+>sFn94z9FDmR3Yg!!Z9LgU2)LXe3WlRTBFRxz0{?u7;G6Le zQ8cyO`@#=ky;=XIZd3km>rKej<=;eM7ikCM|50tg5C3;EMvMA}yowO|mI`dzd~|wD zpa%q9IsR=eAR0Tk7!>3pMT&(E4WE~9Atw{{4WdUJjUfujKaj`>NTtXA0T=5uWkvI? zS-j}yY)9>vhb*?Pg|F}LcNi#fb3Zs+=7!v@OJrI*Y_n;YvLffy#Jier$UU0+SCqXx z?6*t@kFd$h(#jAXWz)ON=DZ*0+EV6b>hf5kw+^0L?;wh5C%Jca<0rnb9fvE|?rw7y zy_Ymvm@1i;q125Ph5j-jj0G3kEmaQ2kqo@eQQY(Gc$svzrQQA=h~Zm$AZ zZ`EhwTnhH7>BRxL{^LLsVA9;=lGYU&u5<>=0H>awGJ}6%$l_2j0ImQP^CPlO0e#s@zGnt~<`kw;!+@&@oo%2Qr>ZaG~MMUY= z=5^tF8+Fr13jM`Tow#S)#!oZU(q}dGd9I}6^FyE1))*pjtP&XSd9;esNrj+J41-Zq zWfh}4QJX(K44nX#o0rry;yxki3V5@7u(zFCOCReKK$IV9PJ2oE~$`|;ylm_ z*ybqF2VgObJ5gRx&+?54te3-(wjvt@A6`HOImF*E1S`YwdvUw%idPe4C$~Y@MOK|> zS?+5{86x>$G?9wz;4lpqP@1D)1LNnBy~RgPJVkC)qInS^daQ7BO82a9$YxPu2)S-! zNwO;r`p$F)yWz0CY09ZX2-Ld!6ku|D^))4BG)G@3gsIu) z1TRJmpc_5<0fp&9wf9Dd8r1y&THxe@@h>MA?Eio2^nX?7KN?_(+P~eJ2UG-! z_tDtE&5$8P2|-aR^OcQ%5Bfj;+pXE4_qQphHob1=4VG@#cRZk=I=GjNmJ-v&=h=P7 zWroks=jeFHVF!e_R~i+DS9%weq9t?QoLlP136;gOaLN|n#c6V+p?CJ{VFgwlOO)pc*vU<%YBoySm<* ztjKhVfa_mR-&BF#oo+JI@%f{h^g9QoLzj)2E*E#S1HI-`52j-1#mQnav}>&gP6>_} zA`}|V)TJZ2Bp$N*X{F74d+VFbG~L>1;Ek$jRmz$?;OJWmRyf9~HHG8wd?U%<_%xnR zjqQs@#fW?&x(VC1f1Wg}mUQ=T=Hpliiyar=vEyCsp)p%kb6LqGfWwzbz``e08<<$g zukU-+D5GCtmPNCol!-b!p~f8{SPc5mRSZV4EaVSLk$0zw$T5_L6k0Qn-8InhohF&@ zp}8R&RDN}BQpY7%;$L6z0X^)=$33cdYCQcO?VWLt?39_D_mYFE{LQ8$S#eyT(oXr~ z_2Oo-X4*5Ea*ffjYXfAs@-asAlS{f^ zKP>(BeBD?kb8&VD>8?4~m|WxD;975`+cv#p!lR?w*z79=Iqc9q#G(-0@i zz(Y<%v9LR>Folu$$QY+ythU7u$i3-loWq+>rr^Mu1)=7;6ARI0iE!3znoZ|NEo05U z2KwDM>3zieo~t(q&3K0Ah}LFliamTOegk@mc)FE2Hv>%|_R-HF%UIku^!>ROGT6UL zW5D$@E6P*oY{ZA8xpdKa@SR{uPRYUIj9Zn+#ib%7s&AGQsEDYUmQsg=S8XJyFsPY@ z89*cTMTHon$&binzi(JcndbQ0{n*6_eQQxY`Y=ayvMjPsV+pDC|{HQU(k7elQqpL%z0EPsK(754hOuXadU0X13NCcKH1u z9kJS?NB7T|(;aI9@gO!$HQ7j#c~4?SC2J7zkZ@K>!_zv|hn>w{cq7GX2^4PJ%5K98 z(8aweW35I=xczA5amJ@$1or%UmsYRWB`a_J!fWKKt8=2ivN|J2`js?)OGk$nso`2w z*>UFET|X|kFKHxE=DjK7g^#+vj<^$yHWUqW{#XkV-lF<=(t^g%?LPhlr7YDoQm?vo z$zpo$Ejp^KLVe4chbX#uP<+X~DAG7OM)~d3X!&dM;-vb-*+DPGNNs)cU)!jLut;`nLpX(*|D5hqYJLm8!0o zBW-rLdc38b0(-zvZG2GyXX3QOHwLJ~mS} zatW8FY2TXEgw#NtMx-aBeg0^PpRM_h_^l*lfYI5? z-a^RM*1_X<4j(Wg-qg(0&BRq0sC4|FPv95Te|Ce=!BCK-vOnhi%!L5z$Z!n|$tVb* zIC#1^DkLS3lcg^$U>E5pguSk1TH&|;61Wxn>N})YsELgfQA5<~Mp&)M%hM}hR*c`( z<@@vbg2jiT3@JdojT8QWo7r$GjzVHbQZKkYwF^!729xYC;}9d`1m9jpW4$u!T>tgBx? z-(RzT?0*!I<%~BvhAFr6ig9q++HcHf*l1)No9)t0&(lKJT3~ZYAC zD70lX+Xsd!y)1W|0E;-h0ZKjST6lq$FA05%j}ZM^8NGOo!Ga8*<=I#1&ZX%FdClUTeMxtLWUH< z(ZcxXFUM5<`t~u94fbnIzYN2Y>#zPe-GsU;LxweP(T)+mql{J}RiEgT8jLT7+Ar-= zXNTYG^vAPJ9Jg^_V;T&usC-4L5Km3SeRh%-;o)Yz-z^T;zqi639Kyb`%ox@~cuX|P z;E5fWJ3wv^Ie)*t^1u3JGdkPZgK#Q$>+mvOdUj9(sfUZ9FtOHfO>Y}i2qhu&ixy!#Og1sE{2i}*|;0o;|f_%DM zad8usXRuWrfeouhrGN$ui&1L~s2p;jng928MT9(x>%=>Gq#g-N4xq&>qS7QeQ9;+f znwVlh+5+Pez)f_U_?|+LY$;)adOr%iA73DxPfBYY!{X!%fctA7%c9h?a zve-khM1sZ2bm0@CZF!PplBR{kNhku65Hq9~*FVZUX73?@61!iKCy2%jC^6l_WUt&G zxH_O3dth-2(P((2&(F~Br4_;0NZUE!Y-3KgK=njkvg!61{A9_~EQM3yj2IT_u^O;42y z90MY(Ra)4cmSQ?l)+T|@XZ{)#CUh_uX&3A#%0r~h$L?eRX8q0NX2)ZW&ve@H!U_@* z$i;yW2*uU6q#^sp%{IjrMH9+llH|?vD9ZF8?>XQ8-aIB+4p0o6TGs?06Qg)Shs!R8 z9$$0D!$83r7XLnigsOrC*u|Sbqar?a?dQUeCTowPdKH2$a;Z!rHQyk=7J1Dc2Mvh) zPKYjUKmN%JPoA_W;zbt50U-HKaypu*wpmtlFH;pCZ@NzVC`ny`gu|R>ogj_Z7bvZv ztsHgGu!E)aDJ2{nzx^;SMI^fHlNMhxS>+}||FP(Si^A~x0ws3D7c|JOiquG4!UPi` zwM*6Kz;)}Z+_HUAln7H9&X4FzEtuB5X*9~=@w-Vp)(SN4m@SgDh++2g*fMEnuYf7f zWZjy{Bh)HPp@fCL)Bvzw*l`#E44PGw$7s>QAF(BBIg`g2-G5o{8wnd1g{tAn)Z3vu z4fPWaoc_v#A2^x}n3qfV_{Oql9Uc;38EN-?D(4M@qbq@kiA}F$3Q!@}-hnkvFmv{n5D$|ohcb}mbXp$ph9^3Zpw*`RVc8rY!x;SPSl zxA!3Xf^n4Xid3>EpRI56U<>GA&FctdXiyD27h8`f=1|1r*zY}n5@%`=7ljG8I$0zo zPF5$n^m_&%GiTNZby1l^;Za2sQc<^uzy3+tizm&V#GIp~|EXPx`z z!#?khGcgmY^(Huep0~@tS6c@@a6f&Rd1*5fU$_Y;! zh8?g3_>Sd9-+-NVL@?yB)a!*8(9IyAd#Hu+&?Wgk+w5IfbUF4XVt#e-VG~L#G1)!> z=IeC=^Yxy&2k!MJ)EbGYnG@9{Y&-vxuNMx?*ZYM)Ky}oQYDL}Sd2WglJX}+mW zo0+6io4BF{cF&@%!S8%MZwkE%c5Gn2UKnu$#vLw|lt#BLTV=n%?tk+2y81%B>7tgk zC9A{(qj?;JjlV)?iE3$@-62YS9x#uiX;?u}F(E~^eyKxT^HqhG8!k7H#+kwL9vXKQ z?7yY>{^h$>s_Ywy#Xjt42Q&`OMVqY-xKQ~3O3U`6_E$RhVnUXcfJn1AQ)5&Wif|@l zk{B4YHpcAX$|yEo)?4TV9QAh%g7C~y9-`2Zn3ugO>Df=PL|w1aG94Qd<*A+<`|`+2 z6}o(wt=bIud+cu)AkW{OHU%Leu_4D|`ijMxk_4pR0hcDt!(gz(_uXHxw2Dsz3lqPH zYhYf+KA7IZt(GC*bFZml_HKhpFxHPkD4$8K9hBTURceQ&4uZp#xh+9;c(~D-D znYy9eSBPYt9-k23;WQ+mka#?!W|HbXBS%R@O{z@w3q-n#8ZYkI6Or6fCJ7smJUaI1 zbjv9eUpo(}kbO0gb;zuf%p>`Mcsl4qwogQoDDw&6a-8_xXu1Cnwe_MV+r|s{a9{l8 z!~NHco!_x~lEBCcS4$OFGe;|X^FINv#$Il~2mU|i-~Ynsat;fE$bRR(dx^=&07c6n z;ULzudd?8)bybXt!gPwhN4dsgxarz&dK$sM1_;QIgGB;92tXVUWv1j@@{|Z%>s=8=2)OJQhDAQf5NXJJp#$w@)lu-5tKa#X& z9r(=W@R>xrGh(j^yNW>}-m94M5txXA^<^+z&@!b&J~#8r2D07UFg$YMT9k*Cru#Ds z{?1}957v;AWsdiO@916J@sP#}6boywZPZ8xw`ltPX26+1EbPF7m={y^^c&0<)!Z$j zJg0N`8LV2)Hc!o>Z&UNkJniu$(;=;FE$JskTuFXO7lQ^R*U7{d;pkbUW4L-=uFTvn zaX^F0`OPY_?-jsI4ldr3(h|IsK2!hRscp8X zHU0P^*WPQ+W=e;}$s47TTIrY0pMWD8lI*q^sZSdloAP(bveFY6@k3LlNuQ*X1(nG= zXu~>01m#}1=|nObG1P(zzH2rjtR(4o)|0BPx#B1jJ|JFpZf<^`9aAmrCg~8bDr;>j zljdc(-y<3e9?)yhcf+3d!L`-bo+m#IzD>f1$#_6qOHWJp)TOtFvq)J;VnyRo@ODy; zTV9$)vr711a2C2mo4p_C zaZiNXg7oikPDUWWRvh_)Um%q|4FL$xwC2A)GYkaQJ#l6pF=phoMc!M@o%L?4 zI4OGMA8E1Zq|rFP*VXK%bWwT2wYT%pINa(;qSGz#p_X3Jg!Z!(;lbv%#1Q<*SIkr6 zW4R^!oy&WgW*z=SdlA=rOz=kq+r0{GDUH+tIWxJHIV%S_fAE*@je4a_7k2K*q`l>w zyVQ_Y=Ggs?Y@R{gVCy_g&mciXCmC%#!b~to1!X`;KI;I4SBQo?=w3N#H2%RL&nkm)?{8d!gpQOnx zN_LiurVj_4PbXmigPg%!LD|X2P$XopFv$}(;XV%j(J+(5H?`3Z_TC5RmjmY_Zwz*& z^mYXu7;^%@EAN36M-Cnc%f0>*mjAt^;kVPVyp@T~pZH+6{|mawP5I;a6TV|5BXdr& zqbB$&N-L&`B3dBXZ$Uzw_~9YA%Lr$p*S+mZ{)vHN+ou34ixO9^`@TP5KewmX(|kf= zjh^Y&c;;e~>p0h9d+qJ%_}t@zNyZcafhEqIch*QYA_52Y07rH=2{DC=SAGvhB%6VE z?6UC2_mq3)GaYk1MtC~JAHUDN!_ukT4$ z5>SyD@g=23+UWUDJgpfn|1>=IUvi!(-M>Qgkkd~pbxpm&x6d}yuaHE|tQs|=y3j+l z=3d-jCbMd5G%!9X->_BjVqT^Hra>q3lWbe-Q=W&Oj$_2#7|y9A+XV6q0tOB$9Eitx zrR$(}OE+mZoqVeHX3HPPtXEH_f(J4xEYJ(Rbw#Haz=y|Bg91_*mt1o=AKey{aZ_>8-$5DU-xE5DqO$+*qjMDMcGih#Tk+@pmCLsuEt3#Z$S-R6zeZfusaFK4R z(aTtq9cynDX4*>ak*kEoWMN*QhS;I4!fv6)J6$th9;=n-e&o# zuP@+aFv445dNTd_073eujxg|$Q^uAB5%SXC-LuYrAbNBAX~&)}a8Pto3dOThG&Vyl zY%5)qq)L$%HBkM+xe%$>AsRBRUk$cFkJAQucFGkG$7}c6vGkWgF733#*;0I5R0q+P2qD=I}KIH!qtNTIOB?0Ba5FBWXY%CtU zN!kmYD2i>G<4r;Tp<)Yj0QnB(Hy7HJY?Lv#Ww|@lGx2oX^9HMQ>GGsS_^^N3xpbW{<1lnMI1 z9x!E$o?dv9BbYE?EB}L}iNHRSr_KNsfCt{$lzs|r9Zj-yPRq;WoyGIy#VQUMx9zf3 z!!|#9JONp9wN`KGHdDufA!|J=-G!uaj`-x7&Lk(J801C(dg{Bz%qmoa+QO=RfXe~V zBv)wzS+m56Ikxx{*TNeDE)2<32NdPPoKp?d?>GzNHv>$mOrM?wD(3OCOPzN5ba~Xf zq#j{ya00!bO+F=b8_C&p9K0~~o8YX1Ud9XqM! z1$13^`>BqFaj`d#2Hn2O4YStal5Uk>fbHUos(u7)^#Ukwwa9^dSP@6Pu+W^X2q+~@ z^*xB{^28uD(2ifuR^Z~i2_74{t#29(`p9499w8jQrg3!dxdfm*e3f?_aq-G7;Zw(q zsnBbW>8T3tam7~HfS}%Gh^qRaJA{-Ff6lM#vA3GA6Bv>WLM2f~8jqM-zQ7b3A8H^D z%7a$Hyq?-2yXODNq}h~gCk#z#n<@uLfjWMRc$xaQeX~?ab0dtRh7c4x}X@Blra?-ZYgRK6fM!)Fdz1FHRc#u01jCg(NUw z(?a^orltC~aPhy)lEr~}MHatv!~T(v{6E(3zjyEd&2{;gH@S}u$~R^3?ij`B#(g~@ zpf|bkI63-@b?Id>kdIu;)5P{pBL@^x{{;I9!~aty*23M#WP>8>W;T=M*cWI^p2M=1 z_x^N?_Cei{4h+UKC!CXaZbIb?uS|aoSvQ%Z6!RyQrheTqyIXsoln-7qhQ*d}73GQ; z*50&Nxzn%SKYWO#0ZQL>t-3Naxl84&GgMh)lj(4)z)O*M3)+XMb?++2*hA|v)Ff$O z(52Znn9*CR7TL=O5a`ieAlMLMxDh3i5h5I%%$JiWw-?o5$P&so8}yooeJa1S+NCH3 zwWAO3=L!sVCV-Y$1YORG@rjKL;8~CuaJHm#1!;_~ym&sY=0m1xBbKhB3 zo}jx9^bw{UHTl5oSBC2N5_C2NUn}|)#MTTPA5UtXMK!nOL$+2io9eywyruzHJvoor z;AuD5lLyue>eg`Xbb|{b8*O)xgC|Gb9p(^phxMW?-hnv+b@7Kl=O++sxisO*OT$zG zrY{3I*Di=SM$+z)>xEssoyu1i;QU;dRJ5UcU^G7;={NFXa*wz#1)h7VpBfp#nzTmy zB{As-G%+a*nPJL(AAKcc4cYHAko;WgyeF-(w|Enr9pMD1VO}=}Z`7qELHO}_#Q-4! z-6VMo`%j=(MfpA4C$T3sk5I!*fi=Bs$1Ji>fiTUr;DJ%>&bTxvTVlF(B*VSAyMzqB zPA3jHMrA=^hG4+fTY+71JWhA3rTVHG@l`p>`!B_ z`G#}QJ`-c*Ys0U@dWR$+-hqXR4hUBV31b#8N=mZQ4)*0BiG+eT0qVgY88IVIP%9Qk?a8hMdDU#wt%h4ABTM>d|oE?^~pl|1-8qz z8G8Sxr7Ofg$ZOxC_ztoU6|S_a@Q<>-WG{V}}F(#~PQj=^Jji+eu`iVPVQ z8YUE67?e1O8iQB~nFtl>737uS6$W7bK;PP=4+nF*+p(6L@HREM{gluX@Ivq*FOZ{g zw>J&`a90gg4OK%*m$X4@pAB_IYEg1=p*}YpGQ^|+n#==_1iIwfPJ^DsPy<^w-H$eEXIuNZ$<;qjsB_dyLx7#+T7u)0%Utj*qy^sd5_C zUU_xx{oTYNY1R`vG}Kod9R`O4TB&)cK_grHgx9WQ6k6w_Zd9A>6w+4<4e%8ARy?Q) z6QWQ)9KMh$U=k~8fFFBns~SGCn~8bw4zTb!gpTx2UuoJSwy9Qjwh(n`q0@5dtuh5e z^)ybmY>Oqr(Sg72hVaz=J-bRix#(f(Yl&PFN3!MdpxtOheq4u(W<+=8Pl?hs%-A%v zCf6eq{&+FG+G%<1%Ud?lhA}1^<@`NiEPI?dx+B>KXQiUyW2k9b3!Vtoixr-E(Bt$- zB0)#d_AYojh3!5%9Jn&4yU?OeXc`(kb`5nZi*8DI!b`?J?~3MUC$)+tAx;Vy=@C$Q z2vEGGaHU`vr}xPxeL0+|r5wB;c@NoCu-ywyxnx_nvo9tKbl=vF`i1J&f`_7#%^0=V zzCvWy*P%Jp1Ykhh8A>Vr_{p!Rsxb0a^V56wJxE^87Jn1vOvAyc+X1*8KiIp`Z@uye zN!R@33U~L5dC*0*3M@geFNi9`eb=A!v==|e-7v2i0yTy#UGh*WCuqUSGq-Q}m#Z80 zB+m77x;jU8o2U#^`_1PWp*wv4vk#4quoQdHyBi@@;P?YX=`rVM?bCZMkO57^n-P$< zef4|jxb<`c;asef8zh8+1Hn@_09;JFa4}ZeHF%@~Vh5JPImcn~ANBNzBhk({a$>&B zz7!h%5Dy_&eX!%H+uev3O590cywTHv&j&vhj39r3NBM}~Y%K47+^gX9#Q1`C_{I6b zLh?Rg`fSUC@klS%i2W{_B@q)LvTxxg7Q%EA+-nB*jy9()C^i#tZ88Z(Dp&~Dx69RT z2!g{Q#NQmui-ctdIG`An!2W&9c2zwX&g;WadP$l-s7JSrqGf9m` zavc0=6ZWo=s+ zI@RY!*Y$tg?FS*Fj0BTFj7;byh(ZeTJSdhrYez+e>bafV@c$n0@F)PJeD{(aqAMD5 zLo#I~nX6|-%=0SG@~Rsm9+hZC_5&d{^!@te{vsvg#8K(0&qL^kHNb2NOW3929(uWw z$=>8@T}S3;0e`ee=85?!)PG4V#Iz=|3%dmY4SHyZb@iZaUUP<8#Ih0Gnky8E)92=5 zF6COqrQ%h(2mMCr`QhpXOVlGIYt#nElaxjUHx0HjfZ#1^_e{Y6ohE{jefus)2qAb- zFuQ5B1y*c~lel#@Jqz~Mcv|PaT=*bEW;Fovc*iT&cisBq7U?9dE_5q1G!+RdO4#6+ zVWUy5T}_j>L{o3|o`2#3t4 z*DE~1r0TqrWvSZ2?mw#J!j7DY>B<3-wGt3ncVMu1mP)F0(9 z&Zt^R(bhG)R5pe>*c)%!e=RzDIoW2iNuOTsKxcbGN|qaq2MR4vFuV&C!Z_h87~%gV zv>-0(X9j}nFf~w_Uu-0xMR^RaD}HuQ3^@c){>E1poj-)9T?Q<)Q63t_5jI#VYxap3 za>Ew+H+ut=`+l*y{qw; zBPm-0xdQ>c<^`aA1$gY%{uWv=hjA?cU7vwM3#5MtEvo-5w7@@_{0yc{L@Km2?DrdN ziy0)oyaS~bKm~^B42Tq~Ace0`zkXs4LnI^;?wAd-s~_npTBL6Xf5#xd$o>CE*jGoz zxor931a}P(+zIXw+}+)2+}(pV4vhu~?(S|0?(P;exJw9<@S2=^@64Mw@0_(*^aq9f zQ`NQi{uxZWp%}+4oM=x=cB0anY#fK2V!MjkUqTCQlC_0b0?+N=-t>Qu1So+$iBthj zjxKKhMQVL5sZG7zyq*5XM7By@;Wbvlzd(r+7x^c2Z4d-2X>|NRAVOqpPwH9!d)Odk zzMou)@T|3~IQ$e^4 zy1l#j2qACA6fY1kP8OaMlg?=|nfBz(cH=GZRm=>xUVA)0c>ps+1IK=9Dc)OcUSPGl zz4}rPRZEr@XeRqJk)Ly$;izp&lP;)=m59!}dUkz*^W05*HM_F&fm}$)Y#4FV(d%VD`Rh5hNHo3WT4BZ%vD7G;L67o6yVo$h6_9dTO3qHIp1(mJ z=~a&<(?FyopqJAUIBq=d{WvNE(YIy`YR}{-_P=K-GLjZGe70B=r>qGzJZ~~@ML&xq z`{ei|ER$9qgJjZcc1d}EK9hYf_{g2KN=OwlojAZ{i?9~^wrr%T4FVR_BTtF*=?q} zTN=wKDxYFP$UKQ#Oi~CR%OQ_gO1d@v%FSNAH2^4g1-<+ZG8W04y=R+MpVBrA@+V0W zSkuw_-Qik5f=1r$>exv7)Z!py?rpLe{2Mb9b-bR=u$+tjJ9Y@nW+``8<3n zN&+f2F@X`=)o9nzET}CRhvL7>@tfy}eKncAmekI8EveT;L@-D$YUd%B;p-YVZ zK@Y~I3e6=SDg7&2P**rbj}{BzG10)@Z|K+7Sezw9Ko)#@{r;Bc`p>==|K%w5zd_Ym zYOeu8=)b9zuyFTcF;p<#k&!Zx4$D!J>Vj=8u7-owC<*?6C=Qn`Ue||zBD9GruXlRr z$3B{`G$6omMZ^DfRPUCIz~Kk3wQ=(uv+aKV2llhdxY4tJS^C$)Wc3B zW7fd@O-Z;basp0GQ1rjMXJHigP&`e0Gu-at)8Rx(j#V z?+o*wr@5_K>@Ir)zU_E8m#FSlFIVzMO3z}PgWW9*tiL!!sn)yE7qSbkSK8;p?Uc6B}`5}j~jG8SdMDj!7|;?9nJ&Zcd>>FdBR#7isGA}so$n;T?EaP~@G z@+tDCIn%Q`1Cy8X`as8DR%XOdXA4)rS$FCn3W=2T#FSGUm!n3u0je9=(*h~8K)Z2% zy8(@QT_%Vnr!38kw+{13cyxS)`Ro)q7&hiKU2_ z^+~K zJ?#BsApg4f*VMNNOkKia#TJ}wkST5~M6(*JP_`nO#$ZHOt;j`J$Hs0_)vXs5RWybD z6e*bD{D|TA#ug+j&G-}I1ERAaft3stl6H(>_kFhORNL;uk6&Y25chRSQiN-~h067E zywNteo&>mJ7}DqN;^?wfh8#I;wFk&IC{?0;DMwC@l(Y5izkYo0fL8#@=L*i8V%56$ zDz%+Bb2{niqIeK2u2KN@l-cm7BQzT3xg6Lo|h{x$TnNj z4D@v*X9#-Z&qlWnMD;`Rp^jN#e{(zRI5bj~6Qg-1oaP}gWLhR5IHK>RS*xBguBR22 zW-5^MeN#F>p$I*jS(i>>NxS?xfdp2tj=5@W;*0lkofrI=wzG2J?iP8J&bpb`a}K-7 za#}0N(9DU+z4$G1U*E^wA!>s=j*S<}#RL)DTa%+?;W!dD;RA0zJgYClQ=$pha8`8n~_Eph9AsM(zj)Y#(SZQJy>D7*3BZreYV-M{)Nc@u9(cQ+*` z02pSsc62ZYSh#{Yu^#`~#edNF*YpEN2N73SYfA@lH^+aoKMZWuM9>94gBjZM^J&dC zO#vFx6kc}u6~3og7a$IXIb$&w*I)Ul5pWWr-%xAK!LC)xzJeVo8*;H>sRI9$AC~hkmeVEsgS3 z>wlJlPH6Ky89GTRT0G=wHZLNm&5Su}li+(G!$C_Im~2ou{F zgRImT8^*iPwa<38ZS`DLbyWOdpXUdxj7G{Y1@P3^pV`WO4jR#RWrs2tlh7ay?|PwD zAS=BXq2Z^}boW;aaq+{GyCL7d$k^!T$LAD_NN+Q;4F{7QbeT1l%3dSw(RjoyB1Ds8 zXwSl~%H3jv0OsrqXvU6$_tT^-)LjDhxg==IZpcXH*N*?qYsdc#tMvg&MUYEpP*QY%z`j8m(ASx1-d)cV;)=m4KC({%aKo<&5vHDI9p$tMmXgWJB`U@fi~qPqS~zN{qC zDurB^6H0yE8yDk7Vw!TaceS__8*bEg7~B!?k|*Rl|M<*V-LJ?WpN1c#{Ptrg!N^d` z%xTPHdh)hko?4ea5@m)b<0fyd+LkV%nqgt%hzc+6)0+d4#t5H?EA!b`Hnof z6QQ`dH^wjox*%C|=II29>;xq|u$DVsm^pDm{Ih==sckc6=^dpva4gLRuSUf~)DrJN zh}>D%Uc6&YogIrTrlo%Mjn4x4#O=!w={01eCoB0E4$L;^$$k6~dJAjD?zzrO^Wa{l;Vh?cr&-=2Nqn*3GgQkg{ zq@xR%F#YdYdz0oL4fpTjB6X{=U*uZ`{ZOM(UMQiV$;K?P__PDuZ1yznPW)@9il1+% zex4Rk;$yvghCHrd2J5+h5f8F=NXYhthX2TOwXm3a0NWn8)~_jj{NM+}5HC2sz6;G~S%X!Dfa?SQyL zRaL{m7d!LYu7-m~V`Ek0?Jc?3QYs^THA8j84y2glsHf5QCL9e?M&QqO)n0{_^&1!w z?9ZgBv)(10Opj*HgN14#@ScRr)G& z0Sxr1EzCaS0Q?$elX&$iX}?=lmsy#z9#}4{k2nua(WT&4?=)-dd}m9j(;S_h)=TPr zkFH&4<7Se^E4O7bEu6dI5VYjcMt`aqOLA}=%%>t?eu$7(!|O0eXGsi{N4nz?r=ri2 zQR;&4w;LYZVOn+Gm^!u5)!8Jk3T$b z1UW#nuqtAQDRPc~6LxvryB)#$boRL<)H8G1xIR5z#bd8Eu<1H4!gu2Q%+yA^Kd!%k z8X!~DEUz(cE8mc0Cxxq~c%Q1~d}FFWNOmxZ%xMV|Zw7_86G28YL_1jE)nB`jng>X; z^5HdqK9h7%+T-lgeET?2yW%rJpvnX>pz(MverSe0$is&L+x2vaEsFQ6l(>=l*;NQ` z7^gx|%W(EG?D`*oZnbus#On0#zl(&Agl*;DB!tFv2XpB8T`iGnsJ2jwQXW9*mPmFhqS#2_}<+?q!Y|{M* zkLSSjT1Xgwzh6M}0$}C-)reFtKj#3~Kyxf0+?sworFPO8wsyDmT{3E$A_Xey3+?{> zM_M?+Hzt$ub<ntz{zk6qZ`Hp~AEYKghn zE1B8=%-q1FZj-;RAb`vNWm889K5g#*4!3UlErrSx(I=16`ExSRjI~28t=K z$2wS!kem5tF!RiQdA_^h{0IG`;7=H7X;MnrB25W(8x2ZIlK%i)pe+Vci}T5*2E&Sk z)!*A~Sy@@>o8yx!*Gn({9w-o~eHO^7$}ysthU8alky_H7vS3uJCdn(L|1+g5_0>e87Yd=n3C$8p%aUmU zfm9VCdKKn`_-RvnOt+i!r^ALS*+~+Kd+5kzO zRW4C~=0~w3ox)WfTe%DV6cjbm7T0*ZZs^?RAHd1up*#_^A4W{}Z?)iNb&p(eQXm15LNJvA=5NMi}h1WYHT)0$SeYU0=)8(~r#d7JsmTpFKdqd4JtvRQfJzbZzf<3YVp;qlGAU7M&C?H|R(}vZzQ8 z@^ezE2VXO}*Jw^{#GF1=NXk28cLCRYd)$$4)te0pjy_b=wsoAv2$r8SuB)na6nIDB z023`JjDU^eg05+#8w#*=7hfGpT$zb8ZGF*Z z6^AtKCS1-CjnFxk)%bTa@n2 z=flOolt1dJRA26-69kGFUmrRl&>i?R!;;S~5C~Ms+7{u6IYNe?VX0;p2!-psQS2k* zkUtS1k?f0^1P!bbD7+n&nn@m@>9h2@My!oCTp|%$Ik0!=*)`Pag1&?y>Y)iK**Zc! zkVAhIcMdQ*c}6Be$+Wz3i%?WjGyp0yxR0;>g7E)vOMZHz1dCzy-H0y4Ocz9gvq!-+ z+~D*2V0PO!4QtKe*&}?^zkp&R3f%L+KY<&3e8#QYZ<4qxlkm@DIu0c%RDylL^zS}~V#5q% zv=SkwALiBtNeD`d!#?2pcb`D95e9bV!mbnr`_;gXoQQaokqYHb#Ty6@LV=QWL8XY- zNw|C9A6JKcAn*@3f?^{HWbC0sk(P&j&_Jq3h9!P|Lh%o{fZF-Ez|K>3Can+qAcj<* zfARW&<^LP}kBQyPHINdOMSd>^S00IA(hmzA-ZQx@rQo6*9_{ZixPRt{Dww%~OL7Z<3jnN~6mtRmKg8_+#t*gq!w*$g zuVs2y5llM|!VeW!rGh+#^_&BghOBM0^MCLC*vou5C>|RH6ld3zWKX!-H?hiB9+)F^^N*7QMM`6HI9kn}t!ezBDfzVSkq&%J^`2P3bHVA_IRpyqTKv}q9ZQ0#XAmR9n>{)YJ9R@s4WwOHA_^H0_9^kbf@;1 z$IEj|Y?MdM8AgCZLFX0VwYihQELK3DCWkjIaTzYbPMaUt9TywIBc+fco6`no+uo&j zhQ3;&%jGz2v1%gJhb*!N|I$9Ge&@$nAZYKT|NS_pu3(ejwYij6Z(V;PO)KU}l|Y`k zUta19-`po8y@E2f1uUwrHop%4qhjglOX2D+v#P{ulBL@mOx}8lvC5XrneS4rM~)nf zaz6u%=W)sGTT!Mk8C0K~Zou|QCl$#0{Z!Bfhg{R~kkC5B)g~NaywLYoU%v|A;_tt# z$paIn#a57uhaQkhVhgwlI#Zj7&z@~UYh){icj_@ZzJ zJ;u}YK*dLulE(AArf(NTMmb8KSvUNB^K&p)O2t#FjaT`jLXz36%{e@~O8S)* z`W}-q-0$R)ZAZkR)hRIU-QkSbBSRv*^ch8pSBUtty|l}A=-y?5Iaz7O&p)Rl69a9y z4qQOY|83p=&x1gDYj9#J*plqOvthtKfdBsXzbo`2)xQRT*`2HAqH^zq-w8Zw7m6Iy zVoFQr=F^szT8S4mj|XQZY4-q3QQR`BJa-{xjZ&gslzwgJaIi2 z9NN7Q>h^=3?zO;?SWlOP^kmSkFwQbrM5F)*Lz@+8*8Iq3t;IvWi_=_m{!UI3FMf1) z)N)^Pp-93iKj6ZcT$^h0USQvhq+cH;Sj@7JP{2Z)51)=EoIFv}!)!)VmjAqz6C=Y! z2@QJ4{nJSx4I5|_p}>m>**g(k$cn~AE2>o~R(98oP3$33efEq6n@|r!tghfmJqw`- zlUb^-nnfyeA6#F@`#HIYc^fjeb0@+r-A|B?yGv#CY^uqoDUMg+xUEmR-N^**UaiTe zV{nm8kRMtlJ?DSGJ14Di{5_Yjw+Po8_NB%mug-nu`~2xXZea-7!e3pb!Z>96=;NxfHt$VHT>V+Vz4k4U*vaUxI!VVWX~(HPHd)$`yhMQ7 zZGzpX|LB}{$wfwyX%Lrr^x}ydwz4_4+yqu_Jb`E2qKl@Takl11sIO2Cs^+a>MXq~F zmmf08THaGKn^DnRps&i!Og!am{~|D$C`XI9VL5R!3m)Y!?1*GVs~|YwB2&ffGG6Z^ zFaG!^*FK3>ZQ~pg0wNv^>HPo2>)>1&2s1}}W^=GS-Oa?#mKhAcGP?j=og5up0nGme z#;O9$0N|bG^55Bw{~{KvD`TgRs zEQapNuKDN`!)TiDXx1_ba>D>LxgT(s6dV@r%Iy~p z@Fy#q8I`!i71~`ku%lA}uiA9_i~gXkI( zn5b9IC>B-Dxz5)&Qf+FRP4UZxPO6n@&P@A99rxkTVFh!|M5&5<*e=ToYcIq z152#oGHQ15G}SC3QN4=fNvMtvwrpGAy%qk~T;Lo}feB0j;p9#x&~~^;WnQ_r9#}%l zK2D+z4Rp;zy9j$}KVc?`>O>y8pCs^?|E<+|t&3tqWs0n}V-Wq>!3s`mkvnXALZP#l z>ahfH^yL#JAZ{1tFh{Hd|M7@y!AeN{sh|;c&ULh?FHN<6$vK0l(4odGl&H|FW|vXJ zqFltBIZ>`8h3@^sg|U$z;iuu^=e`g6)D^Ih_z$onAVkk~9U<^JqUtp^9#h3jH?>C-@%l;Eb);=UQ8A`s}^JYVFg>hn?8E*A9KHA)F zz5%*M(_cA#gas=l8{)F#P|M>MD{50mDz^i93f3O&bl_-B?DVt0soHf^g=t8l z49kS8T^!6R5F%7U;nQ{b0O#gf-1J8A6K_?on_3)fL$5iC09!)uv^d+lHFdtPX;Bm{ z%2x;>whMAHSnvmdO)Oj?Bp+wxKWhpU)yjU8J)B0qEavx{cJJ7IIFM%t#HXWA=pjI7 z0ManuYmb(W;HjFJ<5_SbS#VY*TMRIwZ1tl$E0K>Fn1S`?UYK;a}m#0bR`+hw1d$FUZ&ES=K1wP+%b@AklRx?EIJl%L|*ivR9So)Z_>rmFg#^JQQLz4v)fM~GM|%i zUaQGh??R2WMN;F?Pojtp@8knOcp*hA1hiO8e5hR`-Wx35KfYC3FexJ1XK}pG^!k;# zkDRP-QCQX0$aP{*-`K4X*AI}o?!zVW@2Ad;MQ@9yZ3GgDI+t;-x_O!DS#tz8g8HJ_ zD2H5{oK#3^`fCk#5JlA)wPHm&aa&{f6KX_obpznMda=J52pQ zS8l69gZQYAxs92dt{4Zuy9_qaIxmXsg{sfGdz3LV?jXjo+I?zu`i9Wf===?nCQ&K! zTJqZO?XL$LBb)G6A){yT-+nt@)+RRMS$>U}8jxbJJQm;PW(;dEo;fM>CarD0ZzJt} z0FDzkrPj2;d~KY2H`wvF5i6dnf6~N^tU0j?u}+htq@fx8M7RM`fhHr?imPCyw_UXI zt)3u$CyoMh2JzvE*j&5?gaUF%cr9lzb({s-$#ug4HrMT!P6kANiO2Hn{fVm;Xx&*A z?WKblV*0#!_-& z9_W0uCW3F?(rzQ8^U;wZ_Daew!}MCn@?gR6jHsF*z1dKgbj4!a!vQo%ac| zIixlu!;I#QfATcEs1Vg{2#YX6hj4@n5)q6^#3(+TNhszd9GN0Qhsd(n1S_Ick+Dt? zF+3e&4x-;9pCMpW?wMR6uxe`(qZ!X`7{xfr?wudK9WYBT@tKXmS4B1;R{leL7IUJr z)EG;<*)N7lJL_Z8`)){H$7_s?by`-a=5@X5S|n)@fNgka`I>dlZwGRgOxQvO zgh;TbhDj+CqCQNTBQkkF0v0eyN5Nc;ks5(W2~l=FfwL?#YXpS(V21-R3svDBGGNjR zMCbt^N74g5G*B#*c{U8fFzIFjDIW?ZNTfSF^PPY&7ZM2iloS#(StNi`WY#VS3SpE~ zNMv$~g!H^6rWe^os@xo8B#oZ*ErFh3Piy#L0=iJ|R2t|vEy^~0K{-tJD1tOX`cZf? zhlEscN2Ea-WJ9pWjM-l-QVsxNfo@vhhczL0K%|_Q5&0le9l}CMD3#H4r7Q2iTSQRb z9&uTU$TQ_I#$(+4D5(fU*)_xp+4(SlQd%3Xj9LWO8dQsn2?yds1ATyWNrov)5;>Lu zjah^E2nrE|GX#YnVTW-jrN!Z_$waCPMabEPT_AL}A=yZUtI6Lr`Vg2?A-Kc@OdkV4 zoDlVk(3I39jTIxr)*umG8IbMa>%%HU;Rdw1^yzRDrE~#ueKt&69GrEs2p=TnF(ezg za5archB-)qau|g}ItjTRR=8b2cn4}v@;Z)Vj8u?vSmBn~I#r|@Qo05{;>k#apdsq73xL(!$h(6)*ml|uxPW$Wib0t6YuYeUjBb9dNtY9Oe_Fu05^bxiK*THpdDtZ z{Ywb0RL^)FOHQ5(C4;W1d>g1LL8dNKR2XH9x=uZY4$s};Y}vbcdCGjbBT|9QghnFx zvw+c;DWuT!1*)BZKk^M4dzq{J0hHloifn7IMWNpw zDF&TBR0B=S7v2{le@DuS`mRel6I1XoNroa@?UBvyg0LqanW_H0_ynuZu&G@j2B}DkNyzp;gUxYE25<*~shS!+2M+J~0??}IV zS`>K%ViQx3PiF<0m|KaBg1ThM!Zjsr+ke8In!)(Q+EMeJ_VMU+qzG5hSOHptMm(nL1*k0@uMi-1J7!zRipLeMK|-Vgwo<}lkVwN`H@Sb*xSqM%1xU6#UgW)DU?xvU zW_11j$3K$;>2N$YU-0DM>2CpV>3`hgB6ikpF4j(>ub)%_*7l~a2|2In8UJmR@E;bD zD%cgTD{CpuMEFf;U<9)tr3e9}h<60#wu-7sIYfi;lFaHdPdpD=_t%_DXvSB6nHiVu z*|3j0v+rs<1-;n_$}3%1J=>qMeb0~PHiTaMo=_ngltCiE2cG`z>^Df{j8RTTgO|cU zDs5a7iC_%`5={KY^no%>)6@xt-IZMwDD!aPk3AfA;e?8jHt(ZJx(qWP?^1tLld_JL zr)dCF1}J>wHDU=lo2&?%aG-X5tGAu9Qd%d*2*(J3N6PTt_E0OP1M?c;833E|#z_qa zo^iI);^Ric1L?$y8>Y!ddQ6FU2|Xy*)8aKwsK{!Ir?`PG57v#!cEVoDwJP!iuJKA}U0i|4d>s*HTE1X#Bvrq6Pl9*f zoYBA}>VlyUe{GtL;L73>AsqqR1=;})0pTfZ++^aJK$Nf60}M$2A?A9#2ee#s)v`8BrL(hVCJzBPeuZo-a0;FZuXfvHD1 zN=Z-IETb;dDZT^1tfAa$g6W(zUO&jL&7!~e+a5hL4T9t!BJDVqHCj>CurC?dJz!|t z;s4mhKSBy%_#UY%=bR%_?Y8o*g=r|&SCgRS`!{PisTQ!)7+eja(L7N%c~OO3*a)j} znY!oO)cTE#GhGigZBhDjnYB7XkA}#rMOn2E#=FO!fFp0;2;YZV8d@vf%7b->gR_;9nrVZ-cavg$b{8MU-nvA*GzLDtRk7%)Z}} zp&;c{qjsX~TT-E0-ldhA*0j4-z*XMbU#x1*rVkwW(f5NLpO>Ogc?=nN9jyV^SCNKu zk{Y^)ryEOnPtWxuneSrpYSFHff4*SC#9d~(%C0pa=pvf028Id|TxHV9j&x}Z{qS#Z zb8*7xSat^RJHl#hJAaA%)L*4A-~1lo2q@EBGo$BoEl?kWF}hhB(99 z@w@pbN!s)9!N^XB0;qYA=~B$hNQXP0TnQ?xXEKrQ=wst|zdnoRu_WsEC-=wJjaqzW zpMG?3mK)hmkt_%)k2;K1+;ED7GHEeXLZq-Ws8pOS!R?i+WCahp!Z_(@dH^~Z`gG?xk)14~YX@!s$;ka1`> ztURIb>>!WTf^ekJg*+cy2@0BT-^S&dtYSMOqbzp^^f_~kr;(pa_EpmDz!2`s1AV7i z9A({^3326tPtzc7g6keAONj3>96CSEf5tFxz<3B+P5z>l3Z5YLf&fsv1*-kDg=-DK zCpkj;jc96Q({n)(@-A#Be+zIMmvBEj@)n(+HVe^Xb0`fh7&%<5h8DW2_p{mMPy78x zbXWgd=Cky1R*qa4PchEc5{Srvho0$ddSW-ITJxhvVUUq3&_y-)bfVU9!=s}s> z!G-Ri%~(<@c4=Ms2WYe3L=c$WcV@L1{rZ9MA+*mQ5o*X)|B9lG_T=;z0@n^{$bVNO z|MOrN%muOo6Bob~O)weAUd`=)dg*2*jex5L{Gl(CHbBS~QQ>}+Pn53-meiQ!+NQGQ zZ}z`d{YkJSwxkvablk@By2{mvN`;RnsjL@xfcp^seJN?A*ZgwJq&xfE@#*eM$CsCf zYa9p*(waahunE9dVr#G#4zyn#Y@rfFrJZU)g<9dZJ1u;J#F@>({) zjinbmm4>*3%ZA|h4>q5t%C~TI@Fwv^nZ*e7JlMd4npEak&HCMm@Ze@XuU!9 z;9%gx^;{cZv{*uc&pU0eW`Em(?A~wx#)QRY^s9!0i)E}ZPZk|U#NGxK=9ca(A6h-M$;y^ua#d;g!1rZfeY#U4wm5HT|WoV%GQ=i_E%l$9r zj9l(SGVpI!`t2mBl-#UNvbH=J;HWl-8uLr__||q*XGT7ra5Bl2JE0D09EL;UB(mg- z%4VqGtC?U{51J^1J=Io=qH?`q{CzQlo_4u0DtO;=cERtB?6tIB(RL%Bz3cInZeV$g zkJD}w<1861!I-K6?b8)8{ZGw;)*cdN$W6jY(dqDa=eP$UJQqFAZ@!qk#S>Eva*)C# zE+dsfBra8NF~jD^qGMdW`O9kJ31Qe5&kV|b+~70}>D6jNKUD73YGQ|~#>7op(z4`( zXlYheYlT{x>s%GfY{WJF@RvcZNP*$^AT)HJ1L$;Am^Qej5aHeckj{8IKWrfxL(p3g zDg?rl$Ud|PTMsFQ&@kpcV-8f}wQzmV>sL0U!`O%<5SVu%m1c_P*r35CGAAUB3%JNf zk?SB*!u21C;9B8vuwe-O2@cvt+7I}XHPajAYWOXf>;EYG;gpv58$Iu?6Tq85B3mk9;Qv&Uj!AfcTQY45s4g(e=&4?}~vv z@?P`XU&K_b%)ecx6aXS>J^m%HYTYjp#k zY_6sAMglEv+ZNSl1)eyDvi|vCVTbBd&6~t_s^k5#p_}!DanI7M8r7-YH1powxy%(D z`Q&Bg6a@3$UQ@mYkFSbI?Ita-f}^)|b2a0EY)>Yhn3qGE zKhdD6rb~XcriOeMwT?}p3QG7`0U7eMUV68p2-b%T8h1+z%9GWq5A7T3J#p*QRs)uh z0hC8xAosWTry_Ynl(+fQmY6^CryVgLRq$C5o|KmzG2!xv@p!Nr!<9#OleX9so}l)` zoC^A^K8N&K^8_y<5^vG&UCM0X6K&!?W0+nvZI!eBgh7_-**zpy`_^WbL)xsvN1W+{ z@5((qP3$8!5%O(Ht;lggsuW9#H%>aiH_RU6{SBf} z2&&BrM&_85IfnGpIH?Tr9@Su{4Fnr{Pz<4nt{Z4c62!_b9gTVoXZDQ?0>KELwUwwp zrcW6?>?0}*w2t&IxYs^ly+73aHO-O_;qUHH-hb=^UJYGeAypG|duxY(pX-0)s{i8D zGF9o}eXox2RFPBB?B~~(fC=L;ZKcXbAXu%7aqt|Qtd0~KFv>;yV3lv>cR2(9G5Kn| zIjo*3l2za|{V%_mPg$EE1D;`6qEjd> z55aoPe&^M$OFKB$GDCRTefAaO3^+2RNjSU|VFr}B&D?y9Vu|@F8j*PwWXt&%BP{x} zSoF2O?CFD;?d3}3JqPm{dDqbdM7?p_vfq?pBlI8qI040IRm5{Dl>o{kn|EVV-rALa z_lnzzd6v^%ZOYbdQ3!8B_nBBbmvs^4o1J3qXBT5Yjx4L~55JkkPzt_ozf9%9QD5p| zQf}e7i<#sE^lpOGw@+S@a9L#;ww0DTRwt>Iy6==}%W<`kZo zaZNd3-cC$81&WnmC}?7OLOFFk^h-5oQ}@^+l4-CB6v-?}*@k+*nCWUxJh!;AT@!KU zRU&qV{$MT^+Fh=JB63lF#3~4_Al^;-gHCi$RgPQ-85|lB5B3cIP~eMRmYSpzI>r>y zUm!lHi%CFMqJ8+>m>?~R70Hd>Ci9`?2WkG=P=pP!foP!*aIx{v-iI>c$*Pxg?`q_yjaG48Xi-M3~bHA?|rO5eVyL4{c@9soS? zaEanU@LzMN{c6K$>$a6hb7nbE%3X13wzMqtBls58J+08QNuLmv%S%Y*iGq z1|`KgMbsq3IkVvplM?60swE_Jb0?S#D;l!T6IVTBy!}3f)d=$-`u6MxO#R(Pw{SI1 z%%Q=NO@ZN1Qc#p4<-wau&k(XUIfuX>2_^!4=|5I;anJ*RL`r&%0m!ghzmWG|OW-&r* z(C7K*3SL{?&Y@HJ#0{^X1nJ)Hymt=u`yQ(%W*M9(p!MQqm|f4`P}d0QXn28kzo4ao z-^9O3uo91Gi8{b02mBFWq?0&U9)Ni^ynj2675m2>1r99#E2LZ;oCyIoIRfvi|AlOm zyyAi-g$;ZGXBQxEWeo_6E}PdO%ZZA14y2y;OOn>cGPl~w#m<^@P!#)??x=VLukVqo z!zPZxe$u}r6o6zFcJ`rMxwg`mNbzSaDQS7}yU96!xO{l=gmBmifP|GlNEnJiXrLZX zXEDmXl!HXl=E$?lGX-arv-MqyeZ!6y#pu+>DnIj;Wm#s(rU|YeOTirNtwAmT2q7nz zzL_Y}+s@G9vOyM;g-PuAOs+h8Pg0|fzf9kkz&2uaexz^?B!Al4DXELEu^hr@#DH=C zB0>NxpZbY(-nwqfr?F|P$eyW>B*>&^sz%@TJqmW}hI6T~0$+Baeba^GzNPizve~V$ zL}JT%$@$;dhfyj^X5_|f?4i45x5wAix$he}raMMwhv)2yExeC;^Vu14 z^%+jEE<4`C1~~jLO;wip)g>j_TSUM7kZwaJRbhcF$n7%oawf?n^vHMdYA-BJG>5!p zRxE%hP9End>e9dvtP<R350PK#>2UhN*mG2F_L*^&XMLB%3e()spid$-E^>n&_NJ?kthPXyk{Wv7-KphND z!lVSb5$(aRx>}-v;;N9B-gu%@62m{xVf6RJQi9}(%z;0~&mm{&C<>IiQXmo|L&j-> z*9Y%qNLP5I(|@S{fH)$0D_OlE12Hlvl8Ob!S4;Rle*(qrQ_DFf_{N*e?Y)HD;f5Rb zj6O%oKh~t}+2rh*Yq5oOs5}!$l@jN*^tnab`NYk-B0u~Q6^^<~lDyV;cYk|L{IeH= zIKauo#qAYT`QMa;SxJ9v`++Zt)cyS;=PJVLoyM5&3xXqzRV1A2a#d9asE|Ce3S(oF z(w&R@I)1|ZC+lUim-`ZdQAvq>%iL+3yrkqQ^XA_3_qgB7-FJq-C+$)4kTT@=#=7AI z#FdO;zB;2HrcJnF+c-$rZsB@At-nVS0#!GBX&e07jNh(hK%@MJxhyft4SZ0$7*YZ@ zUj8cA!{)VbONn}@}Qs!BcT0^he+VayXePU$yS_z@U>0&&uNlM|Pv5+pu| zruS&0Z2QR0VoYVkMqS?X1}tNNYGh0i+M2zfypuXmbt< zUh7&Y+ok?BgDK0_G?8R)-!%OmN(}Ow$BIp^%Aq@&!sGKFYZUL53BS%Nut|~s)o5|a zoPZ^yO4%TjT6kQ=NfEMP(L^6i>UI#Q?6Fa7g!5JvP3U*cj74L2;zCb-(m|yKr{RKY1`U8rvuE4S}EXwg@tI2Z}XOMNIcAv^H=D8~Yp)WzYefWW^YfOxj=PT99^b%kH%csM7w&)y!F5D?pV1t)oJ zFYa;`vv(M2&RUuAjPly|gq$e9s|JrWzWgm~S^IA(~^tb_2E#LpL4X;v{l7R^kx2AG%+GvLpG^Q<}I4AStkkZL<>OKaVNODYw+Oi?h+uu zCAez{?oJ@MyF-Emy-jB3yXTxbmASY0!R~&$s{iz=wf1@p8(6dtfF#~vrKlfiH^P*z zfa}h-qqy@V^$^mmE4Rpujw+l_ld)ZK&CnHtv#8Q6qcB{Y(2$g+9yw!6CRWjWvs_*| zms9+qXm19Ntz!>v&^Z# zp)XT?z^vAO4iciQ7m6#Wt(5Ud1H1Y1CM-;!j=SAL*>!R;Kd6dmNo&U{7D1<9*4I0G zzNoiRSFN)uuhRD;BJ(WNQqnB+H;Yp?8*gX58ujY7?red6!tyun@aw5t$6KvcF(c`3 zbf-Qgj(*-tvecGqN^Z72ioAMxfnm~4EbNKuR@B|9AUIx>~9#9ai6rR4)d0{A~z;gl=22`QiE`pJJ8>K!y7=zt{ zr@%~G4oPgo8}dZ*ozN4fNa3Ej_0kg5%vOf6a>$3^Q*(d`;Z!ACu{qHoFkhn&d5=56 ze0Q&Wgt2r|xI+Oz?>o^rf+rm`3g1DBuR#a-hd@2x=1A%zSRBcG+#ps~F3Ti}pbg>5 zp{i;WX1z(D;Mnn=W2ckhjPL5Vz%DwJ8m@MRFVc?16Sqgqe@6MTZ~o|i1Y2@T-gN3d zEcJ-Uii9Nf(=fJ6y#)sX134f;ns&&o1s&$~h!@mA0=A_DADER#T1zS|MLSgKn4pDL zhzP`h4Y*Uq4_xNkL;1P67Ouj=*yZ$ASRH5Mjq6{gKXooWxN@LIH}l6v_wV;1aS(sp z-uid)-v8d|WI(PzSc8U^RJ{RqWTaaV%rb8!MZ|Gf$pWZSF&IQfw&q_M1euZSg4s_5 zzx}6Wr>{1qgGolNuFcHZJT3s$B@gyrpWok}3k&;!IP$OVcyutV9;D-S9H>Rw%2NU= zM%eR(+VMS-Sj3okbs+M9f!Qm0;9!vpyiUr9)RLenH;h(g)p!#(GyU8`wcZyhf2?lA zBGlO8Ipm{?LW!jMXqKc~PM29XD^ztYd9$aCrFJg>8vD09Ui$b4>Qe3eV##B@?J%P> zpj)Nnv0I!(om=N`D-%bh_&YXXjt-f~DN^>R6 z`Y48g%`uoz&kh5QT2%rfFS|WZ&eNf0U$L^ULM*DKE?QfXiI)DAJ0RV$r{y`fTWw?s zyyiYbsqrPc9cb{)wl63dK(rXflDbB~u9*61;@@v!Qc|>RHN%i?rt(>zjAB@=x}{bU zT{F(3P7_s|O5?OICWm1LMJ z6!}5=dVOZ-oL?n+KkD)k(v4+9$?!DDP`2qQ3o`>`uq`$%u(;GcAn>v4Y9x$yg;B%0 z8un$0+rARLZ2S`Iir!lrebT(by7if$?OEefYZioUFyu2ful>juMtBE@?Ne&JVklf1 zfQoDhj@O6E9sL76`*xcrYCR)18k|m~nj$VP^@yU9EXAhLfIQ zcIu;9W4X4NQM%L{Y$(90y4~KuZ%uL}bF=c17R`L503R zkRcwjVFEAK3M}Ob^stfQ4a9F009E}Q8stCi+zCPf-cg^6OkFD!O_E+AhV7y~piHwL zc%x2F!NNfcd&vr&((}$Sw{A!>{e=P;JARtG1+~oGKcWDCPA~g^i^ri9HFmK!eGSl& z0R`y%2NF>G9rvuS>Xo-ks=^%QAqHxgaT^7)T^J3;2BLY@W=nAZ4?Y*?iIhI!3qy}- zanr3}l8r23vlW*mM_xfn>ien8#rp4Swx@H7{?E_PkX>xV*a`h6#P}=Cqmb>4yBC0P z^RQ@;%k3=z$mLdpe-0VuCds%VU)`#O4f)JX!s5}2>gjkpmLkl!jgxQ%j=qxULhQ^- z@3fV(@`jjw%+4(}k!U(0&(6z4pH9Ki<_%klEz_zK@^^**>jTu>>uacz>}Kd7yV+Q# zyf<~lw!^gQz`s>cf5Gqp4-es{WBCYrv5F{v{H;JysRIPQ^@vcS><9I*ycyA8GW}_L z8!nAx*^V>!59AAblyf-8IQZSeC{YjT*7Ynh4-4$XBN{n8{PeH1O7*-$~(Hn11a#J-93OB-PpJTl$J&5@(>1wx&m*na~Ru z;)_zDoeGC3yo2bcXo&9?5{yyJ&q&G0g~Dge$S52b(~&$j|LqpUzWdJT6GaogPW`lb zrfWb31(=0Xjyot7f%okrbeU4^R!L;POUoRK0hQ}W{%EveB3~Y}c(biqJ+WKHS>8R- zNtq>d@2NPMm=js5IN6V3(XcI1uCl#fyrNOQWbYlhfzo`;g&$~lh-GC&XPn45KYO~x zC9G-Y^oXjd4m6fVJ;TUMsqg${%i6n@c^?6)h0#BbkLrIMA79}v(5^()?YC@R0kkan zpQ{qe|M5&*?VljOwBIZBfJrRb>J=6U?28~35$$ts<|sWZ6>z#M*)aDYkVw?x{YY>m z2pHRkmSJV?H>aa6%t$ezhtMQVHgqW2DmH*AywP%7ILLt+w4TzkqV=Jk_v!X*tJyok!2gOojes-mv9IKng zRND28IWSOuf*CJp31rM}l}NaPF;-h@jb&9EaXH|TsN`a?$Exfhra_IC46W&G(2q7r z;iSD7bBc|eWfz0s@avm5eG4(5YNc0s6f z!EPBR#mbgRjEH)hf2K&|r#zuvCN53-3O38gtta#JlQ%c%Ch5wkDCPYMamdyq_jJ{) zz#nQ;!$qDI?4}^d6;O7}_OtbjlPP``{aeRwv-_>T8@s>6QVr_xuJ%vJB~6wA5r3Hqnx0X*+*85VJx z258Be8g;B0vdk;nRjb9kn|yNJs=R7WHAu>_~^0`Vb!ym;n9sf^s(3@=Z3$3aOx7ZDpUhE-z)(7K93 zBn9Y8F+sWAbwA{2?q!Bv^6_bLVh9K+3U_KD0TJ5KEt!iVY*q zF(&!84O0?wMfw3r558(Muv$dOllw?Qdz;8&6K$mM94tJKMAOH&d!uS&679YeYJDDt zB(MN@f#(%oc-yss3um7m=UoEwYOVqWuHGWB4dtvmK!_0sAgB}tt;`0!={1B$mQF=* zCNU*e1G@x)Vj(z%I?$e_(7a`^Wg0+YH_|?oO@v}@**tV+Z$GKOr`x#^d^6Gp6j{a zPF_~8gI$2l&n5&EVfAfB5`R3})W-NoV;tHQ(MwsPktq|tytR5m4Sp5X^>z&>E?+dY zY`5-iX@7fRl;tWwBuPfQ{ua**2ju{rlZpPwq8rBzDr?CpbPHKy52aeiP7F?0IkW{O zP%qDdTVCRnzENRmhZ;9Z2FO$o%uR?%1!|}ydArhC zuBUz8qu&>gEpIW$X({;W7Wo}oy~<2Rt3M&C&cKE@B^oNmo-AWb_nQ+QLZzwuyBK7*IF-zwfu>vdE z!xmzLgJ#`|4WN7zhbL~`C6^9s@J7RsUFGRW`WS9Ka3!U>m#Hxq4G@t{N#)B{acOM$ z_(2?l&5h6YJo=Bo3VSam=elh$OPQhBVaz|IkCeJ3ByeEv8@F`&obQ=4Rxa){hM-&(J z1k}FA8BM~wk3TryV6JW2X7o>AAiq6R$c7*5t|Z<+NBc$KT=mnf6ZyT)#IY68^n7b5 z37WNP$(LFB`)>jvGV7m1b2a@O;LMCW;}fj3;Eow6VG*BRQxZ~Ype2fqptF`P%ADd=HPX`dk9TbPVL_j|HJ17sZQ zC}tX4IHYrxTB|Cvy2O<-V&JWRMvT|gPLwmKTZ}@BlM?Jpg<|6!E&D+1Ci{)mIyOts zV+{KnS9ycRHe8*`_Hp*2IaCw}7E>T?ow|9b$md|j^H#mt>o)m$v~2u~gf6x2vfWJD zf-9Ic$sa1p5NAHlXN`xsL$p{+=y)5HY$gjdy=GQ zM01|`>7qEyR_ijvd-CG=1>E0cDF;3uVBoIkQcop+q{D!-baR3QZC@;}Z6aHtql(n9 z9T`tB`yDp@UH~Vjj^byA{knGZ86s+tG11bA(8a9% z1KNx$;PaRHeBicoYgrdj@MYdh(PlvPGuaV8t$!#?6f?J- zO#1u`oU-C0l@!~}X|t_$tD?3#`=mZW*FY)XlS%m#=#QZSNC`3K$q8}F0Dwt(9N(41 zbrqhsD^FEt73o{#HUE4$RwDIAqI3ioZin$pr2v3`L4&k|IulLkf<2CW0AHbTBFZ7S?9@yVic;a-Y>G#;5bZG7ve!GGCm79)shQtk)(Q42*IYg?_NdpKC!A{$Dd2}A zx+X-rQ5(ZA%#gK*r0Brm^vw~!D>lh+HCKxp_K>A-PQLdLE(SIs(-z-^g1l_!Bf8Y3 zVc`xh5k0YK&0yGoqF#@p2Bs5P6d@emqDDAX&~P9!c?v|RUU(}hh(?YU#=9&9XFUN1 zye9+~1+mHb14Z{XEfNwU42OvK7G59e!8sgeF9X8L31-l>x~#6h)&^{oJp5K>;35H3 zAVBRe{g2BO(SIFp|3|oxB*^l_&G~M&G*{FcJq03}N@ zMW0_vr(FY9Jd6hOhJRsO)(4EF8@I+79D^mWFA4fnj}+;|f=m`4kaRlq{56_-#f9V} z$=6OFihQRJlSx2Lq$N?!#*8TwHbf^TIq0^k{#Yah^8<^pVto6oMD_QIj@TagCv0r{ zL{c8JT(`cP>_9EOSQGqP{b!J^0)@_MHS5tkL=6>CCUlYDCTx>V0S2wLuEZh33O<## zOHU!bV1&L>nA&GBJ3zabVOwcF-fh{Yz5z3wYJytUHfu!JIOoD~Acu5Z zILB1#zcSGuBhQlt6UtrYPt(K3XT5Xo)x~c(s7%fC1tW2z<@P;6I!q6emALcc;kup9 zNh0)cOl?D=@P{RuMN;6C4wpYF$)P?i7Nka=Hb{2n_>hO6Y+*f7sOy?Fz4J0<*&uuq z<XZ{SZ1{j#6++IEZnsahK01G~e4WWo|RO<=JH~%vBf7pd;4I4JCO6@x!8)u zzTh;(AF~ANdQ)uIk+{o~VP5|Z#+Mee?L!W3yHg;77)m(YgJ>}L$&D0@7}F?Z#IUOi zDQfRP&q&S9jxf46E+0vteE5hEAA+?cjB8Asskv*ATESwP{NN#P*^XFr-nmrikBaUTNimqbke@Dv(IQ8N(KcOwdn3B&N5*v1 zq4TZV(%0(zO~P@9Tz&u4~sK>k28%)gr({frP=;AMr19{H$6BHyL~V4JZ+yByy(8?iY*KCOT>t^hT3VSB@RjIGtcw={ov&?_d2xfWy2(}+%nwn(`pXV zqz}IJr@RRB5mdW3&@?k{mHbinGjxQg9`BU4uZ3Cd;aBY9V`jzXrX$b7YzFa;3n@s+ z?JR<`8}zN~S(kXQ3Gwg6@Fh-m&c(fy%4;Si`<yjP488UE&Z77)t;-7xg;pP-3zC|_iwD#-Az++nK%q2|yTIIl=z*q6z zRHA;t#*$fyZ!fCP2WoNV*bFTy{p2n19oiDz=Zh>McU5~b89 z`mpY31l|4~);1REz8r)2B2s_ki~M^69mw0k6y*D(W)7kSgDkNWj2%E(bN^LB^!Eo; zfAfYl{<8wHe>D&sw9MggKk0QyqAs$BOKI9Dw6A*mQ5V8`CZr(_6Jt=tP}|n~*n#(4 zyZKo1)j#k*ZV%nCVDKS*(S8AbL4E{%C#(Ia$BiN1Ixp5v#{Dh)`S}eVHov|IfCZ!* zu|VQ4WQ52peCzf0TA1lo5L}rNQ$}5;Taf8y4m3@I&i2B_kv@wKu5^Rgp$;sW_aVc^ z{w(?hMQ*LLj zz2#_!Xi}KbWj9Z7RjQ^Mf|$*$A@?)6MAM?mvS0A}X2mqs8SPo?u^OuyKW%AKTNFq2 zL%z7K7n!|=gjGp{FPcYf?$UH|uX!ZV8H`_!%*whv$(Y;vEgp7;@SwSRO|Q*^bXsgB z=hwi<91o4k@YzUPJ;z2-qly|WG5~Spl?1a^+3e@qTzT8+fhRsDIYXJ)x?}70V4UH?ZW!ju zT#A<1kAZefS5+w1h`q^RW<=p0N_m4bfhC`_)*ej9?Iq>wL#lgQL&Tf=fe9(vweAh| z^2vD!vz|Z8PGKG&`EjIc9V7MfQIm|u%_Lhb%Smd?N!CuIWv;OWY|}T}%npuJ7wG5< zE5r7ur^05y1$q7X`yjsMjW&Vkmwk`)YZa92aNIXMFsdkH-SDuAJ#?^pjg7hC`x`Nk zmYd=TYcy}Y>Yl_m8k|&9#9T_;Hgdx2p>{5U2?u_0 zOw`|HcTYOO*B^9|Bk_NfgvGH~a3Uc3(G+1hRcquT5RJlkRI}~rn%yXo9V|fLAeF!1*T6^gv(kWV@w+Q994A+DaK>&b9}F#&V3^>SkiK)t3#s{y(Ypdn=;~a) zyg51C=OFQShw^tfrZK-L#{jrxTS!Y$BMKYlEhgaj>_DN$pbm)YC6NL71km>62RiBW zC58vGL32P%7O9~Ya4mrQcQ95u-j6xBgwh0Uv${Goh*> z5GD}2~opQ-&F-2op-h$8`obs3r;mRoTr-bD-bwjxC_SxB|>+kV7?}UYXVE}Rc97uXxHIT_V z^46?5)J{~fZ>nsZm_jqLEL4ZsU76dPTFzR5jR$NQ(QyJwJ+$ zSM;+@jkxjKuBx^f&PvIfA*ZJWuOA=oj&^WgDalFg%tQ4T8SflH^X4Lbi=t!*@CDL32*VGfsiayV z*hVUPRp{zf4ansYa57ooU>YtuPBDVS*`##!Xr zI$TJ@KC|Rn0E5v~#xlD^6Kj&vZ0FS+Xvd}6%lQ3aF}H5+E%MCQFL0BeV?|fuKfIK{ zaA$B^*%z-1Sl#NRyx4aj9acjXC0#r@iV(l$)>!Fch=eYiCB7$G$k;R60>ot;bQ5EG z*G~3<-DC|JQHJtj{?GzA5pm-&KNA^;1t>NQ=5fu>x2PlI zT$q_yN{|i@iB5Vt-i)#wGN=G?r6M4UHN?YoXilzhoFc31tW;yZ3rh~a^=U!%I*qyf z_v&jC7X7yhGALniu%f{ROGFj;NF0o)%JRj_K<5ZMMjiZ0qD7FSyy$)bWpZ8};h^*f zPDrF}kQ)?@W8GOc#c@W{L|mts-6%hi4M;ysNdEJC#SxsBrd<3Xz7^ROPVIMe@{%Qt zVUq@;M30mq{44wy=tLb}dut`B(1 z_PMs>;7fA^e2VS$Sc3DStms8Ni(w|nI|7Hy8zzF2p83W0F!krtm)PysCO+a&MUR3Y0qUDL@bj0jBR16i7+*uJbP1hwbCyD#U79i1GIQ2wk>PYRYF)sHPGWRY;XP)oMvDbod5~;IQ%w6q10a5` zJo-8l+pWJhmQzh(GQX)CTUXk^g4f})V`47^K$+@ctj2n(milc-wYO|I)T}tSO`|v! zA!>S$UT;ooL!QN?&QaY{)M$&ekATkl9AUXec~KG@InqJpIMCRnuJAZiG0}Yx;3^4S zw{+oCZ~|r$B$$f7+<@dV=m(p_DGr}UbmUX80Zz`Y=NLJOCLg?1s7>pA#MQauA{}Gbm%Nj!LLg`7^!_$ly7V( znZ|Hi?9e!FI06o*kZhOgaN5;(;j~t)&gQ^*>@kKXFTjz0D?$7( zp-{Ylj@iO{5AKMexGBHEkquN6^dyA%J^%IvP=Q-!0f36v^N+=A`mev|peZACyN)?WAW|i#apXcPK;aptIE!qOybrcL-eKfOjI8FyXpM zvO780? z^mM4=Uz#c6Fdg9O)+jA6CY_F(yVPxYxxg|WeE94&qwi{=w>goPZ9Ms-h{*}r7`U$0 zZ8#>o{HgJ&Lf^f!PHi* z=rB%xToRm)oP%w5b&Av_nLMf|?x%Sc4Y`?|2J~-LSbHvYI<5kdm|6)a6+W$Jn{NVT zerQjP!<1O5;@ANs7&u>SCU4)kPdhlv+qyfkHk!qgm1@XyW#4Z$u*BNGd8>!D=lfNS zWJbf5`Pa10;Lk-iKWNt7k=!||i!A!ftfMl|V*8?BrArHvrdsy)$ekaqa+%P{MdN>& zTx6pm2N|&sGt5_E)}VEOH`EBF2dVw7IF}cJM|@ATYJ5n zdU?F(-+#l~QD@|8(d0r^pjuP#-9iJUc-E$OSgNYy(O&d8VhTInhx2`#TzGL}+=bgUnPvOVmmDWx<8G&3%|$O=PaT+D!JQ+}c$3Dqul6dzFMKp`~89WEgu>!SoRrdHW*>WRl$9QQ^0Mw_+fX4 z7gKhD7Uz&Z?aOZvR9sY406d2t(?hb*(j+Xh$Sqllw&-@kDb$Ab41~tt2Yzr%NN05! z2CLH!l&>LW;u~UM9HK;>$q()b%lwW^s*638!ze8c>zNFlxdjyE8`912Tn3vd7jb5k zE=RdSL1Y^bZa5-6H`x<}9O8m@4uXb1CMBsMWfzbJIVYg8li-W6A?z^Yn8l)8u_8Ki zqt;2n{(@rvL?CjHH6+L=Ee`uD2D&vJHu8Y=T`NjzrpyCH)aP@|bkJo)q)?_;D;~?CMn)iaYjb1BU;W6dI>c0rpocG~E@cJ>SrI#;;zmI?X^HMrjq;U&+v( z5wIY6XgceUba1mz5SgYx6@m!!TGAf^(z1}XI;3WyNTd(g5u-s3$E3zMW`VHQ-+}pX z80-N^^a-kr(%~pcMnGAC*Z-mk?vT=_;To8XF!-o(P;`j?^uoyDWLLkTau|*T%sdbc zCK>BbS2p86c8u5cq5^0K1X}#O9{*R^&cyT8TIQby@xOw1jejHPAcokfGs9b8N3c#* zjYmHss|liv47zG=Bx`Y|1C5&zfBoWO(gm|n2x#8(zXQ8c9AICDFmHbZOq1~Q*YESM z|Jvi9J*-}TrDytTDF7jesmV~{e_m*zD*dcU3b2ItP&86wO;>Fn(d#c-V8Dh?P=FAF zrc03u)hu$)>c>fsw~QD5l0^-e*~o7_1=OCkrP%?@XwPTGY?jnG#_O=gaiNMC>^CoQ z%ANaFqZC+ktX470)edhjnuVv zu{qy}`Z8Uc)sjVurF!D_oejlj;=k(^rQwXL zzoW-p@s=?noIE=ueq@qFt8A4Zxh@xxfpfv}*6Bj&p>D1$ewE9az?;HSOnP&0QM zdrpEu#~htfm-wm)-CzVWBpH2RAHI*eq3t3vGKqi&1w*&L_Q~>_oF{)5kfz zn4(l|TDgKb5;<&Ubuo@zQ~8Gu?TcKMPwgx_mSjC*Oryt6u=oTIX&!v@5_vl$S(@NE6b_FMhd^gMu?H>6CrDNUb}Jep9xOVNCyHZCCoj!G zYewj@Wz+p#u!t^7Vu%UfL zRPm${BS_3Wf}<&03Nqk#<}RwyIC!A$bsTT3kUI4;T3+#P%ki*iTuAU_F&(sYZLU|!*_7~20kf{jS=Ul}G zW~Qn?CuQNh*Rkk#(@Dp7pMw}oZ_-MWM_|D~f#?@kb)x=S>jX1fP zX8prm7h_0IH%uI!_CY1R$XA6^w-GOF9=rVEBhu)uKpsRifh%{P0a^KEynyg zhPqCwApcPjlaB#P%K1`H7VhW6;jmIS@3lf?r}!dK+)fJVj1^K=Y*uXG@8rz}#E;I|;P>)b^w+0gy_kb8~ykV;D7 zLQRJ+1KIOAtd4lwFz%*fU4Cx>j%eXXZw4a;aF7`{;{p-R*itYTpnBI9P6UvIzdydm zu*2?E!LXXn>b>BBuMtvuBPNKx6Z?*`H<aJ7$(@~_s5qmZ7CHY2L z6teAmwU1Ng%i{iW0Z95?=rKXYu$3wcGQw?14Qpb@>>6${NlZ4Ei}w&7Ha( zV8|OfCrJ&NCs`EMCx7Z*3!jTi8Vel&zM-%d2d6a-;t>3maYQ+(;wmepr06Sd!_;O_falv@H5$$NfvV|h%bx6BU4O`~D)Gx|6yCNP|7Q#xSCap<&Mf?ODp3*-4 z7T-$uJmM>Y?p-8*B%G=Iv5USkUqD3+${2A4ZA|`qzzF4EFaLh_PZ#~Wn$`4`K$-@@ zS*0?jqN3agLs}c%lvG?p4oWk48RWo__#`X&9EU-^7LXRHq)*B}3Dh=8eA3^)#9dCf zGZgCk0EApE_Sak{1aBuCl>B`kP>hgmdClHti4wTgS7huOzOxcTb2(gyp;6vIyHTCOZN-wW!toAKy zQ^Lo&fsq~kXf-0zq+go{ib^Xc02lLJzVu4lGsyDBIhT{8XY%RSFCTpH-O?rWZKVob zCd>O7S=$95RCgFIb(K>&J*4$2m0p61qF6A(qKhFdo^wf=Cq*#(C_{D4CswCp%T{Pt zEp{EXtP+_6tY&(IR3yp}5)7B@w>EN(3!;0{P?2+KVrjv-dF!PF<$IJe^D9iHr&*sE zD#(c6c%R5d+2vM$p`FCIQlD?pk0lB3C^jU`bk~|MwQA~SCsplpV~boFRP90Q5#@q> zzAN>!WoMBQ8k8w`q4B=`#i^asj@A(hF0Pon7FArgvHdBm~OLZ5NM*>`o_2#HhWsVpG0bk&n21IdQ# zGiF)ip~GswnvG7S<6X}gwZAvKZ{`EMSrxYWIR=H=HKWQ&9L=-`U@*8}am5sCY51k5 zX645@cN1%IzPZYSQrWH0>seT5rD&&;-4y4LChImyIC7bvKQ$%61cvbS`5GdZ; znN2SbZ(MvvhP;3&Qm+@FO}9@IE6x@r-4-~6_iKeWAi{>EV1u=7=I0Ev-GSRu?1m&( zQKAX8j8i^zKbl#JE4LHF2#7*Rm-TTAWvO$!MWxLF z<-j)-Uq+HYf-FaRr~WdCkb4g4mH_oA=s)fT|D6@~y2S@A1%dz7Dv0v;tJmWFt0xux z-IG-Bfx=*PSQ6r|>R1iHrG%&`08KtMWJV~1R&lu&#Q{Xbq>J<)vD(t~xq!V(myda0 z!mv>%fJe;7{{BpG|D*TP;pF@f28#B4vPQc$kl<(1QS9VHo{GJv{-9&^uweLYAw?>B=T_D1?ib?Coa>J(DLwX> z%0~dJiMKU^x9!HW#!rfx{dtZuPm#~+lkSr$?(0N_vrk5CTtpg0Nfxojr5#g7(heT> z|5{1UyjGTA(Nt44#b+oKh<3SjjYm&%voH@>N^P2LUVv6XTwtWp!w$C1yV=~+rt z==Wa`Ex5Wj8y4r)L7y^b;J8$W(vsVU$SEiR=V8WKpPwAgp~o+htRTNGyp4oJ~0V-r3sp~ zq7Iwx*{??&<0VTte62}Gn)yUCwV`7zvRx0UBxSNB04(TzpE-C&EqUmA9Elf0$^(Qt ze^AH}ESx52tLg*lO_6`>O=AB#kExnFzk1{T)`b7P;ZXfA9OS=$?5ZI91Z6ZqZY2y@ zPbuR3yBmo3~Dr#z6qBw{-ABP{N7g!#Hm z0N}SPwJ*u4@BPn1{@?4Jf8&S>j1`c^5=Sby^Mq^;1x zFDIt`dK@-=4PyS{kQq0s(AO|1b)1n--rC}B)86ji#I z_T7X2P55_l<&3!;4WwFW{+?By89P!!ECp7%?@OZh^{tA=stRa^QF(SHI0#hg{E_$q z(9Vn*L5tSbX~SU=?jbH%9Igoa;!7#6Q3ge#$PY(n%BT{f^$Z{rm&>{r((#y{IY10L zvf#lSAc71TUvJ70S~Iz&+8BP6K;t4{v)f-G&{*K&#{KCu^5xOG|1k3b)$yT-U{Pa8 z1Y;|95Sa!LdwSJb+A`WIXpC;=efM#P3<4dHgL{Mz9NKUgMr+uyv3Nd^yqVVW9*JDx8ZR*i zi3|f7V_Gb7g))dt+yqGeBcce3aiyf~w|==nRnKxY8D!qQX^wj!vcyX#E2t|1GQL#m|?_H3rU0$ z#{4sE?+pb^jR=ueJx5*j9NHutIK(-w`LTHW+Ofp+7Tgy0zlQ+C0l3e+oWHaXZh<$Y8ydBF8-dH_rC%Rs^s#BEMOwdH(evEw< zRhbsglN9Iped+VHXLYU1kHd^u`04Um9k(YK9A~-7Mr?7d65o1 zCaG?_BEQvzd=945+}mY)U+m{gYO{x*ZjZ zs;jhw<=|IR*QA`Eii32PJ>>~Dl8yAG&3hU0t0u5RmLWp-BGiz;vkeC{=>=3a1zz_3 z01k8WmT-Bn*Vlw_Y+-h2(tW6GO1y}mC)J6GHkjbArmQNYLr+Etr6gvd&d&P*g}S84 zfuzd9(n4tBgTWeC1U(<$@py+UDE<6Qb%}gQq303ru>(oIDP}mlUm}Y_lAe8)U;Oer z5pSZh%=Q{oUF(0Wu7AHci5c60dXe#e%fh34ozDJhOF3$jpuGT|uj+ko8j}?rEjfLZ zPE=h_KOQoCT7nUQbO6`dSObyMYaF_~jDYve!HZEos|f%PmD=E`AZFdpw(HcnOKgAt zcI|fU`0V-q=?OMKf^j!Nk~bP_@6_=-$}O8Cd&{JwL9~c-H8TX0uez?Gxsek76}F*u zZ)%xKHG>Mf@VbC)OlOW6o`cNl<=rvz8V*wE5%Kzd)!i%lby=DF00ANQ8*fr2P-Y@QX89sVbSx#t7QRcUkN_Pah}M z7dXm7Z-b0a#LsCu&*7`!lFxL+m~;fvWIvdL6xVt=BG_Lg7N$R|nG`HLL>Pr9^VoL3 zOY&Ewo9gt>;9#LDQ<#s4xvyrR3W^$R#Bsd`{G1}M4fC!R#SNSyx}sT8SW<7HQHzFE zFB{i*F_~ve>`2r%)=;9>VjS-`=gFsV+b-&6J7y3ISvDr#egP2CBu)D>P|LDHr%}pL zHu^be`*uv&Kdk1`%@>ZF-E+J{O#9Z&L;Z$lh@aMI42b><2?w9}(NYUZHBri(M$duk zMtl~)n3IFc{&T0~Fh_cejg1G^S*{(*`6tD014-T!V7#EF8isiax)r~Jc1nU3MVZpX zqCWSMT)&lr{e$W*MNM$cG8Mt><|e=V%)w6t=~<3(BuyuKFrSFNeYiVc#yh^ulfd*c zKI8JyABKrM4mpTQ!f1P@LxAb>BlZP#76gzU8=u0AmVQUIB0+m43X=^B+gT)or3CI! zV$zYH>vaG#u1Mg&jHE0Ojf4AfibeM2D_@{WL}qU)nuH-OqY=X5@2z$zukxTL=r?Zr z#{ul$7h?Z^u+rZPvE;wZhhJvX(&i=3)I~a??OQA0f*@GQ;NS~IAr@c_#$5U51Kpd? z>}2j>{Gf#cBQJrN5(Sa*AMPSwc|#h^%e&ou;esIjvYy}m*LGol|6edh7>IO~tRKbs zsT)`uTa(GzGkf&qt=V(BzCc;vwWT;xRbz#e7n%xd`}TFsIa|<0cpWx-dgyjpS#reoYrN&Ke-aArmmiuw=Z7LG@0tx-ZD71 zW)qp)@Ix&L*D#^!Co!8i`yzyx-LTZ@n4E6K_i~9%2N#Ih>o?KGdmQ|yS>debt&}rv zpBlsk1q>E{XzSW1^3`no?@y`XQO7EZ9SNRAoIz z{mqZZq1sX$!?2@~iJiv+G;5(`BIuUllEV*2Rh4 zvuzfW)>T|>?2Gy~Gxq$jf!Wp`7>x&*ie!fLJ>X85U*ptMGMex56#xKWd+w`~*pXm6 z8|~KxJB9sq4DN#-Q6083{e*4Fjt2WdAqS-aKMDKwjXi%X5`8GmdFCYz0~R`>AiUVEYneu+Y%&`Fq&7HX3YH`mL>ksp#XiL)DXhdmQpY5{%9S!{ey)D++&vZD`1 ziHYD0$=xfG4@_Vk!54-s%p;~)NJLApLhD0xMX!)6uWb!<@sd9^xFnPzqD{Mf5RHnpC4lcOs``^D8?aljywp zg!{)%q42NQn7g|Y294Rq zw(X>`(fC{G-upf8IpZ7MW8}xPo@C_LJ=eVFyc9-P=j_(`3!N|WFBFz95TPJDjjU_h z#xS3sgZbxG*0m2r=sEunUyut_`N+XMEdli7{@JLd!5s&DZCIFiNV5AC;waM_VyvQjZdBTULZ{AHkS(kVZcBs<39s;Zi>m>8EHl2x{E%_otzh|Yf{ z`))=;YjvRjk8zzvw zQw}e_-xg$m=KV$@JGHMbwaA2uOJlGU5R?#9%ZT>n${tJawFHgv>-e)4{HaUR3`VwT z>Dx8#YEepD0eeE1%dP`dJih2E`Un5Uc zrCOYsxau0{KM|bPTNyjCxrd|G%IOGX+D;GI!!%6<@Dtq{fUin}ZV<&Yx@VLt7q>QE zVwD{p=(45%i;@1s`-Zs`%n-_XPh630IciA>jtga&hV_)B;Q8Pmo~m?len zk=PYviXWwkXEa#X6CiypS9UjNjJ5B{Kd=MI&=B4F%{@4LB7!mo9B;2bHVKY@J>CGB zJ|H3ufOMMtmgN7=4F2mRCn^1QHssAB#|l+xc#cHV0G1$T5Rxf>rG^7;E((|HGA71auGow>v7gvQrC5T*-a zx#~xyVS+)&|1_0a#FEL9j1`&$IMYN*h+S*)yfD5^_E1-9^=P+cv&$t>Ni$fJ@SL$A{V zw6G!dHmk~)@9yhg)kT{pB0?zPb+F@Sa(A2PQ67^>wXBdTg@I>Rz3`A=LM#zYw!REf zhcwhq4#S09+%E%J+EC^-y-_lzAAjkd{AP)vRNLa+q?3j&!LsRIF+CgR!vo|hUF>0wfB#lMQ`s;RHG%Jsx z#*1G_snvkhx%j~KuT2xy10zv+Jx`0>)l(uhsdfuTc^3-Ra(pQD>YoVq8Lw^xFV7sd zgdi}mFS~u8X7UdQ2|oVFxkJ*@6is1dc5nkAL0oY(#?^|0d0A80G~Phm5dzhTvZ5&< zsiam-$fdWar?BjdYjo?mC#gepG~Qw-?aPt2W~HWVLaF8^4M?M9qUmW6hs0M<-(vAZ z&TdGVq+4$Ykg1-EBmKD_Z<%kP{#Y8y z0s$?cq?_MZuBUn8_satJ(|}=WD8`gC%?#2k zDw$<74cC?HS64pP79qlMYwad@OjGpO1E@JzOSSrZ6SZW>sI%tcO;xpRczPTfyY%E- z;A1Y(TG6#~%Rns?ON;t`R$FM(jM>R@fCOHHRDUNU6AMCv!jpIfIozPBT$zYra>`nL zan%Z=E^P-JI1g8SAuUK3oO>HO+2lRr#KhJy;AYFYScI^4A8%7DKI5c8o0i!tmbmJ~ z@URq2RMdWLF)Ca*CJ6@r4agOJ*8MyS5OH#0Ewj=;$K`2xQ{M?!AQ0l~e!}#m(xecV zC59PD0gr+s3j{Ia3r3cybO?zhVb-cDH~ZPWm2_sUdypzZire%+C_dS23(T%^J$8MPKgCQ);7COXE0OiwfJlU90TKG*whrGqlfSwGeWs zs>IL|WK=l=l-o{Cem9JUDiH!0aK)RKD(FY=YL|(O#us&ZJ(%x;=R>wX67O5l?5!AG zPn3Etb(dTp!Ve88>kyhQ-&8ILVzvdn1i+pl9MA$Qer=UG@cJL)<3e2GINCFlCLOqv zPQ^nHOXPu|9lJ(-G9v~P^TN}`juELf{sHo^Z6K2y?UB)84^pXx;Gba+BOdt64SR?h z6E9(EX_Xzap$^TCJ&Y5f9lGbXR1A!>f*^4a<`nn=I&Xq6?oc3(vKa#u`7UVGaD0`F z&_xq!H4Knq1Q@IdAQPa}NVg$0J2U&F1(e`KYXc%ho(V?+2su%CK9C+kX!d13lM&vU z32zdWufx4(pMV9LUzEnT0~t)PXY&Rv(jTMYz{+&i}MMQJ`bs1nTQWvstsY$ zTi*R%Tm@pn?!N*m?!zC+G~)kSasP8+`i)FFDZW?SKd?LL?{|NfT(Yj+yAk#T$2UB3 zx`@+W&~0=j3XZLw$#Z0Edsrx-lu}S{t7!Jb8e?9o)31txma1i{Mfp;>Qk7I_L=8W3 zlLRDmEM2=czywSk)Ps?j$OE~Pn*dyO+Y%~!O$-=1(HWffP8S$rwS8lFsGW3{0( zcT&tSu~DmU`BFS$(b{b;1U0cQC+t4#x)(hM6SZg}c0Q|9=1unk?$%1|(KO?$NVPUOSaz$V_GzQVZmi8Kl{$P}6-Vha z|8CoI8ac6s?nd2iq;7o(Bkx!;y`L2m%{3R(VGUyj5|Yrw3bGtrnV~k>W)U(*E_BY+ z)SIxW`vza&{iPX7zYdLaU}INwv1Pr!bUE%jvU)l?v@;V z_>yOhE;>Oy=$@!juUc$jt;#IIL|guG@D2W?kS?R>{!k(LBSlJ4KHJRlNl6+_QoTnk zys<^H>9mTOiqG*v(3H%Hx;L*zRf8=QOqj0wXZX(1O=&R};8(_BWIoA7GINAidx4Yd z#n>%P!k6_aRA5o%PxQbu#hrYh_M9&PFOXkk0^E=~$?hQFi5aYvMyEN@F=0*&f~nk@ zcoMJWBVKSa4?q@GHg!r!YL*xRVy1brqhh8m`7Vv5o>5RXSR>^pha}p=PlCs@`R{^} z?X+US*X{Bi=t>n}>++#J(e&7by-)@faCf~(1}T}}A0W(qaX%BJ$HX;>D~y3+P6-vuf()3-y;q2QfK6}1#qEMv;!h4SsLkIM9}Wm{rv7-Pt?F7 zr`jh*&KOeNNnD$z`S1UZS*S)6G0>L1Rlqymda&R~P`lml%Hjv&MQL7>j+#T6Tlj|m z>!>reQ%ag8cww|y0}IwTZfvr@d{AN|W01j^{G4z$OzVM!jY>wjruUZ)j?F!oV>BRV z;rn~e!l`9JOyZD$D0zYt=zLpO+$ zc8347nt$f;zXh-Ib#%~Ih@b?&UjyMizf zwDu}!MhYO#li&IQa#zGf8i)$V#r3R101M`!)y?jbj+VlAGo*!0ni$l~)S7Cn|d}BLws50T3v38MUXh2f=-cYSZ zViirQ;e4%itXHsf2$QsEo3;BYo&CxtnuWv&N=%<@!S4*7I<&OJZXNR6U&&M>ak-Wz zO}+N!;@{eTO8n62F3UO0i|vqW!)IsraduQKtzt;FNTPQd@G{`exX--uZZTY@4{_H( z8<$>Lu7RPxot%+PgXB3>`z*SJe0_%3aK6|`*<2JUFDdOg13Psyh%HQW{Mpf7Qfu3{ zK?iZ1iW~~nsZHY1Q7LWyb}aQ?2HCNSwml+hAKLEwRO*>?4Rd6!+A@+O1@H87hYDQp zLL2)URkM&}QaU4Vn?Pe*{wM67#&laRGi(}cva8s`?tL}7QGPOfpwhzm)Gqj9^z$q4{ zc?24?;sH|5b_y4Oa6#Af>mzeN<4-5dchs-TpYwUbx7A}QJ~nba4hg0=amB<1Jx(5B z<`2s>M4v!8V%?ZVO7FugLge%_ECv5qibyoR)%qZ}#nOQ_zG=OyB z$0){Zk=)GXA3+{fxXKjw7lsUqi>yP0M};9{34V-{V3F9R+S6GHl8{vkRm?doCBq50G`Qjv_Va3WCvKJ!3fZu`Qv^S7PDV#VxQc~37k?W zq4;=<@II3bS8-2B0Qy19A6YPh|9V4|uy8byw>7jga5M%?XDW8ac7n$L@h1EGZuq}= z0YH}lk&^CFkom~D&`45cU&?@GG*4_3tlHnrrcs_D)NNmY|C3iuV6x8O8XH9hY4j%5(QMUk^VCUMYM>4h zT-|FtYSt8|DKeK*YTQELGikP(D6)w1;qlH*$k1epHUqFZz?|{YT_^RZ(nTPo-2I&J z*qk9V=xjt;Yho=lxB~!_AbEh6FjR00a!(o7zeD#G;v=#R!OvcOBF1P{q2%$rPFKarc zIoJnzKM=w{!AfR=1c{X(dL9<&9r6g6x$sMD#0jSm&G|JMrQ#M!Hj#*ur7FdqV752| zHqlcj>@^d54Gy)8=d~CqgO+0-WHy;9Vb$#$lG??lh|sdKULzH_xewRY3o|JZh~}a! z0W7mRoMN$g(Onp!9B+~70FkO4F~sj1O6Udyd^X`%%p%hEIZ~{*0O|7-M9V4= zr!O$)vFO;#?{&sZCPd39V7Mas<2IW8UrXn2Ll|K@`~Qqoe;16(-`lzp6mXGjp-yr` zG_YXkqGPX(4?KVkuuprv3BZ+8=aaAp|w_=NcGg$;^Oj_FWGwha1YbWB+1Dqbc5niUhS>%5{1@-vHS#9oDnD5 zsG9K9-fR&mZ@D{YlL#8Un@GBIlNDLRjl4yQ^HQUgoa9$Y7f9ispJYn;Tu2!U3t-l` z9vyTCK7hMKZR+8|aG`%IG{T~WO~fc3WWa5n<9@v%&F&CcfyFbMNYBoBV_?&-7^$7w zrt0l&!)9OWd%n%~Lc;PGBEk^v>g;dJSt)c-7<-fFf>60)eo|CDL1rdl zF^_vt^5Jk17c&=GhEmQoRR}yfs^5H{dlBQuGF&a=#!^6r@$Dn{DzR_w1Kz3)DgE?W z+;SGyQ|P3mYxjMO(zp*nUiJ5ifLzmC+f=UokHq>&kGO;hwvxtQHnkC5jGb5bB zXXlJ06r)Xvw+Q3IXd{dn<|8FYC5+P@O~;9p_-R8O@>gU?kx7|W5(a~F3KP_k?u>>; ziSqsIW#N_)df}1Y{M~m+h_~c{22UsljX{`1@Tj>ZedoYM;((?N9PB|y`sWx@8*Ac+{|8Vz4djF#jQeAtzf^)si6CQ z9W?_eoKSOA&rXs(;l`4@rqEJ-(4J|o!tSeLuPSNwNs@?4geo^;Xq0BG?q%c#j zflO#H!wv&c4PC#;=8fWJv=jZod^X33Y))ci z%>w)!%><)O(tVnxnNpiQntnkrJzJFa2?*9j-xkdWkY8KA4t!D9e7NElI1ToUge(Ux zy;JcQPNb6oTDM&N-|J@5jn?3jFD;|Ul@Ll@P<@q1d_5aE3M6)p-&c4w**5>FGH zY-gYK-|u^V@&@>ifI2(-W1aE;Yn>@r8`zpS+u4Yjm>4^$0_HV?|8v^|#Ejdb2qK2Q z-9?TCpM+WqXat_pfRKVB7f4W$BFBp=pc4=~n6Kc?81NXGF1K9at~LW9L&Omh!sBvY zz_&x^ds^2|763-V)k|;l|u#Pw!B}5SKHI$9)++{vu$4)fCqYZ>0_(4 zT9qa`P=$sW%9h@k;G&q2O{2XXV8b0rJ$;LL)fcJEj^;MJ%IG1SKCRZ>&|)(0Q9vZQ zD=1tgWuPia@x6M4iL_K}t%C6ekGio;=P*UOx!X!BlI^~Tb`DvXC4-u=H`%B2EWf^Q z$FzfHl~#^JtFKI4~X0TXLKFm$#~t+N$RnN`iOLVn~Zz3Au_kMag$6k+~IH z4ftx?`j_B@yI`#c?zC5HdzN%6U2gR0lrfhW`Z?rF9Q;vN*RQHd4F#zID8yk#Q%pFg zLkAZ<9XD(lNs$*kehS>d^@l8Lks3*!@C&a~dr@>In>=)w2V$`SK(N?@=1y2UlA}1y zpS{4*YX)mBHhPRPVR*jK`g!g0yE)q5e0*7`{a!)-1D$Ch*nMg@83Xgk(?ecGg{UdW z;gLn@X0Mkaie)^oD_0p*_ohJZa8=sOXG8plZ!8^2>yzBT2Tmq~ce^bTNsn>VX*|8MUzJww1U&BJxSNxcDEi;tSsCo>`6`y+dTE%PVu; zDs59=d$N83p2}|(cx4im2 z4t?8F%d7>I$Lt>=*neMV{I_G5f{CMzg_9GYDgC#ahg8)4Z*jnXjD3_WS46AOfzI=j z^Jysbh5IHKwV!19_(GG`&I?QqnJBSx);m zndjcuV-`(Mem{I5{Gr^@!ysjPbK%Y^_5@M!#kP@q6RE7ZJ??=(tYkWlF7Cq z#o>H+QZD_;7~7d4aO(WsSbdZUBO^iUT;|Ar#w0t4G_}RQ?W^|CFUR8|tEX{dC+byY zXVpC=TASu|D@*VQSegf+D`;x_SPa@^r0!%DL#R9anGVv1&$IJc&2a#qXC`WZPCPKp zp*b*nXOxOW!&p4RzeL$gf9H|sFwuV&$dF>MKa?0Fgj}lVF}ZVP9%f2lL8{l~9Q*jr zg04A}2vIH?6|&yslqtJ{c>>JqR6TN3H?I^uAiG_+J1>_5ySW-{Wfxuip__hP8rZ4i zX9UL}{kNgrH^xKBXx!}b2H`HXSm|zViF|gn-P~R&Hmj?yvg2BO89Q3;xfOwUc-XN= zO~`2;w$O#y`0Oq$1U8khDEgJ}+J;U#5nP^3ag2S#{?hhK{-BuPH$g}tC7`C-jM<=} zz#CU+r*x=Ino#^>4JX-9qfK)1z!UN?;0u>zNL}pWn1IOce1HD^W*9+O0#xh;_>S{X z{Cb~*TSK`V2n<3^H=!do?6jb+(LB$6L|5V?c!!Qa&W~DwYzeQ>#_AaQeGR%0_nX*N zVyr+G>mt&hFl`OgoG$T$`M@Ima20h-+;EKC2vtEeMR1f<52xr6m*==BzBI?Y_AcvV zQ)-Tt6H(IVO^IXcsubdMSf;Re7KkgsL6n^lNZ-=+pW(@};ub#QSiRv2H@qRv`L-8w z%`tk*oJI>{EDQGXA|y^mkk})gekgrIO0)+t{3}=F3a@Nv9#Bmte_SpI{cE#Pva|kQ zN;uNrVFQ4d|BXETlQ*!^*bx5ZGkW`H0K0P?sZ16UJaFC+`mQ>yG10}IyKN~e0TU$} zV0=!{xiBeW)Qy1O$$nuH1;`vIvX#!iC~)Gu_5qmbWUie~Y;d;$bn;Rb5}l`j(1952 z{W*K}ATMkhWR88NFy*>_+!XEY!(|ZQU7~xoU1GYI?D%cKdD3CtKxyHEmKFifTmqc1914$~y1u_K+_OHowWvV5~ayC^?L}?_Y zWlg0vPNiX?q8NSLvw3S z8Q>y86OP$XR7Fq*ze06onk2SXZSz4pe9j*F_%UwQduz!#)yfD+Mt>j+S+UuYoCA-7 zKAGWk^~aae1Hm*(n8OL&3C;XLuoN=jsb?8DYW>D^OguWLE-HYh0%u0Ot*4s-YmGi? zTj-MsWmH2z!{E~1!HkQl`zExuz?gX6nFUm_x11qgBABKHT*RQiKla<%VAY{ z(Bnfx&J9ojkRvoRl1nv5wpdgQa~G%HFQDBDalRm{59?$9WFoCZ@>VnZ&GE4ME7=!@xd}|-&?^Oap@d~^Bl6GDu?FthVl{L&+vuL zG7DUsGY;kxbLu>3+HRf~H?@M1+mCNs0;6wol>V3i<3K3;%`G+hxj%RZs4{~;g1plI zT4k~pMvis{_V!9HfWk6yerHar09bL>|19500T2HZ?~!==o}?Wzu{$H%#8$klb*$cC ziQLt(~_694LfxxjBn0|aR+$r3|88ky~9c}#fZ zxVhdR-%sd&SQRhwr?J%-+%)B}{^`IS%MIKo@SxSIy9cq%oV70ubgA*F9%gUCnyDC>Qt|Q%kTs{dDn>mD;bm~( zIkgQO&b%AXX{TKc?&aWN_GuR}N1l0>CA?$a%2lA~T5<(W0QLGJVA4oj2~omrT#$&|H0$8cHNrQ1lbDh0z*I*j1?1_s<8RV7(y-Cd+W!v<}1cL!iR_%xL4G*bD2xY1V`?BGhVC4X9>=pHYixj6X2LR-UmZHkb% z=X!J13M76lRkiJKr*-y3`7uJa-MycVw2)|>}FP%AYr3uw6(?>f_fO<%>?X}rF zOcGYNnOW%@=$@0B{WDdX4X3$tDx35Z98M+}65G#Sf;dlhk~11q{r;q~=Kd3vOx=zr zq_Uam5aW9+)(Mob2FdwZB0X6y^yXGXQeGIxdc@sj!?+uoL1|097a(KD9!ec~7VYNL z(qAQ8=<^0Izm;d8R-d*=0f*E5kND8PbAFV}Eo|*%?VObD4UA0w0w0CVO^mE0-$Q5q zi{Vz3_*?xSx^d`sOuRus=u4bT{LXboevly)MUL#)v~7(t`P8QE*0kzzXa`82H`)&Q z7}*a)-*F+1HDOI1a+;p%{>{vFKl6H=`TXSd`Sz6CUy{Z&E;L&V`d%efWy?3TTLpZ^ zJ-1s1xlWSD_`p7dq(u`ohT7(Msh7xcUWOB}tq+0<1IigFwf%Sz= zgNS1>=vao-d@f#kTH6+tO334MqC6lHa#MT`e3r*|_TytuA)BNi zkRRE`T;U5%?3QfvhT*f(iU_aVR_Q0*mY{!Rkj#_DS8ikU-d7;1x2hiIu z_}T2!XS-$bxxO*4`c_rhFz+fMZ;M7}*lvn7N{4k{?2F$Ypi(}f1Ym;4b%8OMvwY5t z#^+)f0g?^LfBXCvw7RqM?uDA?W3Fu2&!66PR2AbuDM z4P5QE$CO}!bWHK=e*;!>i$yw-fCPNb4+~r+>O_2>OCmi1Y8Ry+w4sW-LIQ?@acK&1 zj9gY79&n2M?5W&>&k$U5aj%iRPziQ%Q5~W*k9>rjZeorXDvqnw>A!ww{3;*P(7j)# zX#Y65|2tBnZee91VrTTfW|8;%6yV)IZsbKt+5qc&)PadY$;Or&LmR{Cd9S(pxvJZ$ z4s*#e6=4ur90Jgh-|qKqBjd#sfyBRm0)HK~0lw!qAugCB+)e8`YO;935xh*t_xP{5 z!`5~eatQc=J^`EVAO=Y@9t4j}>%{Muvn&**eKC~^!h)+pIY1lTnx$YCw;$2bOeGPp zMLHPPF19Z_OfH);j&Hl?^M2&@ej)*?JkyZ%$`i}2u90IevsI|8O3?|+xRnH6Dk?s_ z0;hKBq6W`kl^rRf%cg;hLN8Ynb}LiO`+d2ZF^Q3c>kzcTxqbXP_LGy@(p|w=Sx+W+ zrp+#CCxplX8Qdk!{`xM`h|qLIyK=cg_ApF#SwL~tppguVwdJxm%P^X26s51-MjA0| z`=gr~r1P%WaOs3L>+C&h^ALJQG_+GPWg}5WLpcXoWS!6kLg*T6j89)A8}rYvmMs#5 zEuYdyhj3INL(43x_ptBwm5h3t5~jtdwk_ZoBNSuVTCV z*^01UH7}|r4xiG-M~hw%rp1QOFGu?t+>^G666PB8<+IDmTAvzXYF~-tpm0Bd_Dio^ z%Z9J%wHvc$QDyveG!(W;$4{A*GRZ4|9S7u~OgY{aPM_U%6!#S$?+H9Ft71p*hR+h;oxD(6^%cr-A)V?qmqL&$ zkPsn>(8w|_hH#K%md6$(;Yv`BTCiI%j$A5^*)q-^ahK9Ey8%e@iEu|MP6Bba1zAKr zNFBMp~SAciCc2jrmS=2Jo$cl93u+^FPCw?~7izIWSu$_X{Q&si$x> zi;A_3KsM6acrzVhv!w!?vXvIrA=yU9uIF*!TDfT)s@8Iuj{A@`jl>xm6E7JsA)(w_ z2iv8=Gk~ad5y_X4TU?m}<$>36FvA#Zg|xcB_!)u= z-!R7DD0mkO+}qB0ECWB&OimL$biROB7-7}RGYw#srG{OvqS0Pu-*b7Z{P71Fv@O;5 z0O}k0>4OwBAp)&QXiw&P=-g;NrI`7wdfVb}pTFCNv4Kd9JqF=(5r!Nicv6BXy9v7b z$0V>YVP_z}D?*p(65zZtDw{>rs<}3qEArjL@)~io9ouHG*nn7=kB9>e&@O>XX-hB^0)jU%mFD^arApH|l$lLB+D=BrhDrE? z^gCgM2n7XsZsH+)QMbpx;;mST3*{krneC5fIZdoO@m_7bJwL#9GV#&&bd?8TT;wsb z8u3vjJ~T(MuCf&a{D+X|r58VOv=D{-Xu=AUoQ)I$ccX?B(YbF?5=yEWvTyasJ&Kq% zSO{G%#Ue8tdPxpXf(@EzI%BA@0j>xOnC6+JJtH?f8kN`gQIEg3ge5~7IJF1x68llU zPw?hI;8i1mXQ72YJW1x7sMi-Jw0+lr2~=>BZH~-aHV@O4zqU^a!;dW_2cg~ef6_}4 zk0*_5kkHZtWofXRW%WQ!i3~5ha5Z;fKdW*h;pag#R6cm>s2m|7(<@UftJFQr#CCuTR+`x_$RniO@ zAU;pl;J`SUEmKsuA}>fjWff+okjkbT zAUE}evatVfW?4)y*xhDrKij4mZ%G~Sz<_aI>O<3^-KzRbYu)w>6fX35AaBH;=-SEs zQ%TUv%G(cUSeyaiw2Q|q>{C6@^^=~u>qVB;yWoAgNIR6X3K_HW6FwxHqrouuq-?V= zy>sAkBW&he@f0=A(P?qAl3UzL`N?0zKJ=81`%$nvIM?-p({UZ2km!~_p!ib4xfc;w zI5HJbEsdb=Obwc6mcPQ^edc`zU&?nG-;}Mj#rAJf$cr~Xnp@w(7X2yXd^>D62q%|P z=@vh(Lffr_JtxdicjGx)KaCl$AOFNDyn7@N;Tt|E%jI+oNi4=E_RGh4r$wSpW%8KC3xVBJGn5j&7L`9$ zfDx=k^1HVC54Q=Id{aa8a(TvE47rT12avuJ3ZGb|EeO;re$!kl;Yk?Y16(o|*O2F$ zN~>3w%-nuH$sJ0LzZBm*;A&xkfNomw$GxD!A1nQxgsN;};Amw2x5w(cOB^6++r$D8 zvi;9YNU8wvUlnICVyZ$SP??wBDAQDV9H z{q-%?W6f+R2C2|JECJ|!G;(9Gb*L%ZOD7<}#xVlQQqU&K24GKN*D z;IuZuG1%%rS)+MqQ8}(;(0;+1?PDW{G&-9C!=>7jog05mIX;eDqG%;{(TdCrT}d4v zMRe$%)=4rD&BzG7Bc!SAbqZV-{TxChntK{g_8IK!T(PECd|7^k!8c8!)Fh@dC0Nz! zCyoA0s(A&vkKSjq28^nm&}s1rY6cOC)NOg{nkjDSRQ-LeIyVX+bCTi%iYpg_%LQm( zv`}3vbs4h^xgFD8`bJs|J^E&29lA~(fEyyZU;|pe==8|3m9%`4|NNk8N~_%d@kB(+ z)B%3 z^J~>S=aN+f{*PH&BF>WNl{6V!Tn<+P#ywg(u;apZu<4s3u*-QQ;0`uiTgI3dPb_ZE zAQHJN_Zix*$=4MbG@na8i*H~9qlA%$=so*~T|VIl&P;wl>J;0l0>{4W%HH~pbszo9 zwyQ){5C{JgK?TC{B_X~u;sD4A`?4~;ODxDi=NuM>ePb}sPsq+Ep_MR9kPVT~(yzd^ zJD~Rkm2R2U1|Muj!8*a3gYAH!Fuy{-0SBJj~|-?{Lfz1HjNwh)Ty8S40YfH7F`%h4b{gB>mpY;^AJBpjF_|W!EqdxD>{u z8WLIhgBVc{t+8>< zLanZk<@543JJzjs{j92Mg;@JF53&K4`0HuX&-LRLvB+N(j+5DT1Pwq{qyCXvuKCBR z{_nU`WoH*-6Iw7TO}29a5DXr4EJ-rY^=Fvt=LHI){!1+4eUI>RMKx)e~@(9M%W87Jci zU13u@gr&%;A$BLI7#f8M_{s>r0{l|j_f)F^mDfsXz#z5h=t!Y2fQiH2XKl3~_Rpd05)i{jdCZ>HL?fURF>dI!o1%}FHRg?K^oN!IxKS7W)v!gSGZ zn#zx*bvtDs$!>NMtd^Cn_r2*$YcYP}V=YH(8QA6nu^5%1x(3%eYeRz@Nx15RP=H|; zc@mBn>L4rtwD3!c+Q$MJbkBSRLWO4pH!;FvFA_B!x3cyKDA3~9JsFNjI}cbt_bK zuEby*)ew*`gWCJj-E0Jy@CP|*C1w$>^kCkz!f%7TJJVwU|J=^t16?yK##Xa-h+p>N zHD>Q$hLy-Ep!t-5dX@QO7Z&~3di}kcm3K5YaTEbqEn8Uscd-HpSSHqg*QV-UzO2ex zR7Gesk;K0O064d`Hwz+cUe~8`GXL9eX|Ci9E&w<4EV4_4Ul87NB5wh|y;(1&2u#|U zwP8^U#Cm#0JDl#e{*m(*Sd8<+NInFX9SE4FTkgNq*kvLKj=Cqp*G=`yPAJ!c^3cRxE=c=~4m}A4H zKa1cZvu?4PH#CqZ@dZB!q*lJ(w`{QLX%Q7GYez8ElBY8zp9*}XDuQDt1xC_zj)q&X zsnXRhiwZ|YXvaqo-rhl~H)*C5-9*u_-8kxHNFSbo&g7f>5y0u6I@jAQs#(dfw>q8d zToHSq-4U7su+s}MC}r9(9;~v+NspN;LXJ(;(-z^*Z0uI3I)=xiDk&&(;ZJ4tO1Mk* z5)lRJIr0lXCJcA7P)}XXgHfy+CHR5d^=&gE+lrEJ*dm`vVn~YJLnZI$R)ADT*9{7( zRRn6I3$jaZYyH^I*ALC+WoQog7?Bj8SYky(pWZy8U}r#@oCjK>UDcf>e(Vof=WMO> zgBT@e*U<1`o1?@ogc%cU!XLn@H5;N<9v6{0Yne?W1vL#R^oVrisg1I( zdW1UhA;5;mc8{<~|7-zlYM%zU?dTMJE$AbN^I%tae#GdbY}1U??YZR}{J0cVSx)CI z(yxT+NCAf7BivwzH*K6gCtjPq#<-T1qib!P*ahs~bl24iGAvYVvPXR$~ih?c@| z_1m6x2;Q^U3ou>&nXRk%uc!TQwywIJqm`qHk)5Nlih+~W|JFl_**V%sIs+t$e|M!y zW!?96DsSS%$F*h58OuujxpE6=IzH+?WGIn>IksYA3K=$|OjBkQ(~n8te`TOj1tPqD z@QaJxUX!g)5J9{#I2#z{H5>2Xe!6}7N&msth$NP!YCo>KVeqS&1IgzMSTO3ST?1)M z>IP4>9}}JU3^XbYwK3ES+gl2S(&8KI-+kS18H_Hhu;HZM~cZe3e9U4X5zI z)RkG6#7LM}O_FM*4K?;C=!+{qfnuZclTxBZV4V zs6SlDI%r}EQdgHswH&NObH1ZMUm!w@3G2|vMsgMC4*4Oxgi-)vaQdB%mju{`OV-v) zKCBz}G-hO8eo@lzJGIX3&r+$qXw9DCl?}_};TbZ;5+{*a+_6vNuh7?Cp60-ciHfxk zZoqb;&-ii$2L|}rVZiM)!>|Z%M#r!fDEci}Vce%6ND3MEueWqxr>-m<9v) zg*1UVwPw-xV7^Qw@{3wcDW!&MW${rUB7EK#yo1Gi*u{Eq-a}aoORX1SL$RB$5t+w9 z`-DZkizTU%1x!G4=?lD?3H9Cov(W{*DtZ3V@V+>yT-EqM+f%RyJ~K^hc|WWo%Temq zv<%UZBoVzSbPJERgrm}+ba(q>P~227N;9(2ygi-R)Q_-Zj?b&Vc}NqCG&=Nv(;D$d z*i8FhPwU@Oc{K}1XBPu&1Eb$6`Tu=d-~U9xz(eq_-@PLNLjT;R)U@BlynH*oZ1CES z20ICb3cwcj$b-p_)MTJh!sWT8l1>i#R3Q<((83FK6O%h4 zz91f&-7TU3pdnznH7Xd=``-O&V4$n;P6#x43DJ;pC3fQ_yEl*L`?VMAh?tr%A=_|jdkJ=JUul9%O1nuDI&U1utT-Y) zS7x0`C-CS{VL)B7z;At`+=lt|cSkEp6kOGv2tN@NuIDSBRVt8A%(ZvwcMIzgG}f1Q z-l3wj5(1Y1i>-lFrFs#5#GyLl8quK|RnYj!9azrLNrOUptz%|$jmhMd3GM7%5eYO_ z5Y53fGz1yjncHY1rDk_rhW8Lw%A<9Pi=i`yazH7o3U#B_&XsVczaQv>#@47=BlvB} zlT;6GK+2)nUH(hQ5!68Y9k8ix(U@c9{#KNl_eXqp(63}f8VU}8F#C@05ma9bD)P_V z6r+I>`Nm^8soiG?B`StN(3Dd8HS__&Lsew9D8)RBkz07h!=bFT(#pl6*vY2%TS_HO zXOci$)I)NpyIV^_FFiedHM{Z03QsN_teCKx(x(#&pG}^?WnC%SPR4RiM0j+iK#rIq z#mN_Mw3XYxxUv^dBf1LlcW6zQo@w8A=k}ww$T2y!BTXEQqGyIVz{m;y0Bb}SrR57| zM$Zg-<)J}deAai3=+ro(T@8<+UXj<7MQVQ2uj}UUrIz2kXMreC@aH46N4CSNxd^-6 z_W5v5e#r^x8MeuSZJlU<2`8GE7Y=@cHXIM>$>LaZ$%4-9J$uFTxz*`ocx*hvl(2vY zkSshO6kpwpo&PgZo?cWWz`i3@z@iWS0_w|!xueL#31_?sRbuXnlnJFFe7dXBTld)M$_LPczROL+YrB@5XZzz*rg95 zh!N)i-WNyk45SjYAyR%6slrD&1~WYU0ddUS9NOrtxa6$Jj};l&bj@{S+c^em+>oW9 zhH_*LyJIvoW(@s zh+BRtXEUnk)*EbTCn@UsZ^`A=DS1jF;NE8W$2sfY6A9m2n4yU+V2Coeb96Rxaejvc z4L$4)%mCjA|Jk5OI=R04$^6%!h^YJ>THNqIH@XH53MJ8JAw}saTW>TWAt?!lXjW9q zD8{jRyphS%6H~M0V86|}h*#Kx2(g_Y{!aCrXXbwHm5{}45QIB}pX)8}VfPaK79 z&atK+J7Hw%%!ZY4sOSl<_}o0jT4SQWGRml$Xgkcnh#(_inz}jvK(4P)T$4VJp^|Tl6+0}Ip>~x ztKPkTd=yp8UaKj7FlUdk#$(2 z4K7~7&h4J(9@f$a>`}A}9T!QO6C^4+3uwa|KM;iO7hf!Q=NkxtST8DUnr7-}$Yvu% zM8C?$lNjFUF3_o^%km$)X9p2$Ipa76=gB2IFEZM|m&UaY(1wr`Xi&0A*&TEtPf8I4p9;q~bE+v#shc zjN)Sm4W#6!tI;^=N*ybs@ZO<}o=2T{K92yB912HV2>qb9Ty!S{wZCkQPu4hW{DD={ z@^2w=>3^(}f1Y5Z-R+GXT+ChH$BE|uQXv1=qs+hXgET$Yb#Wjv{!DpBt(77SLlTC0 z($;i_$1oJ@~YKZe4s1 zw|t;kFv&--&t&HYbYohg0i__KbCGm~ZJSkE1%Nb==(k44m6!RA5Z#6h?;3cVVe+df zw{&CbL%DHmrv-cH`k_%)dsWx{TKy#hX4nmmqo21e(MGHK^g5ONJ{GljxH^Y#pmx$fcXiv-a6MWKS@es>*eGw zHy~3UKR9rdopKH*sE4}W_HI2fU~Cj?9do1{Soar8_{(Y6v>0YM3R>wKq3&A(i-su(9f^{H~4fr(XM zF@1>_7fuX@LAh4G@Sr4ymNhKW5&OP-IjlC$lG!hs`p;lj_-3@+pGq~P+1T^>H~Yqp z+&flXd*Dtp8>Y6O(oC?nvUct`{Vu>!Fh#!@g5RSX!WZd*^f8Yzp})|8Hq=0Pg9X;% z0=&@o3H>-ng2LjBZ0b0Ouc@U~;BFARzktbzi+JodazT>Y@fSTF`6Eb^!m7@N_~k>% zNQxlts1blQY=E^_LjYf0*os^n>7~Sk;18AwLYkEE3J`~)Li`Xv zGXehu6RKEPB0I4pdT{|ndn5{cZYvGp5$3JZQI?RkCd2VI^;;P0c2d$)9_lp_8A%Qp z36?L3X%o&UDR2%0@yq(EP)X(a5AK+fL0diptf&5eo6`OFu7bcSDQaizWA5TAW$s|^ z0!;V)$9T8uzp(ypf*WEaLy(XlM`b8wNxwqvRKN!e+87LCJS=r8x8V^PPn(Xxf#%P< zQdVi{8jP$im5RjcB*t2u8)!*) zH&6&_$evj?JlVpc%{CmR%3rOZEDU5LRf6-M*cjUkDP}AuHK4_B4ZjqiVx5_PQ8B+D z90touXo#p$xkG&XHCP@nnB-lzqo@9mV-X|D%yp?;f_)I12X-Ky&Fd(Dq-=<`Y3!jw zP|J5mplBLP5@BP3sP{16c$lT)*fQlt!ktvbu`G~M1zUmN91?!8U`@Ws&Ea{5zh2R8 zy{NT}ZWjStZ^S4s{ZUyOg=JkJtjRK@cSxCJHXoo` z4hVO8Ul0s+osf_p!nGrKiiQn^{0VpyP|g5oD~}4A&;oyDyB&Jto>|UmQEb-{D96K) z{`IFx4a)I`T?3ZpmA@^`|4d5$;|pSD{+>D@;%0Ab3Z#L)laocg-+46F|3`DytTFB| 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⋙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 z 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 r8*O8o4I10FZQHhOtFhU* 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

+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ + 代码生成请选择字典属性 +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+ + +
+ 代码生成请选择字典属性 +
+
+
+ +
+ +
+
+
+ +
+
+ + +
+
+
+ + + + + + + \ No newline at end of file diff --git a/snow-admin/src/main/resources/templates/system/log/edit.html b/snow-admin/src/main/resources/templates/system/log/edit.html new file mode 100644 index 0000000..c5dfc20 --- /dev/null +++ b/snow-admin/src/main/resources/templates/system/log/edit.html @@ -0,0 +1,150 @@ + + + + + + + +
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ + 代码生成请选择字典属性 +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+ + +
+ 代码生成请选择字典属性 +
+
+
+ +
+ +
+
+
+ +
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/snow-admin/src/main/resources/templates/system/log/log.html b/snow-admin/src/main/resources/templates/system/log/log.html new file mode 100644 index 0000000..2b1cfff --- /dev/null +++ b/snow-admin/src/main/resources/templates/system/log/log.html @@ -0,0 +1,220 @@ + + + + + + +
+ + + + \ No newline at end of file diff --git a/snow-common/src/main/java/com/snow/common/annotation/DingTalkSyncLog.java b/snow-common/src/main/java/com/snow/common/annotation/DingTalkSyncLog.java new file mode 100644 index 0000000..e941571 --- /dev/null +++ b/snow-common/src/main/java/com/snow/common/annotation/DingTalkSyncLog.java @@ -0,0 +1,41 @@ +package com.snow.common.annotation; + +import com.snow.common.enums.*; +import org.springframework.web.bind.annotation.RequestParam; + +import java.lang.annotation.*; + +/** + * 自定义操作日志记录注解 + * + * @author snow + */ +@Target({ ElementType.PARAMETER, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DingTalkSyncLog +{ + + /** + * 模块描述 + */ + + public DingTalkListenerType dingTalkListenerType(); + + + /** + *钉钉同步方式 + */ + public DingTalkSyncType dingTalkSyncType() default DingTalkSyncType.AUTOMATIC; + + /** + * 请求钉钉的URL + * @return + */ + public String dingTalkUrl() default""; + + /** + * 是否保存请求的参数 + */ + public boolean isSaveRequestData() default true; +} diff --git a/snow-common/src/main/java/com/snow/common/enums/DingTalkBusinessType.java b/snow-common/src/main/java/com/snow/common/enums/DingTalkBusinessType.java new file mode 100644 index 0000000..a85d9d4 --- /dev/null +++ b/snow-common/src/main/java/com/snow/common/enums/DingTalkBusinessType.java @@ -0,0 +1,29 @@ +package com.snow.common.enums; + +/** + * 业务操作类型 + * + * @author snow + */ +public enum DingTalkBusinessType +{ + /** + * 其它 + */ + OTHER, + + /** + * 新增 + */ + INSERT, + + /** + * 修改 + */ + UPDATE, + + /** + * 删除 + */ + DELETE +} diff --git a/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java b/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java index 099715f..deec905 100644 --- a/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java +++ b/snow-common/src/main/java/com/snow/common/enums/DingTalkListenerType.java @@ -13,15 +13,15 @@ public enum DingTalkListenerType { DEPARTMENT_DELETED(3,2,"部门删除"), - USER_CREATED(5,1,"用户创建"), + USER_CREATE(1,1,"用户创建"), - USER_DELETE(6,1,"用户删除"), + USER_DELETE(3,1,"用户删除"), - CALL_BACK_REGISTER(20,10, "回调注册"), + CALL_BACK_REGISTER(1,10, "回调注册"), - CALL_BACK_UPDATE(21,10, "回调更新"), + CALL_BACK_UPDATE(2,10, "回调更新"), - CALL_BACK_DELETE(22,10, "回调删除"), + CALL_BACK_DELETE(3,10, "回调删除"), CALL_BACK_FAILED_RESULT(23,10, "获取回调失败结果"), ; diff --git a/snow-common/src/main/java/com/snow/common/enums/DingTalkSyncType.java b/snow-common/src/main/java/com/snow/common/enums/DingTalkSyncType.java new file mode 100644 index 0000000..9417a60 --- /dev/null +++ b/snow-common/src/main/java/com/snow/common/enums/DingTalkSyncType.java @@ -0,0 +1,31 @@ +package com.snow.common.enums; + +/** + * 操作状态 + * + * @author snow + */ +public enum DingTalkSyncType +{ + /** + * 自动 + */ + AUTOMATIC(1), + + /** + * 手动 + */ + MANUAL(2); + + private final Integer code; + + private DingTalkSyncType(Integer code) + { + this.code = code; + } + + public Integer getCode() + { + return code; + } +} diff --git a/snow-common/src/main/java/com/snow/common/exception/DingTalkSyncException.java b/snow-common/src/main/java/com/snow/common/exception/DingTalkSyncException.java new file mode 100644 index 0000000..9c03ddd --- /dev/null +++ b/snow-common/src/main/java/com/snow/common/exception/DingTalkSyncException.java @@ -0,0 +1,42 @@ +package com.snow.common.exception; + +/** + * @author qimingjin + * @Title: + * @Description: + * @date 2020/11/13 14:54 + */ +public class DingTalkSyncException extends RuntimeException { + private static final long serialVersionUID = 1L; + + private String requestParam; + + protected final String message; + + public DingTalkSyncException(String requestParam,String message) + { + this.requestParam = requestParam; + this.message = message; + } + public DingTalkSyncException(String message) + { + this.message = message; + } + + public DingTalkSyncException(String requestParam,String message, Throwable e) + { + super(message, e); + this.message = message; + this.requestParam = requestParam; + } + + @Override + public String getMessage() + { + return message; + } + + public String getRequestParam() { + return requestParam; + } +} diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/aspectj/DingTalkSyncLogAspect.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/aspectj/DingTalkSyncLogAspect.java new file mode 100644 index 0000000..2fb1246 --- /dev/null +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/aspectj/DingTalkSyncLogAspect.java @@ -0,0 +1,193 @@ +package com.snow.dingtalk.aspectj; + +import com.snow.common.annotation.DingTalkSyncLog; +import com.snow.common.enums.BusinessStatus; +import com.snow.common.exception.DingTalkSyncException; +import com.snow.common.json.JSON; +import com.snow.common.utils.ServletUtils; +import com.snow.common.utils.StringUtils; +import com.snow.framework.manager.AsyncManager; +import com.snow.framework.manager.factory.AsyncFactory; +import com.snow.framework.util.ShiroUtils; +import com.snow.system.domain.SysDingtalkSyncLog; +import com.snow.system.domain.SysUser; +import com.taobao.api.ApiException; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.Map; + +/** + * 操作日志记录处理 + * + * @author snow + */ +@Aspect +@Component +public class DingTalkSyncLogAspect +{ + private static final Logger log = LoggerFactory.getLogger(DingTalkSyncLogAspect.class); + + // 配置织入点 + @Pointcut("@annotation(com.snow.common.annotation.DingTalkSyncLog)") + public void logPointCut() + { + } + + /** + * 处理完请求后执行 + * + * @param joinPoint 切点 + */ + @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult") + public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) + { + handleLog(joinPoint, null, jsonResult); + } + + /** + * 拦截异常操作 + * + * @param joinPoint 切点 + * @param e 异常 + */ + @AfterThrowing(value = "logPointCut()", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, Exception e) + { + handleLog(joinPoint, e, null); + } + + protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) + { + try + { + // 获得注解 + DingTalkSyncLog controllerLog = getAnnotationLog(joinPoint); + if (controllerLog == null) + { + return; + } + + // 获取当前的用户 + SysUser currentUser = ShiroUtils.getSysUser(); + // *========数据库日志=========*// + SysDingtalkSyncLog sysDingtalkSyncLog = new SysDingtalkSyncLog(); + if(StringUtils.isNotNull(currentUser)){ + sysDingtalkSyncLog.setOperName(currentUser.getUserName()); + if (StringUtils.isNotNull(currentUser.getDept()) + && StringUtils.isNotEmpty(currentUser.getDept().getDeptName())) + { + sysDingtalkSyncLog.setDeptName(currentUser.getDept().getDeptName()); + } + + // 请求的地址 + String ip = ShiroUtils.getIp(); + sysDingtalkSyncLog.setOperIp(ip); + }else { + sysDingtalkSyncLog.setOperName("无"); + sysDingtalkSyncLog.setDeptName("无"); + } + + sysDingtalkSyncLog.setStatus(BusinessStatus.SUCCESS.ordinal()); + + // 返回参数 + sysDingtalkSyncLog.setJsonResult(StringUtils.substring(JSON.marshal(jsonResult), 0, 2000)); + + sysDingtalkSyncLog.setOperUrl(ServletUtils.getRequest().getRequestURI()); + if (e != null) + { + if(e instanceof DingTalkSyncException){ + sysDingtalkSyncLog.setStatus(BusinessStatus.FAIL.ordinal()); + sysDingtalkSyncLog.setOperDingtalkParam(((DingTalkSyncException) e).getRequestParam()); + sysDingtalkSyncLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000)); + }else if(e instanceof ApiException){ + sysDingtalkSyncLog.setStatus(BusinessStatus.FAIL.ordinal()); + // sysDingtalkSyncLog.setOperDingtalkParam(((ApiException) e).getErrMsg()); + sysDingtalkSyncLog.setErrorMsg(StringUtils.substring(((ApiException) e).getErrMsg(), 0, 2000)); + } + else { + sysDingtalkSyncLog.setStatus(BusinessStatus.FAIL.ordinal()); + sysDingtalkSyncLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000)); + } + } + // 设置方法名称 + String className = joinPoint.getTarget().getClass().getName(); + String methodName = joinPoint.getSignature().getName(); + + sysDingtalkSyncLog.setMethod(className + "." + methodName + "()"); + // 设置请求方式 + sysDingtalkSyncLog.setRequestMethod(ServletUtils.getRequest().getMethod()); + // 处理设置注解上的参数 + getControllerMethodDescription(controllerLog,joinPoint, sysDingtalkSyncLog); + // 保存数据库 + AsyncManager.me().execute(AsyncFactory.recordDingTalkSyncOper(sysDingtalkSyncLog)); + } + catch (Exception exp) + { + // 记录本地异常日志 + log.error("==前置通知异常=="); + log.error("异常信息:{}", exp.getMessage()); + exp.printStackTrace(); + } + } + + /** + * 获取注解中对方法的描述信息 用于Service层注解 + * + * @param log 日志 + * @param sysDingtalkSyncLog 操作日志 + * @throws Exception + */ + public void getControllerMethodDescription(DingTalkSyncLog log,JoinPoint joinPoint, SysDingtalkSyncLog sysDingtalkSyncLog) throws Exception + { + sysDingtalkSyncLog.setTitle(log.dingTalkListenerType().getInfo()); + sysDingtalkSyncLog.setModuleType(log.dingTalkListenerType().getType()); + sysDingtalkSyncLog.setBusinessType(log.dingTalkListenerType().getCode()); + // 设置操作人类别 + sysDingtalkSyncLog.setOperatorType(log.dingTalkSyncType().getCode()); + // 是否需要保存request,参数和值 + if (log.isSaveRequestData()) + { + // 获取参数的信息,传入到数据库中。 + setRequestValue(sysDingtalkSyncLog,joinPoint); + } + } + + /** + * 获取请求的参数,放到log中 + * + * @param operLog 操作日志 + * @throws Exception 异常 + */ + private void setRequestValue(SysDingtalkSyncLog operLog ,JoinPoint joinPoint) throws Exception + { + //获取切面的参数 + Object[] args = joinPoint.getArgs(); + operLog.setOperSourceParam(StringUtils.substring(com.alibaba.fastjson.JSON.toJSONString(args), 0, 4000)); + } + + /** + * 是否存在注解,如果存在就获取 + */ + private DingTalkSyncLog getAnnotationLog(JoinPoint joinPoint) throws Exception + { + Signature signature = joinPoint.getSignature(); + MethodSignature methodSignature = (MethodSignature) signature; + Method method = methodSignature.getMethod(); + + if (method != null) + { + return method.getAnnotation(DingTalkSyncLog.class); + } + return null; + } +} diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseService.java index 00f9500..2de6590 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/common/BaseService.java @@ -6,13 +6,20 @@ import com.dingtalk.api.DefaultDingTalkClient; import com.dingtalk.api.request.OapiGettokenRequest; import com.dingtalk.api.response.OapiGettokenResponse; import com.snow.common.constant.Constants; +import com.snow.common.enums.BusinessStatus; import com.snow.common.enums.BusinessType; +import com.snow.common.enums.DingTalkSyncType; +import com.snow.common.utils.ServletUtils; import com.snow.common.utils.StringUtils; import com.snow.common.utils.spring.SpringUtils; +import com.snow.framework.util.ShiroUtils; +import com.snow.system.domain.SysDingtalkSyncLog; import com.snow.system.domain.SysOperLog; +import com.snow.system.domain.SysUser; import com.snow.system.service.ISysConfigService; import com.snow.system.service.ISysOperLogService; import com.snow.system.service.impl.SysConfigServiceImpl; +import com.snow.system.service.impl.SysDingtalkSyncLogServiceImpl; import com.snow.system.service.impl.SysOperLogServiceImpl; import com.taobao.api.ApiException; @@ -32,6 +39,7 @@ public class BaseService { private SysOperLogServiceImpl iSysOperLogService=SpringUtils.getBean("sysOperLogServiceImpl"); + private SysDingtalkSyncLogServiceImpl sysDingtalkSyncLogService=SpringUtils.getBean("sysDingtalkSyncLogServiceImpl"); /** * 获取token * @return @@ -49,7 +57,7 @@ public class BaseService { OapiGettokenResponse response = client.execute(request); if(response.getErrcode()==0){ timedCache.put(TOKEN,response.getAccessToken()); - syncDingTalkErrorOperLog(BaseConstantUrl.GET_TOKEN_URL,response.getMessage(),"getDingTalkToken()", com.alibaba.fastjson.JSON.toJSONString(request)); + syncDingTalkSuccessOperLog(BaseConstantUrl.GET_TOKEN_URL,response.getMessage(),"getDingTalkToken()", com.alibaba.fastjson.JSON.toJSONString(request)); return response.getAccessToken(); }else { //记录获取token失败日志 @@ -107,5 +115,4 @@ public class BaseService { sysOperLog.setStatus(0); iSysOperLogService.insertOperlog(sysOperLog); } - } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/CallBackService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/CallBackService.java index 0f695f1..7e316e9 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/CallBackService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/CallBackService.java @@ -2,9 +2,12 @@ package com.snow.dingtalk.listener; import com.alibaba.fastjson.JSON; import com.snow.common.enums.DingTalkListenerType; +import com.snow.common.enums.DingTalkSyncType; import com.snow.common.utils.spring.SpringUtils; +import com.snow.dingtalk.common.BaseConstantUrl; import com.snow.dingtalk.service.impl.CallBackServiceImpl; import com.snow.system.domain.DingtalkCallBack; +import com.snow.system.domain.SysDingtalkSyncLog; import com.snow.system.event.SyncEvent; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -27,6 +30,7 @@ public class CallBackService implements ISyncDingTalkInfo { DingTalkListenerType eventType =(DingTalkListenerType) syncEvent.getT(); Integer code = eventType.getCode(); if(code.equals(DingTalkListenerType.CALL_BACK_REGISTER.getCode())){ + // new SysDingtalkSyncLog(eventType,"registerCallBack",BaseConstantUrl.REGISTER_CALL_BACK,DingTalkSyncType.AUTOMATIC.) callBackServiceImpl.registerCallBack((DingtalkCallBack) syncEvent.getSource()); } else if( code.equals(DingTalkListenerType.CALL_BACK_UPDATE.getCode())){ diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java index 13639e0..a7a02d0 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/SyncDingTalkInfoFactory.java @@ -22,7 +22,7 @@ public class SyncDingTalkInfoFactory { if(type.equals(DingTalkListenerType.DEPARTMENT_CREATE.getType())){ return new DepartmentEventService(); } - else if(type.equals(DingTalkListenerType.USER_CREATED.getType())){ + else if(type.equals(DingTalkListenerType.USER_CREATE.getType())){ return new UserEventService(); } else if(type.equals(DingTalkListenerType.CALL_BACK_REGISTER.getType())){ diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/UserEventService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/UserEventService.java index e150041..87e7e51 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/UserEventService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/listener/UserEventService.java @@ -25,7 +25,7 @@ public class UserEventService implements ISyncDingTalkInfo { log.info("调用钉钉用户回调传入的原始参数:{}"+JSON.toJSONString(syncEvent)); DingTalkListenerType eventType =(DingTalkListenerType) syncEvent.getT(); Integer code = eventType.getCode(); - if(code.equals(DingTalkListenerType.USER_CREATED.getCode())){ + if(code.equals(DingTalkListenerType.USER_CREATE.getCode())){ userService.createUser((SysUser) syncEvent.getSource()); } else if( code.equals(DingTalkListenerType.USER_DELETE.getCode())){ diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/CallBackService.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/CallBackService.java index 3b6d47e..1deec37 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/CallBackService.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/CallBackService.java @@ -21,7 +21,7 @@ public interface CallBackService { * 更新事件 * @param dingtalkCallBack */ - void updateCallBack(DingtalkCallBack dingtalkCallBack); + Boolean updateCallBack(DingtalkCallBack dingtalkCallBack); /** * 删除事件 diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/CallBackServiceImpl.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/CallBackServiceImpl.java index 7325168..6cf973e 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/CallBackServiceImpl.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/CallBackServiceImpl.java @@ -7,13 +7,19 @@ import com.dingtalk.api.DefaultDingTalkClient; import com.dingtalk.api.DingTalkClient; import com.dingtalk.api.request.*; import com.dingtalk.api.response.*; +import com.snow.common.annotation.DingTalkSyncLog; import com.snow.common.constant.Constants; +import com.snow.common.enums.DingTalkBusinessType; +import com.snow.common.enums.DingTalkListenerType; +import com.snow.common.enums.DingTalkSyncType; +import com.snow.common.exception.DingTalkSyncException; import com.snow.common.utils.StringUtils; import com.snow.dingtalk.common.BaseConstantUrl; import com.snow.dingtalk.common.BaseService; import com.snow.dingtalk.service.CallBackService; import com.snow.system.domain.DingtalkCallBack; import com.taobao.api.ApiException; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.List; @@ -26,11 +32,12 @@ import java.util.List; * @date 2020/11/3 11:19 */ @Service +@Slf4j public class CallBackServiceImpl extends BaseService implements CallBackService { - public static final String TOKEN="call_back_dingtalk_token"; @Override + @DingTalkSyncLog(dingTalkListenerType = DingTalkListenerType.CALL_BACK_REGISTER,dingTalkUrl=BaseConstantUrl.REGISTER_CALL_BACK,dingTalkSyncType=DingTalkSyncType.AUTOMATIC) public void registerCallBack(DingtalkCallBack dingtalkCallBack) { DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.REGISTER_CALL_BACK); OapiCallBackRegisterCallBackRequest request = new OapiCallBackRegisterCallBackRequest(); @@ -40,20 +47,18 @@ public class CallBackServiceImpl extends BaseService implements CallBackService request.setCallBackTag(dingtalkCallBack.getEventNameList()); try { OapiCallBackRegisterCallBackResponse response = client.execute(request,getDingTalkToken()); - if(response.getErrcode()==0){ - syncDingTalkErrorOperLog(BaseConstantUrl.REGISTER_CALL_BACK,response.getMessage(),"registerCallBack()", JSON.toJSONString(request)); - }else { - //记录获取token失败日志 - syncDingTalkErrorOperLog(BaseConstantUrl.REGISTER_CALL_BACK,response.getErrmsg(),"registerCallBack()", JSON.toJSONString(request)); + if(response.getErrcode()!=0){ + throw new DingTalkSyncException(JSON.toJSONString(request),response.getErrmsg()); } } catch (ApiException e) { - syncDingTalkErrorOperLog(BaseConstantUrl.REGISTER_CALL_BACK,e.getMessage(),"registerCallBack()", JSON.toJSONString(request)); - e.printStackTrace(); + log.error("注册钉钉回调registerCallBack异常:{}",e.getMessage()); + throw new DingTalkSyncException(JSON.toJSONString(request),e.getErrMsg()); } } @Override - public void updateCallBack(DingtalkCallBack dingtalkCallBack) { + @DingTalkSyncLog(dingTalkListenerType = DingTalkListenerType.CALL_BACK_UPDATE,dingTalkUrl=BaseConstantUrl.UPDATE_CALL_BACK,dingTalkSyncType=DingTalkSyncType.AUTOMATIC) + public Boolean updateCallBack(DingtalkCallBack dingtalkCallBack) { DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.UPDATE_CALL_BACK); OapiCallBackUpdateCallBackRequest request = new OapiCallBackUpdateCallBackRequest(); request.setUrl(dingtalkCallBack.getUrl()); @@ -63,33 +68,30 @@ public class CallBackServiceImpl extends BaseService implements CallBackService try { OapiCallBackUpdateCallBackResponse response = client.execute(request,getDingTalkToken()); if(response.getErrcode()==0){ - syncDingTalkErrorOperLog(BaseConstantUrl.UPDATE_CALL_BACK,response.getMessage(),"updateCallBack()", JSON.toJSONString(request)); + return response.isSuccess(); }else { - //记录获取token失败日志 - syncDingTalkErrorOperLog(BaseConstantUrl.UPDATE_CALL_BACK,response.getErrmsg(),"updateCallBack()", JSON.toJSONString(request)); + throw new DingTalkSyncException(JSON.toJSONString(request),response.getErrmsg()); } } catch (ApiException e) { - syncDingTalkErrorOperLog(BaseConstantUrl.UPDATE_CALL_BACK,e.getMessage(),"updateCallBack()", JSON.toJSONString(request)); - e.printStackTrace(); + log.error("更新钉钉回调updateCallBack异常:{}",e.getMessage()); + throw new DingTalkSyncException(JSON.toJSONString(request),e.getErrMsg()); } } @Override + @DingTalkSyncLog(dingTalkListenerType = DingTalkListenerType.CALL_BACK_DELETE,dingTalkUrl=BaseConstantUrl.DELETE_CALL_BACK,dingTalkSyncType=DingTalkSyncType.AUTOMATIC) public void deleteCallBack(DingtalkCallBack dingtalkCallBack) { DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.DELETE_CALL_BACK); OapiCallBackDeleteCallBackRequest request = new OapiCallBackDeleteCallBackRequest(); request.setHttpMethod("GET"); try { OapiCallBackDeleteCallBackResponse response = client.execute(request, getDingTalkToken()); - if(response.getErrcode()==0){ - syncDingTalkErrorOperLog(BaseConstantUrl.DELETE_CALL_BACK,response.getMessage(),"deleteCallBack()", JSON.toJSONString(request)); - }else { - //记录获取token失败日志 - syncDingTalkErrorOperLog(BaseConstantUrl.DELETE_CALL_BACK,response.getErrmsg(),"deleteCallBack()", JSON.toJSONString(request)); + if(response.getErrcode()!=0){ + throw new DingTalkSyncException(JSON.toJSONString(request),response.getErrmsg()); } } catch (ApiException e) { - syncDingTalkErrorOperLog(BaseConstantUrl.DELETE_CALL_BACK,e.getMessage(),"deleteCallBack()", JSON.toJSONString(request)); - e.printStackTrace(); + log.error("删除钉钉回调deleteCallBack异常:{}",e.getMessage()); + throw new DingTalkSyncException(JSON.toJSONString(request),e.getErrMsg()); } } @@ -102,7 +104,7 @@ public class CallBackServiceImpl extends BaseService implements CallBackService OapiCallBackGetCallBackFailedResultResponse response = client.execute(request, getDingTalkToken()); if(response.getErrcode()==0){ List failedList = response.getFailedList(); - syncDingTalkErrorOperLog(BaseConstantUrl.CALL_BACK_FAILED_RESULT,response.getMessage(),"getCallBackFailedResult()", JSON.toJSONString(request)); + syncDingTalkSuccessOperLog(BaseConstantUrl.CALL_BACK_FAILED_RESULT,response.getMessage(),"getCallBackFailedResult()", JSON.toJSONString(request)); return failedList; }else { //记录获取token失败日志 @@ -114,40 +116,5 @@ public class CallBackServiceImpl extends BaseService implements CallBackService } return null; } - /** - * 获取token - * @return - */ - @Deprecated - public String getCallBackDingTalkToken(DingtalkCallBack dingtalkCallBack){ - //创建缓存,缓存默认是7100S - TimedCache timedCache = CacheUtil.newTimedCache(7100); - if(StringUtils.isEmpty(timedCache.get(TOKEN))){ - DefaultDingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.GET_TOKEN_URL); - OapiGettokenRequest request = new OapiGettokenRequest(); - request.setAppkey(dingtalkCallBack.getAppKey()); - request.setAppsecret(dingtalkCallBack.getAppSecret()); - request.setHttpMethod(Constants.GET); - try { - OapiGettokenResponse response = client.execute(request); - if(response.getErrcode()==0){ - timedCache.put(TOKEN,response.getAccessToken()); - syncDingTalkErrorOperLog(BaseConstantUrl.GET_TOKEN_URL,response.getMessage(),"getCallBackDingTalkToken()", JSON.toJSONString(request)); - return response.getAccessToken(); - }else { - //记录获取token失败日志 - syncDingTalkErrorOperLog(BaseConstantUrl.GET_TOKEN_URL,response.getErrmsg(),"getCallBackDingTalkToken()", JSON.toJSONString(request)); - return null; - } - } catch (ApiException e) { - syncDingTalkErrorOperLog(BaseConstantUrl.GET_TOKEN_URL,e.getMessage(),"getCallBackDingTalkToken()",JSON.toJSONString(request)); - e.printStackTrace(); - } - return null; - }else { - return timedCache.get(TOKEN); - } - - } } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/DepartmentServiceImpl.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/DepartmentServiceImpl.java index ddaf581..5f12292 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/DepartmentServiceImpl.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/DepartmentServiceImpl.java @@ -7,6 +7,10 @@ import com.dingtalk.api.request.OapiDepartmentCreateRequest; import com.dingtalk.api.request.OapiDepartmentListRequest; import com.dingtalk.api.response.OapiDepartmentCreateResponse; import com.dingtalk.api.response.OapiDepartmentListResponse; +import com.snow.common.annotation.DingTalkSyncLog; +import com.snow.common.enums.DingTalkListenerType; +import com.snow.common.enums.DingTalkSyncType; +import com.snow.common.exception.DingTalkSyncException; import com.snow.common.utils.spring.SpringUtils; import com.snow.dingtalk.common.BaseConstantUrl; import com.snow.dingtalk.common.BaseService; @@ -15,6 +19,7 @@ import com.snow.dingtalk.service.DepartmentService; import com.snow.system.service.impl.SysDeptServiceImpl; import com.taobao.api.ApiException; import com.taobao.api.Constants; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.List; @@ -26,11 +31,13 @@ import java.util.List; * @create: 2020-10-31 12:59 **/ @Service(value = "departmentServiceImpl") +@Slf4j public class DepartmentServiceImpl extends BaseService implements DepartmentService { private SysDeptServiceImpl sysDeptServiceImpl=SpringUtils.getBean("sysDeptServiceImpl"); @Override + @DingTalkSyncLog(dingTalkListenerType = DingTalkListenerType.DEPARTMENT_CREATE,dingTalkUrl=BaseConstantUrl.DEPARTMENT_CREATE) public Long createDepartment(DepartmentCreateRequest departmentDTO){ DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.DEPARTMENT_CREATE); OapiDepartmentCreateRequest request = new OapiDepartmentCreateRequest(); @@ -43,16 +50,15 @@ public class DepartmentServiceImpl extends BaseService implements DepartmentServ try { OapiDepartmentCreateResponse response = client.execute(request,getDingTalkToken()); if(response.getErrcode()==0){ - syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_CREATE,response.getMessage(),"createDepartment",JSON.toJSONString(request)); return response.getId(); }else { - syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_CREATE,response.getErrmsg(),"createDepartment",JSON.toJSONString(request)); + throw new DingTalkSyncException(JSON.toJSONString(request),response.getErrmsg()); } } catch (ApiException e) { - syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_CREATE,e.getMessage(),"createDepartment",JSON.toJSONString(request)); e.printStackTrace(); + log.error("钉钉创建部门createDepartment异常:{}",e.getMessage()); + throw new DingTalkSyncException(JSON.toJSONString(request),e.getErrMsg()); } - return null; } @@ -66,7 +72,7 @@ public class DepartmentServiceImpl extends BaseService implements DepartmentServ try { OapiDepartmentListResponse response = client.execute(request, getDingTalkToken()); if(response.getErrcode()==0){ - syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_LIST,response.getMessage(),"getDingTalkDepartmentList",JSON.toJSONString(request)); + syncDingTalkSuccessOperLog(BaseConstantUrl.DEPARTMENT_LIST,response.getMessage(),"getDingTalkDepartmentList",JSON.toJSONString(request)); return response.getDepartment(); }else { syncDingTalkErrorOperLog(BaseConstantUrl.DEPARTMENT_LIST,response.getErrmsg(),"getDingTalkDepartmentList",JSON.toJSONString(request)); @@ -79,9 +85,4 @@ public class DepartmentServiceImpl extends BaseService implements DepartmentServ } - public void sycnDepartmentData(){ - List dingTalkDepartmentList = getDingTalkDepartmentList(); - - - } } diff --git a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/UserServiceImpl.java b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/UserServiceImpl.java index 0699cf4..0ec73a5 100644 --- a/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/UserServiceImpl.java +++ b/snow-dingtalk/src/main/java/com/snow/dingtalk/service/impl/UserServiceImpl.java @@ -7,6 +7,9 @@ import com.dingtalk.api.request.OapiV2UserCreateRequest; import com.dingtalk.api.request.OapiV2UserDeleteRequest; import com.dingtalk.api.response.OapiV2UserCreateResponse; import com.dingtalk.api.response.OapiV2UserDeleteResponse; +import com.snow.common.annotation.DingTalkSyncLog; +import com.snow.common.enums.DingTalkListenerType; +import com.snow.common.exception.DingTalkSyncException; import com.snow.common.utils.StringUtils; import com.snow.common.utils.spring.SpringUtils; import com.snow.dingtalk.common.BaseConstantUrl; @@ -36,6 +39,7 @@ public class UserServiceImpl extends BaseService implements UserService { private SysPostServiceImpl sysPostService=SpringUtils.getBean("sysPostServiceImpl"); @Override + @DingTalkSyncLog(dingTalkListenerType = DingTalkListenerType.USER_CREATE,dingTalkUrl=BaseConstantUrl.USER_CREATE) public OapiV2UserCreateResponse.UserCreateResponse createUser(SysUser sysUser) { DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.USER_CREATE); OapiV2UserCreateRequest req = new OapiV2UserCreateRequest(); @@ -73,20 +77,19 @@ public class UserServiceImpl extends BaseService implements UserService { try { response = client.execute(req, getDingTalkToken()); if(response.getErrcode()==0){ - syncDingTalkErrorOperLog(BaseConstantUrl.USER_CREATE,response.getMessage(),"createUser",JSON.toJSONString(req)); OapiV2UserCreateResponse.UserCreateResponse result = response.getResult(); return result; }else { - syncDingTalkErrorOperLog(BaseConstantUrl.USER_CREATE,response.getErrmsg(),"createUser",JSON.toJSONString(req)); + throw new DingTalkSyncException(JSON.toJSONString(req),response.getErrmsg()); } } catch (ApiException e) { - syncDingTalkErrorOperLog(BaseConstantUrl.USER_CREATE,e.getMessage(),"createUser",JSON.toJSONString(req)); - e.printStackTrace(); + log.error("钉钉createUser异常:{}",e.getErrMsg()); + throw new DingTalkSyncException(JSON.toJSONString(req),e.getErrMsg()); } - return null; } @Override + @DingTalkSyncLog(dingTalkListenerType = DingTalkListenerType.USER_DELETE,dingTalkUrl=BaseConstantUrl.USER_DELETE) public void deleteUser(String ids) { DingTalkClient client = new DefaultDingTalkClient(BaseConstantUrl.USER_DELETE); OapiV2UserDeleteRequest req = new OapiV2UserDeleteRequest(); @@ -95,15 +98,15 @@ public class UserServiceImpl extends BaseService implements UserService { try { response = client.execute(req, getDingTalkToken()); if(response.getErrcode()==0){ - syncDingTalkErrorOperLog(BaseConstantUrl.USER_DELETE,response.getMessage(),"deleteUser",JSON.toJSONString(req)); String requestId = response.getRequestId(); log.info("dingTalk删除用户返回:{}",requestId); }else { - syncDingTalkErrorOperLog(BaseConstantUrl.USER_DELETE,response.getErrmsg(),"deleteUser",JSON.toJSONString(req)); + throw new DingTalkSyncException(JSON.toJSONString(req),response.getErrmsg()); } } catch (ApiException e) { - syncDingTalkErrorOperLog(BaseConstantUrl.USER_DELETE,e.getMessage(),"deleteUser",JSON.toJSONString(req)); + log.error("钉钉deleteUser异常:{}",e.getErrMsg()); e.printStackTrace(); + throw new DingTalkSyncException(JSON.toJSONString(req),e.getErrMsg()); } } } diff --git a/snow-framework/src/main/java/com/snow/framework/manager/factory/AsyncFactory.java b/snow-framework/src/main/java/com/snow/framework/manager/factory/AsyncFactory.java index d0640fe..65d14eb 100644 --- a/snow-framework/src/main/java/com/snow/framework/manager/factory/AsyncFactory.java +++ b/snow-framework/src/main/java/com/snow/framework/manager/factory/AsyncFactory.java @@ -5,6 +5,8 @@ import java.util.TimerTask; import com.snow.framework.shiro.session.OnlineSession; import com.snow.framework.util.LogUtils; import com.snow.framework.util.ShiroUtils; +import com.snow.system.domain.SysDingtalkSyncLog; +import com.snow.system.service.ISysDingtalkSyncLogService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.snow.common.constant.Constants; @@ -81,6 +83,25 @@ public class AsyncFactory }; } + /** + * 操作日志记录 + * + * @param operLog 操作日志信息 + * @return 任务task + */ + public static TimerTask recordDingTalkSyncOper(final SysDingtalkSyncLog operLog) + { + return new TimerTask() + { + @Override + public void run() + { + // 远程查询操作地点 + operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp())); + SpringUtils.getBean(ISysDingtalkSyncLogService.class).insertSysDingtalkSyncLog(operLog); + } + }; + } /** * 记录登陆信息 * diff --git a/snow-system/src/main/java/com/snow/system/domain/SysDingtalkSyncLog.java b/snow-system/src/main/java/com/snow/system/domain/SysDingtalkSyncLog.java new file mode 100644 index 0000000..b1aa523 --- /dev/null +++ b/snow-system/src/main/java/com/snow/system/domain/SysDingtalkSyncLog.java @@ -0,0 +1,141 @@ +package com.snow.system.domain; + +import java.util.Date; +import com.snow.common.annotation.Excel; +import com.snow.common.core.domain.BaseEntity; +import com.snow.common.enums.DingTalkListenerType; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * 钉钉同步日志记录对象 sys_dingtalk_sync_log + * + * @author snow + * @date 2020-11-13 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SysDingtalkSyncLog extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 日志主键 */ + private Long logId; + + /** 模块标题 */ + @Excel(name = "模块标题") + private String title; + + /** 模块类型(0其它 1用户 2部门 3角色 10回调) */ + @Excel(name = "模块类型", readConverterExp = "0=其它,1=用户,2=部门,3=角色,1=0回调") + private Integer moduleType; + + /** 业务类型(0其它 1新增 2修改 3删除) */ + @Excel(name = "业务类型", readConverterExp = "0=其它,1=新增,2=修改,3=删除") + private Integer businessType; + + /** 方法名称 */ + @Excel(name = "方法名称") + private String method; + + /** 请求方式 */ + @Excel(name = "请求方式") + private String requestMethod; + + /** 操作类别(0其它 1自动同步 2手工同步) */ + @Excel(name = "操作类别", readConverterExp = "0=其它,1=自动同步,2=手工同步") + private Integer operatorType; + + /** 操作人员 */ + @Excel(name = "操作人员") + private String operName; + + /** 部门名称 */ + @Excel(name = "部门名称") + private String deptName; + + /** 请求URL */ + @Excel(name = "请求URL") + private String operUrl; + + /** 主机地址 */ + @Excel(name = "主机地址") + private String operIp; + + /** 操作地点 */ + @Excel(name = "操作地点") + private String operLocation; + + /** 请求原参数 */ + @Excel(name = "请求原参数") + private String operSourceParam; + + /** 请求钉钉参数 */ + @Excel(name = "请求钉钉参数") + private String operDingtalkParam; + + /** 返回参数 */ + @Excel(name = "返回参数") + private String jsonResult; + + /** 操作状态(0正常 1异常) */ + @Excel(name = "操作状态", readConverterExp = "0=正常,1=异常") + private Integer status; + + /** 错误消息 */ + @Excel(name = "错误消息") + private String errorMsg; + + /** 操作时间 */ + @Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd") + private Date operTime; + + private DingTalkListenerType dingTalkListenerType; + + public SysDingtalkSyncLog(DingTalkListenerType dingTalkListenerType, String method, String operUrl, Integer operatorType, String operSourceParam, String operDingtalkParam, String jsonResult){ + this.dingTalkListenerType=dingTalkListenerType; + this.method= method; + this.operUrl=operUrl; + this.operatorType=operatorType; + this.operSourceParam= operSourceParam; + this.operDingtalkParam=operDingtalkParam; + this.jsonResult= jsonResult; + } + public SysDingtalkSyncLog(DingTalkListenerType dingTalkListenerType,String method,String operUrl,Integer operatorType,String operSourceParam,String operDingtalkParam,String jsonResult, String errorMsg){ + this.dingTalkListenerType=dingTalkListenerType; + this.method= method; + this.operUrl=operUrl; + this.operatorType=operatorType; + this.operSourceParam= operSourceParam; + this.operDingtalkParam=operDingtalkParam; + this.jsonResult= jsonResult; + this.errorMsg= errorMsg; + } + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("logId", getLogId()) + .append("title", getTitle()) + .append("moduleType", getModuleType()) + .append("businessType", getBusinessType()) + .append("method", getMethod()) + .append("requestMethod", getRequestMethod()) + .append("operatorType", getOperatorType()) + .append("operName", getOperName()) + .append("deptName", getDeptName()) + .append("operUrl", getOperUrl()) + .append("operIp", getOperIp()) + .append("operLocation", getOperLocation()) + .append("operSourceParam", getOperSourceParam()) + .append("operDingtalkParam", getOperDingtalkParam()) + .append("jsonResult", getJsonResult()) + .append("status", getStatus()) + .append("errorMsg", getErrorMsg()) + .append("operTime", getOperTime()) + .toString(); + } +} diff --git a/snow-system/src/main/java/com/snow/system/mapper/SysDingtalkSyncLogMapper.java b/snow-system/src/main/java/com/snow/system/mapper/SysDingtalkSyncLogMapper.java new file mode 100644 index 0000000..34ee9da --- /dev/null +++ b/snow-system/src/main/java/com/snow/system/mapper/SysDingtalkSyncLogMapper.java @@ -0,0 +1,61 @@ +package com.snow.system.mapper; + +import java.util.List; +import com.snow.system.domain.SysDingtalkSyncLog; + +/** + * 钉钉同步日志记录Mapper接口 + * + * @author snow + * @date 2020-11-13 + */ +public interface SysDingtalkSyncLogMapper +{ + /** + * 查询钉钉同步日志记录 + * + * @param logId 钉钉同步日志记录ID + * @return 钉钉同步日志记录 + */ + public SysDingtalkSyncLog selectSysDingtalkSyncLogById(Long logId); + + /** + * 查询钉钉同步日志记录列表 + * + * @param sysDingtalkSyncLog 钉钉同步日志记录 + * @return 钉钉同步日志记录集合 + */ + public List selectSysDingtalkSyncLogList(SysDingtalkSyncLog sysDingtalkSyncLog); + + /** + * 新增钉钉同步日志记录 + * + * @param sysDingtalkSyncLog 钉钉同步日志记录 + * @return 结果 + */ + public int insertSysDingtalkSyncLog(SysDingtalkSyncLog sysDingtalkSyncLog); + + /** + * 修改钉钉同步日志记录 + * + * @param sysDingtalkSyncLog 钉钉同步日志记录 + * @return 结果 + */ + public int updateSysDingtalkSyncLog(SysDingtalkSyncLog sysDingtalkSyncLog); + + /** + * 删除钉钉同步日志记录 + * + * @param logId 钉钉同步日志记录ID + * @return 结果 + */ + public int deleteSysDingtalkSyncLogById(Long logId); + + /** + * 批量删除钉钉同步日志记录 + * + * @param logIds 需要删除的数据ID + * @return 结果 + */ + public int deleteSysDingtalkSyncLogByIds(String[] logIds); +} diff --git a/snow-system/src/main/java/com/snow/system/service/ISysDingtalkSyncLogService.java b/snow-system/src/main/java/com/snow/system/service/ISysDingtalkSyncLogService.java new file mode 100644 index 0000000..134a12c --- /dev/null +++ b/snow-system/src/main/java/com/snow/system/service/ISysDingtalkSyncLogService.java @@ -0,0 +1,61 @@ +package com.snow.system.service; + +import java.util.List; +import com.snow.system.domain.SysDingtalkSyncLog; + +/** + * 钉钉同步日志记录Service接口 + * + * @author snow + * @date 2020-11-13 + */ +public interface ISysDingtalkSyncLogService +{ + /** + * 查询钉钉同步日志记录 + * + * @param logId 钉钉同步日志记录ID + * @return 钉钉同步日志记录 + */ + public SysDingtalkSyncLog selectSysDingtalkSyncLogById(Long logId); + + /** + * 查询钉钉同步日志记录列表 + * + * @param sysDingtalkSyncLog 钉钉同步日志记录 + * @return 钉钉同步日志记录集合 + */ + public List selectSysDingtalkSyncLogList(SysDingtalkSyncLog sysDingtalkSyncLog); + + /** + * 新增钉钉同步日志记录 + * + * @param sysDingtalkSyncLog 钉钉同步日志记录 + * @return 结果 + */ + public int insertSysDingtalkSyncLog(SysDingtalkSyncLog sysDingtalkSyncLog); + + /** + * 修改钉钉同步日志记录 + * + * @param sysDingtalkSyncLog 钉钉同步日志记录 + * @return 结果 + */ + public int updateSysDingtalkSyncLog(SysDingtalkSyncLog sysDingtalkSyncLog); + + /** + * 批量删除钉钉同步日志记录 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteSysDingtalkSyncLogByIds(String ids); + + /** + * 删除钉钉同步日志记录信息 + * + * @param logId 钉钉同步日志记录ID + * @return 结果 + */ + public int deleteSysDingtalkSyncLogById(Long logId); +} diff --git a/snow-system/src/main/java/com/snow/system/service/impl/SysDingtalkSyncLogServiceImpl.java b/snow-system/src/main/java/com/snow/system/service/impl/SysDingtalkSyncLogServiceImpl.java new file mode 100644 index 0000000..7587af8 --- /dev/null +++ b/snow-system/src/main/java/com/snow/system/service/impl/SysDingtalkSyncLogServiceImpl.java @@ -0,0 +1,97 @@ +package com.snow.system.service.impl; + +import java.util.Date; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.snow.system.mapper.SysDingtalkSyncLogMapper; +import com.snow.system.domain.SysDingtalkSyncLog; +import com.snow.system.service.ISysDingtalkSyncLogService; +import com.snow.common.core.text.Convert; + +/** + * 钉钉同步日志记录Service业务层处理 + * + * @author snow + * @date 2020-11-13 + */ +@Service +public class SysDingtalkSyncLogServiceImpl implements ISysDingtalkSyncLogService +{ + @Autowired + private SysDingtalkSyncLogMapper sysDingtalkSyncLogMapper; + + /** + * 查询钉钉同步日志记录 + * + * @param logId 钉钉同步日志记录ID + * @return 钉钉同步日志记录 + */ + @Override + public SysDingtalkSyncLog selectSysDingtalkSyncLogById(Long logId) + { + return sysDingtalkSyncLogMapper.selectSysDingtalkSyncLogById(logId); + } + + /** + * 查询钉钉同步日志记录列表 + * + * @param sysDingtalkSyncLog 钉钉同步日志记录 + * @return 钉钉同步日志记录 + */ + @Override + public List selectSysDingtalkSyncLogList(SysDingtalkSyncLog sysDingtalkSyncLog) + { + return sysDingtalkSyncLogMapper.selectSysDingtalkSyncLogList(sysDingtalkSyncLog); + } + + /** + * 新增钉钉同步日志记录 + * + * @param sysDingtalkSyncLog 钉钉同步日志记录 + * @return 结果 + */ + @Override + public int insertSysDingtalkSyncLog(SysDingtalkSyncLog sysDingtalkSyncLog) + { + + sysDingtalkSyncLog.setOperTime(new Date()); + return sysDingtalkSyncLogMapper.insertSysDingtalkSyncLog(sysDingtalkSyncLog); + } + + /** + * 修改钉钉同步日志记录 + * + * @param sysDingtalkSyncLog 钉钉同步日志记录 + * @return 结果 + */ + @Override + public int updateSysDingtalkSyncLog(SysDingtalkSyncLog sysDingtalkSyncLog) + { + return sysDingtalkSyncLogMapper.updateSysDingtalkSyncLog(sysDingtalkSyncLog); + } + + /** + * 删除钉钉同步日志记录对象 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + @Override + public int deleteSysDingtalkSyncLogByIds(String ids) + { + return sysDingtalkSyncLogMapper.deleteSysDingtalkSyncLogByIds(Convert.toStrArray(ids)); + } + + /** + * 删除钉钉同步日志记录信息 + * + * @param logId 钉钉同步日志记录ID + * @return 结果 + */ + @Override + public int deleteSysDingtalkSyncLogById(Long logId) + { + return sysDingtalkSyncLogMapper.deleteSysDingtalkSyncLogById(logId); + } +} diff --git a/snow-system/src/main/java/com/snow/system/service/impl/SysUserServiceImpl.java b/snow-system/src/main/java/com/snow/system/service/impl/SysUserServiceImpl.java index ca676b9..6bea4d3 100644 --- a/snow-system/src/main/java/com/snow/system/service/impl/SysUserServiceImpl.java +++ b/snow-system/src/main/java/com/snow/system/service/impl/SysUserServiceImpl.java @@ -213,7 +213,7 @@ public class SysUserServiceImpl implements ISysUserService // 新增用户与角色管理 insertUserRole(user.getUserId(), user.getRoleIds()); //同步用户数据 - SyncEvent syncEvent = new SyncEvent(user, DingTalkListenerType.USER_CREATED); + SyncEvent syncEvent = new SyncEvent(user, DingTalkListenerType.USER_CREATE); applicationContext.publishEvent(syncEvent); return rows; } diff --git a/snow-system/src/main/resources/mapper/system/SysDingtalkSyncLogMapper.xml b/snow-system/src/main/resources/mapper/system/SysDingtalkSyncLogMapper.xml new file mode 100644 index 0000000..54c6129 --- /dev/null +++ b/snow-system/src/main/resources/mapper/system/SysDingtalkSyncLogMapper.xml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + select log_id, title, module_type, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_source_param, oper_dingtalk_param, json_result, status, error_msg, oper_time from sys_dingtalk_sync_log + + + + + + + + insert into sys_dingtalk_sync_log + + title, + module_type, + business_type, + method, + request_method, + operator_type, + oper_name, + dept_name, + oper_url, + oper_ip, + oper_location, + oper_source_param, + oper_dingtalk_param, + json_result, + status, + error_msg, + oper_time, + + + #{title}, + #{moduleType}, + #{businessType}, + #{method}, + #{requestMethod}, + #{operatorType}, + #{operName}, + #{deptName}, + #{operUrl}, + #{operIp}, + #{operLocation}, + #{operSourceParam}, + #{operDingtalkParam}, + #{jsonResult}, + #{status}, + #{errorMsg}, + #{operTime}, + + + + + update sys_dingtalk_sync_log + + title = #{title}, + module_type = #{moduleType}, + business_type = #{businessType}, + method = #{method}, + request_method = #{requestMethod}, + operator_type = #{operatorType}, + oper_name = #{operName}, + dept_name = #{deptName}, + oper_url = #{operUrl}, + oper_ip = #{operIp}, + oper_location = #{operLocation}, + oper_source_param = #{operSourceParam}, + oper_dingtalk_param = #{operDingtalkParam}, + json_result = #{jsonResult}, + status = #{status}, + error_msg = #{errorMsg}, + oper_time = #{operTime}, + + where log_id = #{logId} + + + + delete from sys_dingtalk_sync_log where log_id = #{logId} + + + + delete from sys_dingtalk_sync_log where log_id in + + #{logId} + + + + \ No newline at end of file From 0126366f956056b7ae9b055be365518362cb0a5e Mon Sep 17 00:00:00 2001 From: jinqiming <45981669@qq.com> Date: Fri, 13 Nov 2020 18:01:24 +0800 Subject: [PATCH 19/82] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=92=89=E9=92=89?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=90=8C=E6=AD=A5=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/SysDingtalkSyncLogController.java | 8 ++ .../templates/system/log/detail.html | 74 +++++++++++++++++++ .../resources/templates/system/log/log.html | 56 +++++++++----- 3 files changed, 118 insertions(+), 20 deletions(-) create mode 100644 snow-admin/src/main/resources/templates/system/log/detail.html diff --git a/snow-admin/src/main/java/com/snow/web/controller/system/SysDingtalkSyncLogController.java b/snow-admin/src/main/java/com/snow/web/controller/system/SysDingtalkSyncLogController.java index 41183a6..60e731d 100644 --- a/snow-admin/src/main/java/com/snow/web/controller/system/SysDingtalkSyncLogController.java +++ b/snow-admin/src/main/java/com/snow/web/controller/system/SysDingtalkSyncLogController.java @@ -123,4 +123,12 @@ public class SysDingtalkSyncLogController extends BaseController { return toAjax(sysDingtalkSyncLogService.deleteSysDingtalkSyncLogByIds(ids)); } + + @RequiresPermissions("system:log:detail") + @GetMapping("/detail/{operId}") + public String detail(@PathVariable("operId") Long operId, ModelMap mmap) + { + mmap.put("operLog", sysDingtalkSyncLogService.selectSysDingtalkSyncLogById(operId)); + return prefix + "/detail"; + } } diff --git a/snow-admin/src/main/resources/templates/system/log/detail.html b/snow-admin/src/main/resources/templates/system/log/detail.html new file mode 100644 index 0000000..59fa2e6 --- /dev/null +++ b/snow-admin/src/main/resources/templates/system/log/detail.html @@ -0,0 +1,74 @@ + + + + + + + +
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+ +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/snow-admin/src/main/resources/templates/system/log/log.html b/snow-admin/src/main/resources/templates/system/log/log.html index 2b1cfff..43b7435 100644 --- a/snow-admin/src/main/resources/templates/system/log/log.html +++ b/snow-admin/src/main/resources/templates/system/log/log.html @@ -110,6 +110,8 @@ var removeFlag = [[${@permission.hasPermi('system:log:remove')}]]; var moduleTypeDatas = [[${@dict.getType('dingtalk_module_type')}]]; var businessTypeDatas = [[${@dict.getType('dingtalk_oper_type')}]]; + var syncTypeDatas = [[${@dict.getType('dingtalk_sync_type')}]]; + var prefix = ctx + "system/log"; $(function() { @@ -119,26 +121,28 @@ updateUrl: prefix + "/edit/{id}", removeUrl: prefix + "/remove", exportUrl: prefix + "/export", - modalName: "钉钉同步日志记录", + detailUrl: prefix + "/detail/{id}", + modalName: "钉钉同步日志", columns: [{ checkbox: true }, { field: 'logId', - title: '日志主键', - visible: false + title: '日志编号', + visible: true }, + { + field: 'moduleType', + title: '模块类型', + formatter: function(value, row, index) { + return $.table.selectDictLabel(moduleTypeDatas, value); + } + }, { field: 'title', title: '模块标题' }, - { - field: 'moduleType', - title: '模块类型', - formatter: function(value, row, index) { - return $.table.selectDictLabel(moduleTypeDatas, value); - } - }, + { field: 'businessType', title: '业务类型', @@ -146,17 +150,20 @@ return $.table.selectDictLabel(businessTypeDatas, value); } }, - { + /* { field: 'method', title: '方法名称' - }, + },*/ { field: 'requestMethod', title: '请求方式' }, { field: 'operatorType', - title: '操作类别' + title: '操作类别', + formatter: function(value, row, index) { + return $.table.selectDictLabel(syncTypeDatas, value); + } }, { field: 'operName', @@ -166,10 +173,10 @@ field: 'deptName', title: '部门名称' }, - { + /* { field: 'operUrl', title: '请求URL' - }, + },*/ { field: 'operIp', title: '主机地址' @@ -178,7 +185,7 @@ field: 'operLocation', title: '操作地点' }, - { + /* { field: 'operSourceParam', title: '请求原参数' }, @@ -189,15 +196,23 @@ { field: 'jsonResult', title: '返回参数' - }, + },*/ { field: 'status', - title: '操作状态' + title: '操作状态', + align: 'center', + formatter: function(value, row, index) { + if (value == 0) { + return '成功'; + } else if (value == 1) { + return '失败'; + } + } }, - { + /* { field: 'errorMsg', title: '错误消息' - }, + },*/ { field: 'operTime', title: '操作时间' @@ -209,6 +224,7 @@ var actions = []; actions.push('编辑 '); actions.push('删除'); + actions.push('详细'); return actions.join(''); } }] From 65bc8105e6e2c4efa48fc8cc67fc28515c9c66ac Mon Sep 17 00:00:00 2001 From: "459816669@qq.com" <459816669@qq.com> Date: Sat, 14 Nov 2020 21:04:56 +0800 Subject: [PATCH 20/82] =?UTF-8?q?=E8=B0=83=E9=80=9A=E5=9B=9E=E8=B0=83?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...k.java => DingTalkCallBackController.java} | 30 +++-- .../system/DingtalkCallBackController.java | 11 +- .../resources/templates/system/back/back.html | 19 +--- .../templates/system/back/detail.html | 74 ------------ .../templates/system/log/detail.html | 24 +++- .../resources/templates/system/log/log.html | 80 ++----------- .../snow/framework/config/ShiroConfig.java | 2 + .../snow/system/domain/DingtalkCallBack.java | 107 +----------------- .../mapper/system/DingtalkCallBackMapper.xml | 18 +-- 9 files changed, 79 insertions(+), 286 deletions(-) rename snow-admin/src/main/java/com/snow/web/controller/dingtalk/{DingTalkCallBack.java => DingTalkCallBackController.java} (73%) delete mode 100644 snow-admin/src/main/resources/templates/system/back/detail.html diff --git a/snow-admin/src/main/java/com/snow/web/controller/dingtalk/DingTalkCallBack.java b/snow-admin/src/main/java/com/snow/web/controller/dingtalk/DingTalkCallBackController.java similarity index 73% rename from snow-admin/src/main/java/com/snow/web/controller/dingtalk/DingTalkCallBack.java rename to snow-admin/src/main/java/com/snow/web/controller/dingtalk/DingTalkCallBackController.java index 4dc5333..521b42d 100644 --- a/snow-admin/src/main/java/com/snow/web/controller/dingtalk/DingTalkCallBack.java +++ b/snow-admin/src/main/java/com/snow/web/controller/dingtalk/DingTalkCallBackController.java @@ -4,11 +4,15 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.dingtalk.oapi.lib.aes.DingTalkEncryptor; import com.snow.dingtalk.common.EventNameEnum; +import com.snow.system.domain.DingtalkCallBack; +import com.snow.system.service.impl.DingtalkCallBackServiceImpl; import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.*; + +import java.util.Collections; +import java.util.List; /** * @author qimingjin @@ -16,9 +20,13 @@ import org.springframework.web.bind.annotation.RestController; * @Description: * @date 2020/11/3 17:11 */ -@RestController("/dingTalk") +@RestController @Slf4j -public class DingTalkCallBack { +@RequestMapping("/dingTalk") +public class DingTalkCallBackController { + + @Autowired + private DingtalkCallBackServiceImpl dingtalkCallBackService; /** * 钉钉回调 @@ -35,10 +43,18 @@ public class DingTalkCallBack { @RequestParam(value = "nonce") String nonce, @RequestBody(required = false) JSONObject body ) { + DingtalkCallBack dingtalkCallBack=new DingtalkCallBack(); + dingtalkCallBack.setFlag(true); + List dingtalkCallBacks = dingtalkCallBackService.selectDingtalkCallBackList(dingtalkCallBack); + if(!CollectionUtils.isEmpty(dingtalkCallBacks)){ + dingtalkCallBack=dingtalkCallBacks.get(0); + }else { + return "fail"; + } String params = "signature:" + signature + " timestamp:" + timestamp + " nonce:" + nonce + " body:" + body; try { log.info("begin callback:" + params); - DingTalkEncryptor dingTalkEncryptor = new DingTalkEncryptor("","",""); + DingTalkEncryptor dingTalkEncryptor = new DingTalkEncryptor(dingtalkCallBack.getToken(),dingtalkCallBack.getAesKey(),dingtalkCallBack.getCorpId()); // 从post请求的body中获取回调信息的加密数据进行解密处理 String encrypt = body.getString("encrypt"); diff --git a/snow-admin/src/main/java/com/snow/web/controller/system/DingtalkCallBackController.java b/snow-admin/src/main/java/com/snow/web/controller/system/DingtalkCallBackController.java index 6a26ab1..a6d6fde 100644 --- a/snow-admin/src/main/java/com/snow/web/controller/system/DingtalkCallBackController.java +++ b/snow-admin/src/main/java/com/snow/web/controller/system/DingtalkCallBackController.java @@ -37,8 +37,6 @@ public class DingtalkCallBackController extends BaseController @Autowired private IDingtalkCallBackService dingtalkCallBackService; - @Autowired - private CallBackServiceImpl callBackServiceImpl; @RequiresPermissions("system:back:view") @GetMapping() @@ -132,12 +130,5 @@ public class DingtalkCallBackController extends BaseController return toAjax(dingtalkCallBackService.deleteDingtalkCallBackByIds(ids)); } - @RequiresPermissions("system:back:detail") - @GetMapping("/detail/{id}") - public String detail(@PathVariable("id") Long operId, ModelMap mmap) - { - List callBackFailedResult = callBackServiceImpl.getCallBackFailedResult(); - mmap.put("operLog", callBackFailedResult); - return prefix + "/detail"; - } + } diff --git a/snow-admin/src/main/resources/templates/system/back/back.html b/snow-admin/src/main/resources/templates/system/back/back.html index e2a1d66..6f4923e 100644 --- a/snow-admin/src/main/resources/templates/system/back/back.html +++ b/snow-admin/src/main/resources/templates/system/back/back.html @@ -24,7 +24,7 @@
- @@ -66,18 +66,10 @@ title: 'ID', visible: false }, - /* { - field: 'token', - title: 'token' - }, { - field: 'aesKey', - title: '数据加密密钥' - },*/ - { - field: 'callBackName', - title: '回调名称' - }, + field: 'callBackName', + title: '回调名称' + }, { field: 'url', title: '回调url' @@ -89,8 +81,7 @@ formatter: function(value, row, index) { var actions = []; actions.push('编辑 '); - actions.push('删除'); - actions.push('获取失败结果'); + actions.push('删除 '); return actions.join(''); } }] diff --git a/snow-admin/src/main/resources/templates/system/back/detail.html b/snow-admin/src/main/resources/templates/system/back/detail.html deleted file mode 100644 index 02c5db6..0000000 --- a/snow-admin/src/main/resources/templates/system/back/detail.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - -
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
- -
-
-
- -
-
-
-
- -
-
-
-
-
- - - - - \ No newline at end of file diff --git a/snow-admin/src/main/resources/templates/system/log/detail.html b/snow-admin/src/main/resources/templates/system/log/detail.html index 59fa2e6..0c2181c 100644 --- a/snow-admin/src/main/resources/templates/system/log/detail.html +++ b/snow-admin/src/main/resources/templates/system/log/detail.html @@ -9,7 +9,7 @@
-
+
@@ -33,13 +33,25 @@
- +
+
+ +
+
+
+
+ +
+ + +
+
@@ -57,11 +69,19 @@ + +
+ + diff --git a/snow-flowable/src/main/resources/static/browserconfig.xml b/snow-flowable/src/main/resources/static/browserconfig.xml new file mode 100644 index 0000000..006d54a --- /dev/null +++ b/snow-flowable/src/main/resources/static/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #da532c + + + diff --git a/snow-flowable/src/main/resources/static/display-cmmn/cmmn-draw.js b/snow-flowable/src/main/resources/static/display-cmmn/cmmn-draw.js new file mode 100644 index 0000000..039c392 --- /dev/null +++ b/snow-flowable/src/main/resources/static/display-cmmn/cmmn-draw.js @@ -0,0 +1,491 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function _cmmnGetColor(element, defaultColor) +{ + var strokeColor; + if(element.current) { + strokeColor = CURRENT_COLOR; + } else if(element.completed) { + strokeColor = COMPLETED_COLOR; + } else { + strokeColor = defaultColor; + } + return strokeColor; +} + +function _drawPlanModel(planModel) +{ + var rect = paper.rect(planModel.x, planModel.y, planModel.width, planModel.height); + + rect.attr({"stroke-width": 1, + "stroke": "#000000", + "fill": "white" + }); + + if (planModel.name) + { + var planModelName = paper.text(planModel.x + 14, planModel.y + (planModel.height / 2), planModel.name).attr({ + "text-anchor" : "middle", + "font-family" : "Arial", + "font-size" : "12", + "fill" : "#000000" + }); + + planModelName.transform("r270"); + } +} + +function _drawSubProcess(element) +{ + var rect = paper.rect(element.x, element.y, element.width, element.height, 4); + + var strokeColor = _cmmnGetColor(element, MAIN_STROKE_COLOR); + + rect.attr({"stroke-width": 1, + "stroke": strokeColor, + "fill": "white" + }); +} + +function _drawVariableServiceTaskIcon(element) +{ + _drawTask(element); + if (element.taskType === "mail") + { + _drawSendTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.taskType === "camel") + { + _drawCamelTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.taskType === "mule") + { + _drawMuleTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.taskType === "http") + { + _drawHttpTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.stencilIconId) + { + paper.image("../service/stencilitem/" + element.stencilIconId + "/icon", element.x + 4, element.y + 4, 16, 16); + } + else + { + _drawServiceTaskIcon(paper, element.x + 4, element.y + 4); + } + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawHttpServiceTask(element) +{ + _drawTask(element); + _drawHttpTaskIcon(paper, element.x + 4, element.y + 4); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawHumanTask(element) +{ + _drawTask(element); + _drawHumanTaskIcon(paper, element.x + 4, element.y + 4); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawCaseTask(element) +{ + _drawTask(element); + _drawCaseTaskIcon(paper, element.x + 1, element.y + 1); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawProcessTask(element) +{ + _drawTask(element); + _drawProcessTaskIcon(paper, element.x + 1, element.y + 1); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawScriptTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("m 5,2 0,0.094 c 0.23706,0.064 0.53189,0.1645 0.8125,0.375 0.5582,0.4186 1.05109,1.228 1.15625,2.5312 l 8.03125,0 1,0 1,0 c 0,-3 -2,-3 -2,-3 l -10,0 z M 4,3 4,13 2,13 c 0,3 2,3 2,3 l 9,0 c 0,0 2,0 2,-3 L 15,6 6,6 6,5.5 C 6,4.1111 5.5595,3.529 5.1875,3.25 4.8155,2.971 4.5,3 4.5,3 L 4,3 z"); + path1.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#72a7d0" + }); + + var scriptTaskIcon = paper.set(); + scriptTaskIcon.push(path1); + + scriptTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawScriptServiceTask(element) +{ + _drawTask(element); + _drawScriptTaskIcon(paper, element.x + 4, element.y + 4); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawDecisionTask(element) +{ + _drawTask(element); + _drawDecisionTaskIcon(paper, element.x + 1, element.y + 1); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawServiceTask(element) +{ + _drawTask(element); + _drawVariableServiceTaskIcon(element); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawTask(element) +{ + var rectAttrs = {}; + + // Stroke + var strokeColor = _cmmnGetColor(element, ACTIVITY_STROKE_COLOR); + rectAttrs['stroke'] = strokeColor; + + var strokeWidth; + if (strokeColor === ACTIVITY_STROKE_COLOR) { + strokeWidth = TASK_STROKE; + } else { + strokeWidth = TASK_HIGHLIGHT_STROKE; + } + + var width = element.width - (strokeWidth / 2); + var height = element.height - (strokeWidth / 2); + + var rect = paper.rect(element.x, element.y, width, height, 4); + rectAttrs['stroke-width'] = strokeWidth; + + // Fill + rectAttrs['fill'] = ACTIVITY_FILL_COLOR; + + rect.attr(rectAttrs); + rect.id = element.id; + + if (element.name) { + this._drawMultilineText(element.name, element.x, element.y, element.width, element.height, "middle", "middle", 11); + } +} + +function _drawTimerEventListener(element) +{ + _drawEventListener(element); + _drawTimerEventListenerIcon(paper, element); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawUserEventListener(element) +{ + _drawEventListener(element); + _drawUserEventListenerIcon(paper, element); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawGenericEventListener(element) +{ + _drawEventListener(element); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawEventListener(element) +{ + var x = element.x + (element.width / 2); + var y = element.y + (element.height / 2); + + var circle = paper.circle(x, y, 15); + + circle.attr({"stroke-width": 1, + "stroke": "black", + "fill": "white" + }); + + circle.id = element.id; +} + +function _drawMilestone(element) +{ + var rectAttrs = {}; + + // Stroke + var strokeColor = _cmmnGetColor(element, ACTIVITY_STROKE_COLOR); + rectAttrs['stroke'] = strokeColor; + + var strokeWidth; + if (strokeColor === ACTIVITY_STROKE_COLOR) { + strokeWidth = TASK_STROKE; + } else { + strokeWidth = TASK_HIGHLIGHT_STROKE; + } + + var width = element.width - (strokeWidth / 2); + var height = element.height - (strokeWidth / 2); + + var rect = paper.rect(element.x, element.y, width, height, 24); + rectAttrs['stroke-width'] = strokeWidth; + + // Fill + rectAttrs['fill'] = WHITE_FILL_COLOR; + + rect.attr(rectAttrs); + rect.id = element.id; + + if (element.name) { + this._drawMultilineText(element.name, element.x, element.y, element.width, element.height, "middle", "middle", 11); + } +} + +function _drawStage(element) +{ + var rectAttrs = {}; + + // Stroke + var strokeColor = _cmmnGetColor(element, ACTIVITY_STROKE_COLOR); + rectAttrs['stroke'] = strokeColor; + + var strokeWidth; + if (strokeColor === ACTIVITY_STROKE_COLOR) { + strokeWidth = TASK_STROKE; + } else { + strokeWidth = TASK_HIGHLIGHT_STROKE; + } + + var width = element.width - (strokeWidth / 2); + var height = element.height - (strokeWidth / 2); + + var rect = paper.rect(element.x, element.y, width, height, 16); + rectAttrs['stroke-width'] = strokeWidth; + + // Fill + rectAttrs['fill'] = WHITE_FILL_COLOR; + + rect.attr(rectAttrs); + rect.id = element.id; + + if (element.name) { + this._drawMultilineText(element.name, element.x + 10, element.y + 5, element.width, element.height, "start", "top", 11); + } +} + +function _drawPlanModel(element) +{ + var rectAttrs = {}; + + // Stroke + var strokeColor = _cmmnGetColor(element, ACTIVITY_STROKE_COLOR); + rectAttrs['stroke'] = strokeColor; + + var strokeWidth; + if (strokeColor === ACTIVITY_STROKE_COLOR) { + strokeWidth = TASK_STROKE; + } else { + strokeWidth = TASK_HIGHLIGHT_STROKE; + } + + var width = element.width - (strokeWidth / 2); + var height = element.height - (strokeWidth / 2); + + var rect = paper.rect(element.x, element.y, width, height, 4); + rectAttrs['stroke-width'] = strokeWidth; + + // Fill + rectAttrs['fill'] = WHITE_FILL_COLOR; + + rect.attr(rectAttrs); + rect.id = element.id; + + var path1 = paper.path("M20 55 L37 34 L275 34 L291 55"); + path1.attr({ + "opacity": 1, + "stroke": strokeColor, + "fill": "#ffffff" + }); + + var planModelHeader = paper.set(); + planModelHeader.push(path1); + + planModelHeader.translate(element.x, element.y - 55); + if (element.name) { + this._drawMultilineText(element.name, element.x + 10, element.y - 16, 275, element.height, "middle", "top", 11); + } +} + +function _drawEntryCriterion(element) +{ + var strokeColor = _cmmnGetColor(element, MAIN_STROKE_COLOR); + + var rhombus = paper.path("M" + element.x + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + (element.y + element.height) + + "L" + (element.x + element.width) + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + element.y + "z" + ); + + // Fill + var gatewayFillColor = WHITE_FILL_COLOR; + + // Opacity + var gatewayOpacity = 1.0; + + rhombus.attr("stroke-width", 1); + rhombus.attr("stroke", strokeColor); + rhombus.attr("fill", gatewayFillColor); + rhombus.attr("fill-opacity", gatewayOpacity); + + rhombus.id = element.id; +} + +function _drawExitCriterion(element) +{ + var strokeColor = _cmmnGetColor(element, MAIN_STROKE_COLOR); + + var rhombus = paper.path("M" + element.x + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + (element.y + element.height) + + "L" + (element.x + element.width) + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + element.y + "z" + ); + + // Fill + var gatewayFillColor = '#000000'; + + // Opacity + var gatewayOpacity = 1.0; + + rhombus.attr("stroke-width", 1); + rhombus.attr("stroke", strokeColor); + rhombus.attr("fill", gatewayFillColor); + rhombus.attr("fill-opacity", gatewayOpacity); + + rhombus.id = element.id; +} + +function _drawMultilineText(text, x, y, boxWidth, boxHeight, horizontalAnchor, verticalAnchor, fontSize) +{ + if (!text || text == "") + { + return; + } + + var textBoxX, textBoxY; + var width = boxWidth - (2 * TEXT_PADDING); + + if (horizontalAnchor === "middle") + { + textBoxX = x + (boxWidth / 2); + } + else if (horizontalAnchor === "start") + { + textBoxX = x; + } + + textBoxY = y + (boxHeight / 2); + + var t = paper.text(textBoxX + TEXT_PADDING, textBoxY + TEXT_PADDING).attr({ + "text-anchor" : horizontalAnchor, + "font-family" : "Arial", + "font-size" : fontSize, + "fill" : "#373e48" + }); + + var abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + t.attr({ + "text" : abc + }); + var letterWidth = t.getBBox().width / abc.length; + + t.attr({ + "text" : text + }); + var removedLineBreaks = text.split("\n"); + var x = 0, s = []; + for (var r = 0; r < removedLineBreaks.length; r++) + { + var words = removedLineBreaks[r].split(" "); + for ( var i = 0; i < words.length; i++) { + + var l = words[i].length; + if (x + (l * letterWidth) > width) { + s.push("\n"); + x = 0; + } + x += l * letterWidth; + s.push(words[i] + " "); + } + s.push("\n"); + x = 0; + } + t.attr({ + "text" : s.join("") + }); + + if (verticalAnchor && verticalAnchor === "top") + { + t.attr({"y": y + (t.getBBox().height / 2)}); + } +} + +function _drawAssociation(flow){ + + var polyline = new Polyline(flow.id, flow.waypoints, ASSOCIATION_STROKE, paper); + polyline.element = paper.path(polyline.path); + polyline.element.attr({"stroke-width": ASSOCIATION_STROKE}); + polyline.element.attr({"stroke-dasharray": ". "}); + polyline.element.attr({"stroke":"#585858"}); + + polyline.element.id = flow.id; + + var polylineInvisible = new Polyline(flow.id, flow.waypoints, ASSOCIATION_STROKE, paper); + + polylineInvisible.element = paper.path(polyline.path); + polylineInvisible.element.attr({ + "opacity": 0, + "stroke-width": 8, + "stroke" : "#000000" + }); + + _showTip(jQuery(polylineInvisible.element.node), flow); + + polylineInvisible.element.mouseover(function() { + paper.getById(polyline.element.id).attr({"stroke":"blue"}); + }); + + polylineInvisible.element.mouseout(function() { + paper.getById(polyline.element.id).attr({"stroke":"#585858"}); + }); +} + +function _drawArrowHead(line, connectionType) +{ + var doubleArrowWidth = 2 * ARROW_WIDTH; + + var arrowHead = paper.path("M0 0L-" + (ARROW_WIDTH / 2 + .5) + " -" + doubleArrowWidth + "L" + (ARROW_WIDTH/2 + .5) + " -" + doubleArrowWidth + "z"); + + // anti smoothing + if (this.strokeWidth%2 == 1) + line.x2 += .5, line.y2 += .5; + + arrowHead.transform("t" + line.x2 + "," + line.y2 + ""); + arrowHead.transform("...r" + Raphael.deg(line.angle - Math.PI / 2) + " " + 0 + " " + 0); + + arrowHead.attr("fill", "#585858"); + + arrowHead.attr("stroke-width", SEQUENCEFLOW_STROKE); + arrowHead.attr("stroke", "#585858"); + + return arrowHead; +} diff --git a/snow-flowable/src/main/resources/static/display-cmmn/cmmn-icons.js b/snow-flowable/src/main/resources/static/display-cmmn/cmmn-icons.js new file mode 100644 index 0000000..e15023b --- /dev/null +++ b/snow-flowable/src/main/resources/static/display-cmmn/cmmn-icons.js @@ -0,0 +1,180 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function _drawHumanTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("m 1,17 16,0 0,-1.7778 -5.333332,-3.5555 0,-1.7778 c 1.244444,0 1.244444,-2.3111 1.244444,-2.3111 l 0,-3.0222 C 12.555557,0.8221 9.0000001,1.0001 9.0000001,1.0001 c 0,0 -3.5555556,-0.178 -3.9111111,3.5555 l 0,3.0222 c 0,0 0,2.3111 1.2444443,2.3111 l 0,1.7778 L 1,15.2222 1,17 17,17"); + path1.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#d1b575" + }); + + var userTaskIcon = paper.set(); + userTaskIcon.push(path1); + + userTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawServiceTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("M 8,1 7.5,2.875 c 0,0 -0.02438,0.250763 -0.40625,0.4375 C 7.05724,3.330353 7.04387,3.358818 7,3.375 6.6676654,3.4929791 6.3336971,3.6092802 6.03125,3.78125 6.02349,3.78566 6.007733,3.77681 6,3.78125 5.8811373,3.761018 5.8125,3.71875 5.8125,3.71875 l -1.6875,-1 -1.40625,1.4375 0.96875,1.65625 c 0,0 0.065705,0.068637 0.09375,0.1875 0.002,0.00849 -0.00169,0.022138 0,0.03125 C 3.6092802,6.3336971 3.4929791,6.6676654 3.375,7 3.3629836,7.0338489 3.3239228,7.0596246 3.3125,7.09375 3.125763,7.4756184 2.875,7.5 2.875,7.5 L 1,8 l 0,2 1.875,0.5 c 0,0 0.250763,0.02438 0.4375,0.40625 0.017853,0.03651 0.046318,0.04988 0.0625,0.09375 0.1129372,0.318132 0.2124732,0.646641 0.375,0.9375 -0.00302,0.215512 -0.09375,0.34375 -0.09375,0.34375 L 2.6875,13.9375 4.09375,15.34375 5.78125,14.375 c 0,0 0.1229911,-0.09744 0.34375,-0.09375 0.2720511,0.147787 0.5795915,0.23888 0.875,0.34375 0.033849,0.01202 0.059625,0.05108 0.09375,0.0625 C 7.4756199,14.874237 7.5,15.125 7.5,15.125 L 8,17 l 2,0 0.5,-1.875 c 0,0 0.02438,-0.250763 0.40625,-0.4375 0.03651,-0.01785 0.04988,-0.04632 0.09375,-0.0625 0.332335,-0.117979 0.666303,-0.23428 0.96875,-0.40625 0.177303,0.0173 0.28125,0.09375 0.28125,0.09375 l 1.65625,0.96875 1.40625,-1.40625 -0.96875,-1.65625 c 0,0 -0.07645,-0.103947 -0.09375,-0.28125 0.162527,-0.290859 0.262063,-0.619368 0.375,-0.9375 0.01618,-0.04387 0.04465,-0.05724 0.0625,-0.09375 C 14.874237,10.52438 15.125,10.5 15.125,10.5 L 17,10 17,8 15.125,7.5 c 0,0 -0.250763,-0.024382 -0.4375,-0.40625 C 14.669647,7.0572406 14.641181,7.0438697 14.625,7 14.55912,6.8144282 14.520616,6.6141566 14.4375,6.4375 c -0.224363,-0.4866 0,-0.71875 0,-0.71875 L 15.40625,4.0625 14,2.625 l -1.65625,1 c 0,0 -0.253337,0.1695664 -0.71875,-0.03125 l -0.03125,0 C 11.405359,3.5035185 11.198648,3.4455201 11,3.375 10.95613,3.3588185 10.942759,3.3303534 10.90625,3.3125 10.524382,3.125763 10.5,2.875 10.5,2.875 L 10,1 8,1 z m 1,5 c 1.656854,0 3,1.3431458 3,3 0,1.656854 -1.343146,3 -3,3 C 7.3431458,12 6,10.656854 6,9 6,7.3431458 7.3431458,6 9,6 z"); + path1.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#72a7d0" + }); + + var serviceTaskIcon = paper.set(); + serviceTaskIcon.push(path1); + + serviceTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawCaseTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("M5 8 L9 4 L18 4 L 21 7"); + path1.attr({ + "opacity": 1, + "stroke": "#000000", + "fill": "#000000" + }); + + var path2 = paper.path("M1 23 L1 4 L30 4 L30 23z"); + path2.attr({ + "opacity": 1, + "stroke": "#000000", + "fill": "#F4F6F7" + }); + + var caseTaskIcon = paper.set(); + caseTaskIcon.push(path1); + caseTaskIcon.push(path2); + + caseTaskIcon.translate(startX, startY); + caseTaskIcon.scale(0.7, 0.7); +} + +function _drawProcessTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("M1 23 L7 11 L1 0 L30 0 L 35 11 L 30 23z"); + path1.attr({ + "opacity": 1, + "stroke": "#000000", + "fill": "#F4F6F7" + }); + + var processTaskIcon = paper.set(); + processTaskIcon.push(path1); + + processTaskIcon.translate(startX, startY); + processTaskIcon.scale(0.7, 0.7); +} + +function _drawDecisionTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("m 1,2 0,14 16,0 0,-14 z m 1.9,2.4000386 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m -8.67364,3.9 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m -8.67364,3.9 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z"); + path1.attr({ + "opacity": 1, + "stroke": "#000000", + "fill": "#F4F6F7" + }); + + var decisionTaskIcon = paper.set(); + decisionTaskIcon.push(path1); + + decisionTaskIcon.translate(startX, startY); + decisionTaskIcon.scale(0.7, 0.7); +} + +function _drawHttpTaskIcon(paper, startX, startY) +{ + var path = paper.path("m 16.704699,5.9229055 q 0.358098,0 0.608767,0.2506681 0.250669,0.250668 0.250669,0.6087677 0,0.3580997 -0.250669,0.6087677 -0.250669,0.2506679 -0.608767,0.2506679 -0.358098,0 -0.608767,-0.2506679 -0.250669,-0.250668 -0.250669,-0.6087677 0,-0.3580997 0.250669,-0.6087677 0.250669,-0.2506681 0.608767,-0.2506681 z m 2.578308,-2.0053502 q -2.229162,0 -3.854034,0.6759125 -1.624871,0.6759067 -3.227361,2.2694472 -0.716197,0.725146 -1.575633,1.7457293 L 7.2329969,8.7876913 Q 7.0897576,8.8055849 7.000233,8.9309334 L 4.9948821,12.368677 q -0.035811,0.06267 -0.035811,0.143242 0,0.107426 0.080572,0.205905 l 0.5729577,0.572957 q 0.125334,0.116384 0.2864786,0.07162 l 2.4708789,-0.760963 2.5156417,2.515645 -0.76096,2.470876 q -0.009,0.02687 -0.009,0.08057 0,0.125338 0.08058,0.205905 l 0.572957,0.572958 q 0.170096,0.152194 0.349146,0.04476 l 3.437744,-2.005351 q 0.125335,-0.08953 0.143239,-0.232763 l 0.17905,-3.392986 q 1.02058,-0.859435 1.745729,-1.575629 1.67411,-1.6830612 2.309735,-3.2049805 0.635625,-1.5219191 0.635625,-3.8585111 0,-0.1253369 -0.08505,-0.2148575 -0.08505,-0.089526 -0.201431,-0.089526 z"); + path.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#16964d" + }); + + startX += -2; + startY += -2; + + path.transform("T" + startX + "," + startY); + +} + +function _drawBusinessRuleTaskIcon(paper, startX, startY) { + var path1 = paper.path("m 1,2 0,14 16,0 0,-14 z m 1.45458,5.6000386 2.90906,0 0,2.7999224 -2.90906,0 z m 4.36364,0 8.72718,0 0,2.7999224 -8.72718,0 z m -4.36364,4.1998844 2.90906,0 0,2.800116 -2.90906,0 z m 4.36364,0 8.72718,0 0,2.800116 -8.72718,0 z"); + path1.attr({ + "stroke": "none", + "fill": "#72a7d0" + }); + + var businessRuleTaskIcon = paper.set(); + businessRuleTaskIcon.push(path1); + + businessRuleTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawTimerEventListenerIcon(paper, element) +{ + var x = element.x + (element.width / 2); + var y = element.y + (element.height / 2); + + var circle = paper.circle(x, y, 10); + + circle.attr({"stroke-width": 1, + "stroke": "black", + "fill": "none" + }); + + var path = paper.path("M 10 0 C 4.4771525 0 0 4.4771525 0 10 C 0 15.522847 4.4771525 20 10 20 C 15.522847 20 20 15.522847 20 10 C 20 4.4771525 15.522847 1.1842379e-15 10 0 z M 9.09375 1.03125 C 9.2292164 1.0174926 9.362825 1.0389311 9.5 1.03125 L 9.5 3.5 L 10.5 3.5 L 10.5 1.03125 C 15.063526 1.2867831 18.713217 4.9364738 18.96875 9.5 L 16.5 9.5 L 16.5 10.5 L 18.96875 10.5 C 18.713217 15.063526 15.063526 18.713217 10.5 18.96875 L 10.5 16.5 L 9.5 16.5 L 9.5 18.96875 C 4.9364738 18.713217 1.2867831 15.063526 1.03125 10.5 L 3.5 10.5 L 3.5 9.5 L 1.03125 9.5 C 1.279102 5.0736488 4.7225326 1.4751713 9.09375 1.03125 z M 9.5 5 L 9.5 8.0625 C 8.6373007 8.2844627 8 9.0680195 8 10 C 8 11.104569 8.8954305 12 10 12 C 10.931981 12 11.715537 11.362699 11.9375 10.5 L 14 10.5 L 14 9.5 L 11.9375 9.5 C 11.756642 8.7970599 11.20294 8.2433585 10.5 8.0625 L 10.5 5 L 9.5 5 z"); + path.attr({ + "stroke": "none", + "fill": "#585858" + }); + path.transform("T" + (element.x + 5) + "," + (element.y + 5)); + return path; +} + +function _drawUserEventListenerIcon(paper, element) { + var userTaskIcon = paper.set(); + var path1 = paper.path("M0.585,24.167h24.083v-7.833c0,0-2.333-3.917-7.083-5.167h-9.25 c-4.417,1.333-7.833,5.75-7.833,5.75L0.585,24.167z"); + path1.attr({"opacity": 1, "stroke": "none", "fill": "#F4F6F7"}); + userTaskIcon.push(path1); + + var path2 = paper.path("M6,20L6,24"); + path2.attr({"opacity": 1, "stroke": "white", "fill": "none"}); + userTaskIcon.push(path2); + + var path3 = paper.path("M20,20L20,24"); + path3.attr({"opacity": 1, "stroke": "white", "fill": "none"}); + userTaskIcon.push(path3); + + var circle = paper.circle(13.002, 5.916, 5.417); + circle.attr({"stroke-width": 1, "stroke": "black", "fill": "#000000"}); + userTaskIcon.push(circle); + + var path4 = paper.path("M8.043,7.083c0,0,2.814-2.426,5.376-1.807s4.624-0.693,4.624-0.693 c0.25,1.688,0.042,3.75-1.458,5.584c0,0,1.083,0.75,1.083,1.5s0.125,1.875-1,3s-5.5,1.25-6.75,0S8.668,12.834,8.668,12 s0.583-1.25,1.25-1.917C8.835,9.5,7.419,7.708,8.043,7.083z"); + path4.attr({"opacity": 1, "stroke": "none", "fill": "#F0EFF0"}); + userTaskIcon.push(path4); + + var x = (element.width / 2) - 2; + var y = (element.height / 2) - 2; + var circle2 = paper.circle(x, y, 17); + circle2.attr({"stroke-width": 1, "stroke": "#F0EFF0", "fill": "none"}); + userTaskIcon.push(circle2); + + userTaskIcon.transform("S0.7,0.7" + "T" + (element.x + 2) + "," + (element.y + 2)); + return userTaskIcon; +} diff --git a/snow-flowable/src/main/resources/static/display-cmmn/displaymodel.css b/snow-flowable/src/main/resources/static/display-cmmn/displaymodel.css new file mode 100644 index 0000000..ddaf36e --- /dev/null +++ b/snow-flowable/src/main/resources/static/display-cmmn/displaymodel.css @@ -0,0 +1,24 @@ +div[class*='ui-tooltip-flowable-'] { + background-color: #ffffff; + border-color: #c5c5c5; + color: #4a4a4a; + font-family: Verdana; + font-size: 12px; +} + +div[class*='ui-tooltip-flowable-'] .qtip-content { + color: #4a4a4a; + background-color: #ffffff; + font-family: Verdana; + font-size: 12px; +} + +.ui-tooltip-flowable-cmmn .qtip-titlebar { + color: #FFFFFF; + font-size: 12px; + background: #2B414F; +} + +.ui-tooltip-flowable-cmmn .qtip-tip { + background-color: #2B414F; +} diff --git a/snow-flowable/src/main/resources/static/display-cmmn/displaymodel.html b/snow-flowable/src/main/resources/static/display-cmmn/displaymodel.html new file mode 100644 index 0000000..a56de7d --- /dev/null +++ b/snow-flowable/src/main/resources/static/display-cmmn/displaymodel.html @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/display-cmmn/displaymodel.js b/snow-flowable/src/main/resources/static/display-cmmn/displaymodel.js new file mode 100644 index 0000000..a4c2d2e --- /dev/null +++ b/snow-flowable/src/main/resources/static/display-cmmn/displaymodel.js @@ -0,0 +1,272 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +var NORMAL_STROKE = 1; +var ASSOCIATION_STROKE = 2; +var TASK_STROKE = 1; +var TASK_HIGHLIGHT_STROKE = 2; + +var TEXT_COLOR= "#373e48"; +var CURRENT_COLOR= "#017501"; +var HOVER_COLOR= "#666666"; +var ACTIVITY_STROKE_COLOR = "#bbbbbb"; +var ACTIVITY_FILL_COLOR = "#f9f9f9"; +var WHITE_FILL_COLOR = "#ffffff"; +var MAIN_STROKE_COLOR = "#585858"; + +var TEXT_PADDING = 3; +var ARROW_WIDTH = 4; +var MARKER_WIDTH = 12; + +var TASK_FONT = {font: "11px Arial", opacity: 1, fill: Raphael.rgb(0, 0, 0)}; + +// icons +var ICON_SIZE = 16; +var ICON_PADDING = 4; + +var INITIAL_CANVAS_WIDTH; +var INITIAL_CANVAS_HEIGHT; + +var paper; +var viewBox; +var viewBoxWidth; +var viewBoxHeight; + +var canvasWidth; +var canvasHeight; + +var modelDiv = jQuery('#cmmnModel'); +var modelId = modelDiv.attr('data-model-id'); +var historyModelId = modelDiv.attr('data-history-id'); +var caseDefinitionId = modelDiv.attr('data-case-definition-id'); +var modelType = modelDiv.attr('data-model-type'); + +var elementsAdded = new Array(); +var elementsRemoved = new Array(); + +function _showTip(htmlNode, element) +{ + // Default tooltip, no custom tool tip set + if (documentation === undefined) { + var documentation = ""; + if (element.name && element.name.length > 0) { + documentation += "Name: " + element.name + "

"; + } + + if (element.properties) { + for (var i = 0; i < element.properties.length; i++) { + var propName = element.properties[i].name; + if (element.properties[i].type && element.properties[i].type === 'list') { + documentation += '' + propName + ':
'; + for (var j = 0; j < element.properties[i].value.length; j++) { + documentation += '' + element.properties[i].value[j] + '
'; + } + } + else { + documentation += '' + propName + ': ' + element.properties[i].value + '
'; + } + } + } + } + + var text = element.type + " "; + if (element.name && element.name.length > 0) + { + text += element.name; + } + else + { + text += element.id; + } + + htmlNode.qtip({ + content: { + text: documentation, + title: { + text: text + } + }, + position: { + my: 'top left', + at: 'bottom center', + viewport: jQuery('#cmmnModel') + }, + hide: { + fixed: true, delay: 500, + event: 'click mouseleave' + }, + style: { + classes: 'ui-tooltip-flowable-cmmn' + } + }); +} + +function _addHoverLogic(element, type, defaultColor) +{ + var strokeColor = _cmmnGetColor(element, defaultColor); + var topBodyRect = null; + if (type === "rect") + { + topBodyRect = paper.rect(element.x, element.y, element.width, element.height); + } + else if (type === "circle") + { + var x = element.x + (element.width / 2); + var y = element.y + (element.height / 2); + topBodyRect = paper.circle(x, y, 15); + } + else if (type === "rhombus") + { + topBodyRect = paper.path("M" + element.x + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + (element.y + element.height) + + "L" + (element.x + element.width) + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + element.y + "z" + ); + } + + var opacity = 0; + var fillColor = "#ffffff"; + if (jQuery.inArray(element.id, elementsAdded) >= 0) + { + opacity = 0.2; + fillColor = "green"; + } + + if (jQuery.inArray(element.id, elementsRemoved) >= 0) + { + opacity = 0.2; + fillColor = "red"; + } + + topBodyRect.attr({ + "opacity": opacity, + "stroke" : "none", + "fill" : fillColor + }); + _showTip(jQuery(topBodyRect.node), element); + + topBodyRect.mouseover(function() { + paper.getById(element.id).attr({"stroke":HOVER_COLOR}); + }); + + topBodyRect.mouseout(function() { + paper.getById(element.id).attr({"stroke":strokeColor}); + }); +} + +function _zoom(zoomIn) +{ + var tmpCanvasWidth, tmpCanvasHeight; + if (zoomIn) + { + tmpCanvasWidth = canvasWidth * (1.0/0.90); + tmpCanvasHeight = canvasHeight * (1.0/0.90); + } + else + { + tmpCanvasWidth = canvasWidth * (1.0/1.10); + tmpCanvasHeight = canvasHeight * (1.0/1.10); + } + + if (tmpCanvasWidth != canvasWidth || tmpCanvasHeight != canvasHeight) + { + canvasWidth = tmpCanvasWidth; + canvasHeight = tmpCanvasHeight; + paper.setSize(canvasWidth, canvasHeight); + } +} + +var modelUrl; + +if (modelType == 'runtime') { + if (historyModelId) { + modelUrl = FLOWABLE.APP_URL.getCaseInstancesHistoryModelJsonUrl(historyModelId); + } else { + modelUrl = FLOWABLE.APP_URL.getCaseInstancesModelJsonUrl(modelId); + } +} else if (modelType == 'design') { + if (historyModelId) { + modelUrl = FLOWABLE.APP_URL.getModelHistoryModelJsonUrl(modelId, historyModelId); + } else { + modelUrl = FLOWABLE.APP_URL.getModelModelJsonUrl(modelId); + } +} else if (modelType == 'case-definition') { + modelUrl = FLOWABLE.APP_URL.getCaseDefinitionModelJsonUrl(caseDefinitionId); +} + +var request = jQuery.ajax({ + type: 'get', + url: modelUrl + '?nocaching=' + new Date().getTime() +}); + +request.success(function(data, textStatus, jqXHR) { + + if ((!data.elements || data.elements.length == 0) && (!data.pools || data.pools.length == 0)) return; + + INITIAL_CANVAS_WIDTH = data.diagramWidth; + + if (modelType == 'design') { + INITIAL_CANVAS_WIDTH += 20; + } else { + INITIAL_CANVAS_WIDTH += 30; + } + + INITIAL_CANVAS_HEIGHT = data.diagramHeight + 50; + canvasWidth = INITIAL_CANVAS_WIDTH; + canvasHeight = INITIAL_CANVAS_HEIGHT; + viewBoxWidth = INITIAL_CANVAS_WIDTH; + viewBoxHeight = INITIAL_CANVAS_HEIGHT; + + if (modelType == 'design') { + var headerBarHeight = 170; + var offsetY = 0; + if (jQuery(window).height() > (canvasHeight + headerBarHeight)) + { + offsetY = (jQuery(window).height() - headerBarHeight - canvasHeight) / 2; + } + + if (offsetY > 50) { + offsetY = 50; + } + + jQuery('#cmmnModel').css('marginTop', offsetY); + } + + jQuery('#cmmnModel').width(INITIAL_CANVAS_WIDTH); + jQuery('#cmmnModel').height(INITIAL_CANVAS_HEIGHT); + paper = Raphael(document.getElementById('cmmnModel'), canvasWidth, canvasHeight); + paper.setViewBox(0, 0, viewBoxWidth, viewBoxHeight, false); + paper.renderfix(); + + var modelElements = data.elements; + for (var i = 0; i < modelElements.length; i++) + { + var element = modelElements[i]; + //try { + var drawFunction = eval("_draw" + element.type); + drawFunction(element); + //} catch(err) {console.log(err);} + } + + if (data.flows) + { + for (var i = 0; i < data.flows.length; i++) + { + var flow = data.flows[i]; + _drawAssociation(flow); + } + } +}); + +request.error(function(jqXHR, textStatus, errorThrown) { + alert("error"); +}); diff --git a/snow-flowable/src/main/resources/static/display/Gruntfile.js b/snow-flowable/src/main/resources/static/display/Gruntfile.js new file mode 100644 index 0000000..9aac21f --- /dev/null +++ b/snow-flowable/src/main/resources/static/display/Gruntfile.js @@ -0,0 +1,153 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +module.exports = function (grunt) { + + require('load-grunt-tasks')(grunt); + require('time-grunt')(grunt); + + grunt.initConfig({ + yeoman: { + app: require('./package.json').appPath || 'app', + dist: 'dist' + }, + clean: { + dist: { + files: [ + { + dot: true, + src: [ + '.tmp', + '<%= yeoman.dist %>/*', + '!<%= yeoman.dist %>/.git*' + ] + } + ] + }, + server: '.tmp' + }, + useminPrepare: { + html: 'displaymodel.html', + options: { + dest: '<%= yeoman.dist %>/' + } + }, + usemin: { + html: ['<%= yeoman.dist %>/{,*/}*.html'], + css: ['<%= yeoman.dist %>/display/styles/{,*/}*.css'], + options: { + dirs: ['<%= yeoman.dist %>'] + } + }, + // Put files not handled in other tasks here + copy: { + dist: { + files: [{ + expand: true, + dot: true, + cwd: '.', + dest: '<%= yeoman.dist %>', + src: [ + 'fonts/*' + ] + }, { + expand: true, + cwd: '.tmp/images', + dest: '<%= yeoman.dist %>/images', + src: [ + 'generated/*' + ] + }] + }, + styles: { + expand: true, + cwd: 'styles', + dest: '.tmp/styles/', + src: '{,*/}*.css' + }, + index: { + expand: true, + cwd: './', + src: ['*.html', 'views/**/**.html'], + dest: '<%= yeoman.dist %>' + }, + copyCss : { + files: [ + {expand: true, cwd:'.tmp/concat/display/styles/', src:'*.css', dest:'<%= yeoman.dist %>/display/styles/', filter: 'isFile'} + ] + }, + copyJs : { + files: [ + {expand: true, cwd:'.tmp/concat/display/scripts', src:'*.js', dest:'<%= yeoman.dist %>/display/scripts/', filter: 'isFile'} + ] + }, + }, + ngAnnotate: { + dist: { + files: [ + { + expand: true, + cwd: '.tmp/concat/display/scripts', + src: '*.js', + dest: '.tmp/concat/display/scripts' + } + ] + } + }, + uglify: { + dist: { + options: { + mangle: true + }, + files: { + '<%= yeoman.dist %>/display/scripts/displaymodel-logic.js': [ + '<%= yeoman.dist %>/display/scripts/displaymodel-logic.js' + ] + } + } + }, + rev: { + dist: { + files: { + src: [ + '<%= yeoman.dist %>/display/{,*/}*.js', + '<%= yeoman.dist %>/display/{,*/}*.css', + '<%= yeoman.dist %>/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' + ] + } + } + } + }); + + grunt.registerTask('buildApp', [ + 'clean:dist', + 'useminPrepare', + 'copy:styles', + 'concat', + 'copy:dist', + 'ngAnnotate', + 'copy:copyCss', + 'copy:copyJs', + 'copy:index', + 'uglify', + 'rev', + 'usemin' + ]); + + + grunt.registerTask('default', [ + 'buildApp' + ]); + +}; diff --git a/snow-flowable/src/main/resources/static/display/Polyline.js b/snow-flowable/src/main/resources/static/display/Polyline.js new file mode 100644 index 0000000..aafef8f --- /dev/null +++ b/snow-flowable/src/main/resources/static/display/Polyline.js @@ -0,0 +1,387 @@ +/* Copyright 2005-2015 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * 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, paper) { + /* 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.paper = paper; + + this.closePath = false; + + this.init(); +}; + +Polyline.prototype = { + id: null, + points: [], + path: [], + anchors: [], + strokeWidth: 1, + radius: 1, + showDetails: false, + paper: null, + 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); + this.pushAnchor(ANCHOR_TYPE.main, line1.x2, line1.y2); + } + + 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){ + if (this.points.length > i && this.points[i]) { + return {x1: this.points[i].x, y1: this.points[i].y, x2: this.points[i+1].x, y2: this.points[i+1].y}; + } else { + return undefined; + } + }, + getLine: function(i){ + var line = this._getLine(i); + if (line != undefined) { + 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){ + 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 { + 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)); + + 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 10)); + } + + // 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) + { + path.push(["Z"]); + } + + this.path = path; + }, + + transform: function(transformation) + { + this.element.transform(transformation); + }, + attr: function(attrs) + { + // 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 = []; + 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; +}; diff --git a/snow-flowable/src/main/resources/static/display/bpmn-draw.js b/snow-flowable/src/main/resources/static/display/bpmn-draw.js new file mode 100644 index 0000000..b573976 --- /dev/null +++ b/snow-flowable/src/main/resources/static/display/bpmn-draw.js @@ -0,0 +1,866 @@ +/* Copyright 2005-2015 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +function _bpmnGetColor(element, defaultColor) +{ + var strokeColor; + if(element.current) { + strokeColor = CURRENT_COLOR; + } else if(element.completed) { + strokeColor = COMPLETED_COLOR; + } else { + strokeColor = defaultColor; + } + return strokeColor; +} + +function _drawPool(pool) +{ + var rect = paper.rect(pool.x, pool.y, pool.width, pool.height); + + rect.attr({"stroke-width": 1, + "stroke": "#000000", + "fill": "white" + }); + + if (pool.name) + { + var poolName = paper.text(pool.x + 14, pool.y + (pool.height / 2), pool.name).attr({ + "text-anchor" : "middle", + "font-family" : "Arial", + "font-size" : "12", + "fill" : "#000000" + }); + + poolName.transform("r270"); + } + + if (pool.lanes) + { + for (var i = 0; i < pool.lanes.length; i++) + { + var lane = pool.lanes[i]; + _drawLane(lane); + } + } +} + +function _drawLane(lane) +{ + var rect = paper.rect(lane.x, lane.y, lane.width, lane.height); + + rect.attr({"stroke-width": 1, + "stroke": "#000000", + "fill": "white" + }); + + if (lane.name) + { + var laneName = paper.text(lane.x + 10, lane.y + (lane.height / 2), lane.name).attr({ + "text-anchor" : "middle", + "font-family" : "Arial", + "font-size" : "12", + "fill" : "#000000" + }); + + laneName.transform("r270"); + } +} + +function _drawSubProcess(element) +{ + var rect = paper.rect(element.x, element.y, element.width, element.height, 4); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + rect.attr({"stroke-width": 1, + "stroke": strokeColor, + "fill": "white" + }); +} + +function _drawTransaction(element) +{ + var rect = paper.rect(element.x, element.y, element.width, element.height, 4); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + rect.attr({"stroke-width": 1, + "stroke": strokeColor, + "fill": "white" + }); + + var borderRect = paper.rect(element.x + 2, element.y + 2, element.width - 4, element.height -4, 4); + + borderRect.attr({"stroke-width": 1, + "stroke": "black", + "fill": "none" + }); +} + +function _drawEventSubProcess(element) +{ + var rect = paper.rect(element.x, element.y, element.width, element.height, 4); + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + rect.attr({"stroke-width": 1, + "stroke": strokeColor, + "stroke-dasharray": ".", + "fill": "white" + }); +} + +function _drawAdhocSubProcess(element) +{ + var rect = paper.rect(element.x, element.y, element.width, element.height, 4); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + rect.attr({"stroke-width": 1, + "stroke": strokeColor, + "fill": "white" + }); + + paper.text(element.x + (element.width / 2), element.y + element.height - 8).attr({ + "text-anchor" : "middle", + "font-family" : "Arial", + "font-size" : 20, + "text" : "~", + "fill" : "#373e48" + }); +} + +function _drawStartEvent(element) +{ + var startEvent = _drawEvent(element, NORMAL_STROKE, 15); + startEvent.click(function() { + _zoom(true); + }); + _addHoverLogic(element, "circle", MAIN_STROKE_COLOR); +} + +function _drawEndEvent(element) +{ + var endEvent = _drawEvent(element, ENDEVENT_STROKE, 14); + endEvent.click(function() { + _zoom(false); + }); + _addHoverLogic(element, "circle", MAIN_STROKE_COLOR); +} + +function _drawEvent(element, strokeWidth, radius) +{ + var x = element.x + (element.width / 2); + var y = element.y + (element.height / 2); + + var circle = paper.circle(x, y, radius); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + // Fill + var eventFillColor = _determineCustomFillColor(element, "#ffffff"); + + // Opacity + var eventOpacity = 1.0; + if (customActivityBackgroundOpacity) { + eventOpacity = customActivityBackgroundOpacity; + } + + if (element.interrupting === undefined || element.interrupting) { + circle.attr({ + "stroke-width": strokeWidth, + "stroke": strokeColor, + "fill": eventFillColor, + "fill-opacity": eventOpacity + }); + + } else { + circle.attr({ + "stroke-width": strokeWidth, + "stroke": strokeColor, + "stroke-dasharray": ".", + "fill": eventFillColor, + "fill-opacity": eventOpacity + }); + } + + circle.id = element.id; + + _drawEventIcon(paper, element); + + return circle; +} + +function _drawServiceTask(element) +{ + _drawTask(element); + if (element.taskType === "mail") + { + _drawSendTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.taskType === "camel") + { + _drawCamelTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.taskType === "mule") + { + _drawMuleTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.taskType === "http") + { + _drawHttpTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.taskType === "shell") + { + _drawShellTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.taskType === "dmn") { + _drawDecisionTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.stencilIconId) + { + paper.image("../service/stencilitem/" + element.stencilIconId + "/icon", element.x + 4, element.y + 4, 16, 16); + } + else + { + _drawServiceTaskIcon(paper, element.x + 4, element.y + 4); + } + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawHttpServiceTask(element) +{ + _drawTask(element); + _drawHttpTaskIcon(paper, element.x + 4, element.y + 4); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawCallActivity(element) +{ + var width = element.width - (CALL_ACTIVITY_STROKE / 2); + var height = element.height - (CALL_ACTIVITY_STROKE / 2); + + var rect = paper.rect(element.x, element.y, width, height, 4); + + var strokeColor = _bpmnGetColor(element, ACTIVITY_STROKE_COLOR); + + // Fill + var callActivityFillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR); + + // Opacity + var callActivityOpacity = 1.0; + if (customActivityBackgroundOpacity) { + callActivityOpacity = customActivityBackgroundOpacity; + } + + rect.attr({"stroke-width": CALL_ACTIVITY_STROKE, + "stroke": strokeColor, + "fill": callActivityFillColor, + "fill-opacity": callActivityOpacity + }); + + rect.id = element.id; + + if (element.name) { + this._drawMultilineText(element.name, element.x, element.y, element.width, element.height, "middle", "middle", 11); + } + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawScriptTask(element) +{ + _drawTask(element); + _drawScriptTaskIcon(paper, element.x + 4, element.y + 4); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawUserTask(element) +{ + _drawTask(element); + _drawUserTaskIcon(paper, element.x + 4, element.y + 4); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawBusinessRuleTask(element) +{ + _drawTask(element); + _drawBusinessRuleTaskIcon(paper, element.x + 4, element.y + 4); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawManualTask(element) +{ + _drawTask(element); + _drawManualTaskIcon(paper, element.x + 4, element.y + 4); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawSendTask(element) +{ + _drawTask(element); + _drawSendTaskIcon(paper, element.x + 4, element.y + 4); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawReceiveTask(element) +{ + _drawTask(element); + _drawReceiveTaskIcon(paper, element.x, element.y); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawTask(element) +{ + var rectAttrs = {}; + + // Stroke + var strokeColor = _bpmnGetColor(element, ACTIVITY_STROKE_COLOR); + rectAttrs['stroke'] = strokeColor; + + var strokeWidth; + if (strokeColor === ACTIVITY_STROKE_COLOR) { + strokeWidth = TASK_STROKE; + } else { + strokeWidth = TASK_HIGHLIGHT_STROKE; + } + + var width = element.width - (strokeWidth / 2); + var height = element.height - (strokeWidth / 2); + + var rect = paper.rect(element.x, element.y, width, height, 4); + rectAttrs['stroke-width'] = strokeWidth; + + // Fill + var fillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR); + rectAttrs['fill'] = fillColor; + + // Opacity + if (customActivityBackgroundOpacity) { + rectAttrs['fill-opacity'] = customActivityBackgroundOpacity; + } + + rect.attr(rectAttrs); + rect.id = element.id; + + if (element.name) { + this._drawMultilineText(element.name, element.x, element.y, element.width, element.height, "middle", "middle", 11); + } +} + +function _drawExclusiveGateway(element) +{ + _drawGateway(element); + var quarterWidth = element.width / 4; + var quarterHeight = element.height / 4; + + var iks = paper.path( + "M" + (element.x + quarterWidth + 3) + " " + (element.y + quarterHeight + 3) + + "L" + (element.x + 3 * quarterWidth - 3) + " " + (element.y + 3 * quarterHeight - 3) + + "M" + (element.x + quarterWidth + 3) + " " + (element.y + 3 * quarterHeight - 3) + + "L" + (element.x + 3 * quarterWidth - 3) + " " + (element.y + quarterHeight + 3) + ); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + // Fill + var gatewayFillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR); + + // Opacity + var gatewayOpacity = 1.0; + if (customActivityBackgroundOpacity) { + gatewayOpacity = customActivityBackgroundOpacity; + } + + + iks.attr({"stroke-width": 3, "stroke": strokeColor, "fill": gatewayFillColor, "fill-opacity": gatewayOpacity}); + + _addHoverLogic(element, "rhombus", MAIN_STROKE_COLOR); +} + +function _drawParallelGateway(element) +{ + _drawGateway(element); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + var path1 = paper.path("M 6.75,16 L 25.75,16 M 16,6.75 L 16,25.75"); + + // Fill + var gatewayFillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR); + + // Opacity + var gatewayOpacity = 1.0; + if (customActivityBackgroundOpacity) { + gatewayOpacity = customActivityBackgroundOpacity; + } + + path1.attr({ + "stroke-width": 3, + "stroke": strokeColor, + "fill": gatewayFillColor, + "fill-opacity": gatewayOpacity + }); + + path1.transform("T" + (element.x + 4) + "," + (element.y + 4)); + + _addHoverLogic(element, "rhombus", MAIN_STROKE_COLOR); +} + +function _drawInclusiveGateway(element) +{ + _drawGateway(element); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + var circle1 = paper.circle(element.x + (element.width / 2), element.y + (element.height / 2), 9.75); + + // Fill + var gatewayFillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR); + + // Opacity + var gatewayOpacity = 1.0; + if (customActivityBackgroundOpacity) { + gatewayOpacity = customActivityBackgroundOpacity; + } + + circle1.attr({ + "stroke-width": 2.5, + "stroke": strokeColor, + "fill": gatewayFillColor, + "fill-opacity": gatewayOpacity + }); + + _addHoverLogic(element, "rhombus", MAIN_STROKE_COLOR); +} + +function _drawEventGateway(element) +{ + _drawGateway(element); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + var circle1 = paper.circle(element.x + (element.width / 2), element.y + (element.height / 2), 10.4); + + // Fill + var gatewayFillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR); + + // Opacity + var gatewayOpacity = 1.0; + if (customActivityBackgroundOpacity) { + gatewayOpacity = customActivityBackgroundOpacity; + } + + circle1.attr({ + "stroke-width": 0.5, + "stroke": strokeColor, + "fill": gatewayFillColor, + "fill-opacity": gatewayOpacity + }); + + var circle2 = paper.circle(element.x + (element.width / 2), element.y + (element.height / 2), 11.7); + circle2.attr({ + "stroke-width": 0.5, + "stroke": strokeColor, + "fill": gatewayFillColor, + "fill-opacity": gatewayOpacity + }); + + var path1 = paper.path("M 20.327514,22.344972 L 11.259248,22.344216 L 8.4577203,13.719549 L 15.794545,8.389969 L 23.130481,13.720774 L 20.327514,22.344972 z"); + path1.attr({ + "stroke-width": 1.39999998, + "stroke": strokeColor, + "fill": gatewayFillColor, + "fill-opacity": gatewayOpacity, + "stroke-linejoin": "bevel" + }); + + path1.transform("T" + (element.x + 4) + "," + (element.y + 4)); + + _addHoverLogic(element, "rhombus", MAIN_STROKE_COLOR); +} + +function _drawGateway(element) +{ + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + var rhombus = paper.path("M" + element.x + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + (element.y + element.height) + + "L" + (element.x + element.width) + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + element.y + "z" + ); + + // Fill + var gatewayFillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR); + + // Opacity + var gatewayOpacity = 1.0; + if (customActivityBackgroundOpacity) { + gatewayOpacity = customActivityBackgroundOpacity; + } + + rhombus.attr("stroke-width", 2); + rhombus.attr("stroke", strokeColor); + rhombus.attr("fill", gatewayFillColor); + rhombus.attr("fill-opacity", gatewayOpacity); + + rhombus.id = element.id; + + return rhombus; +} + +function _drawBoundaryEvent(element) +{ + var x = element.x + (element.width / 2); + var y = element.y + (element.height / 2); + + var circle = paper.circle(x, y, 15); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + if (element.cancelActivity) { + circle.attr({ + "stroke-width": 1, + "stroke": strokeColor, + "fill": "white" + }); + + } else { + circle.attr({ + "stroke-width": 1, + "stroke-dasharray": ".", + "stroke": strokeColor, + "fill": "white" + }); + } + + var innerCircle = paper.circle(x, y, 12); + + if (element.cancelActivity) { + innerCircle.attr({"stroke-width": 1, + "stroke": strokeColor, + "fill": "none" + }); + + } else { + innerCircle.attr({ + "stroke-width": 1, + "stroke-dasharray": ".", + "stroke": strokeColor, + "fill": "none" + }); + } + + _drawEventIcon(paper, element); + _addHoverLogic(element, "circle", MAIN_STROKE_COLOR); + + circle.id = element.id; + innerCircle.id = element.id + "_inner"; +} + +function _drawIntermediateCatchEvent(element) +{ + var x = element.x + (element.width / 2); + var y = element.y + (element.height / 2); + + var circle = paper.circle(x, y, 15); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + circle.attr({"stroke-width": 1, + "stroke": strokeColor, + "fill": "white" + }); + + var innerCircle = paper.circle(x, y, 12); + + innerCircle.attr({"stroke-width": 1, + "stroke": strokeColor, + "fill": "none" + }); + + _drawEventIcon(paper, element); + _addHoverLogic(element, "circle", MAIN_STROKE_COLOR); + + circle.id = element.id; + innerCircle.id = element.id + "_inner"; +} + +function _drawThrowEvent(element) +{ + var x = element.x + (element.width / 2); + var y = element.y + (element.height / 2); + + var circle = paper.circle(x, y, 15); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + circle.attr({"stroke-width": 1, + "stroke": strokeColor, + "fill": "white" + }); + + var innerCircle = paper.circle(x, y, 12); + + innerCircle.attr({"stroke-width": 1, + "stroke": strokeColor, + "fill": "none" + }); + + _drawEventIcon(paper, element); + _addHoverLogic(element, "circle", MAIN_STROKE_COLOR); + + circle.id = element.id; + innerCircle.id = element.id + "_inner"; +} + +function _drawMultilineText(text, x, y, boxWidth, boxHeight, horizontalAnchor, verticalAnchor, fontSize) +{ + if (!text || text == "") + { + return; + } + + var textBoxX, textBoxY; + var width = boxWidth - (2 * TEXT_PADDING); + + if (horizontalAnchor === "middle") + { + textBoxX = x + (boxWidth / 2); + } + else if (horizontalAnchor === "start") + { + textBoxX = x; + } + + textBoxY = y + (boxHeight / 2); + + var t = paper.text(textBoxX + TEXT_PADDING, textBoxY + TEXT_PADDING).attr({ + "text-anchor" : horizontalAnchor, + "font-family" : "Arial", + "font-size" : fontSize, + "fill" : "#373e48" + }); + + var abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + t.attr({ + "text" : abc + }); + var letterWidth = t.getBBox().width / abc.length; + + t.attr({ + "text" : text + }); + var removedLineBreaks = text.split("\n"); + var x = 0, s = []; + for (var r = 0; r < removedLineBreaks.length; r++) + { + var words = removedLineBreaks[r].split(" "); + for ( var i = 0; i < words.length; i++) { + + var l = words[i].length; + if (x + (l * letterWidth) > width) { + s.push("\n"); + x = 0; + } + x += l * letterWidth; + s.push(words[i] + " "); + } + s.push("\n"); + x = 0; + } + t.attr({ + "text" : s.join("") + }); + + if (verticalAnchor && verticalAnchor === "top") + { + t.attr({"y": y + (t.getBBox().height / 2)}); + } +} + +function _drawTextAnnotation(element) +{ + var path1 = paper.path("M20,1 L1,1 L1,50 L20,50"); + path1.attr({ + "stroke": "#585858", + "fill": "none" + }); + + var annotation = paper.set(); + annotation.push(path1); + + annotation.transform("T" + element.x + "," + element.y); + + if (element.text) { + this._drawMultilineText(element.text, element.x + 2, element.y, element.width, element.height, "start", "middle", 11); + } +} + +function _drawFlow(flow){ + + var polyline = new Polyline(flow.id, flow.waypoints, SEQUENCEFLOW_STROKE, paper); + + var strokeColor = _bpmnGetColor(flow, MAIN_STROKE_COLOR); + + polyline.element = paper.path(polyline.path); + polyline.element.attr({"stroke-width":SEQUENCEFLOW_STROKE}); + polyline.element.attr({"stroke":strokeColor}); + + polyline.element.id = flow.id; + + var lastLineIndex = polyline.getLinesCount() - 1; + var line = polyline.getLine(lastLineIndex); + + if (line == undefined) return; + + if (flow.type == "connection" && flow.conditions) + { + var middleX = (line.x1 + line.x2) / 2; + var middleY = (line.y1 + line.y2) / 2; + var image = paper.image("../editor/images/condition-flow.png", middleX - 8, middleY - 8, 16, 16); + } + + var polylineInvisible = new Polyline(flow.id, flow.waypoints, SEQUENCEFLOW_STROKE, paper); + + polylineInvisible.element = paper.path(polyline.path); + polylineInvisible.element.attr({ + "opacity": 0, + "stroke-width": 8, + "stroke" : "#000000" + }); + + if (flow.name) { + var firstLine = polyline.getLine(0); + + var angle; + if (firstLine.x1 !== firstLine.x2) { + angle = Math.atan((firstLine.y2 - firstLine.y1) / (firstLine.x2 - firstLine.x1)); + } else if (firstLine.y1 < firstLine.y2) { + angle = Math.PI / 2; + } else { + angle = -Math.PI / 2; + } + var flowName = paper.text(firstLine.x1, firstLine.y1, flow.name).attr({ + "text-anchor": "middle", + "font-family" : "Arial", + "font-size" : "12", + "fill" : "#000000" + }); + + var offsetX = (flowName.getBBox().width / 2 + 5); + var offsetY = -(flowName.getBBox().height / 2 + 5); + + if (firstLine.x1 > firstLine.x2) { + offsetX = -offsetX; + } + var rotatedOffsetX = offsetX * Math.cos(angle) - offsetY * Math.sin(angle); + var rotatedOffsetY = offsetX * Math.sin(angle) + offsetY * Math.cos(angle); + + flowName.attr({ + x: firstLine.x1 + rotatedOffsetX, + y: firstLine.y1 + rotatedOffsetY + }); + + flowName.transform("r" + ((angle) * 180) / Math.PI); + } + + _showTip(jQuery(polylineInvisible.element.node), flow); + + polylineInvisible.element.mouseover(function() { + paper.getById(polyline.element.id).attr({"stroke":"blue"}); + }); + + polylineInvisible.element.mouseout(function() { + paper.getById(polyline.element.id).attr({"stroke":"#585858"}); + }); + + _drawArrowHead(line); +} + +function _drawAssociation(flow){ + + var polyline = new Polyline(flow.id, flow.waypoints, ASSOCIATION_STROKE, paper); + + polyline.element = paper.path(polyline.path); + polyline.element.attr({"stroke-width": ASSOCIATION_STROKE}); + polyline.element.attr({"stroke-dasharray": ". "}); + polyline.element.attr({"stroke":"#585858"}); + + polyline.element.id = flow.id; + + var polylineInvisible = new Polyline(flow.id, flow.waypoints, ASSOCIATION_STROKE, paper); + + polylineInvisible.element = paper.path(polyline.path); + polylineInvisible.element.attr({ + "opacity": 0, + "stroke-width": 8, + "stroke" : "#000000" + }); + + _showTip(jQuery(polylineInvisible.element.node), flow); + + polylineInvisible.element.mouseover(function() { + paper.getById(polyline.element.id).attr({"stroke":"blue"}); + }); + + polylineInvisible.element.mouseout(function() { + paper.getById(polyline.element.id).attr({"stroke":"#585858"}); + }); +} + +function _drawArrowHead(line, connectionType) +{ + var doubleArrowWidth = 2 * ARROW_WIDTH; + + var arrowHead = paper.path("M0 0L-" + (ARROW_WIDTH / 2 + .5) + " -" + doubleArrowWidth + "L" + (ARROW_WIDTH/2 + .5) + " -" + doubleArrowWidth + "z"); + + // anti smoothing + if (this.strokeWidth%2 == 1) + line.x2 += .5, line.y2 += .5; + + arrowHead.transform("t" + line.x2 + "," + line.y2 + ""); + arrowHead.transform("...r" + Raphael.deg(line.angle - Math.PI / 2) + " " + 0 + " " + 0); + + arrowHead.attr("fill", "#585858"); + + arrowHead.attr("stroke-width", SEQUENCEFLOW_STROKE); + arrowHead.attr("stroke", "#585858"); + + return arrowHead; +} + +function _determineCustomFillColor(element, defaultColor) { + + var color; + + // By name + if (customActivityColors && customActivityColors[element.name]) { + color = customActivityColors[element.name]; + } + + if (color !== null && color !== undefined) { + return color; + } + + // By id + if (customActivityColors && customActivityColors[element.id]) { + color = customActivityColors[element.id]; + } + + if (color !== null && color !== undefined) { + return color; + } + + return defaultColor; +} diff --git a/snow-flowable/src/main/resources/static/display/bpmn-icons.js b/snow-flowable/src/main/resources/static/display/bpmn-icons.js new file mode 100644 index 0000000..d99cc2b --- /dev/null +++ b/snow-flowable/src/main/resources/static/display/bpmn-icons.js @@ -0,0 +1,342 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +function _drawUserTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("m 1,17 16,0 0,-1.7778 -5.333332,-3.5555 0,-1.7778 c 1.244444,0 1.244444,-2.3111 1.244444,-2.3111 l 0,-3.0222 C 12.555557,0.8221 9.0000001,1.0001 9.0000001,1.0001 c 0,0 -3.5555556,-0.178 -3.9111111,3.5555 l 0,3.0222 c 0,0 0,2.3111 1.2444443,2.3111 l 0,1.7778 L 1,15.2222 1,17 17,17"); + path1.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#d1b575" + }); + + var userTaskIcon = paper.set(); + userTaskIcon.push(path1); + + userTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawServiceTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("M 8,1 7.5,2.875 c 0,0 -0.02438,0.250763 -0.40625,0.4375 C 7.05724,3.330353 7.04387,3.358818 7,3.375 6.6676654,3.4929791 6.3336971,3.6092802 6.03125,3.78125 6.02349,3.78566 6.007733,3.77681 6,3.78125 5.8811373,3.761018 5.8125,3.71875 5.8125,3.71875 l -1.6875,-1 -1.40625,1.4375 0.96875,1.65625 c 0,0 0.065705,0.068637 0.09375,0.1875 0.002,0.00849 -0.00169,0.022138 0,0.03125 C 3.6092802,6.3336971 3.4929791,6.6676654 3.375,7 3.3629836,7.0338489 3.3239228,7.0596246 3.3125,7.09375 3.125763,7.4756184 2.875,7.5 2.875,7.5 L 1,8 l 0,2 1.875,0.5 c 0,0 0.250763,0.02438 0.4375,0.40625 0.017853,0.03651 0.046318,0.04988 0.0625,0.09375 0.1129372,0.318132 0.2124732,0.646641 0.375,0.9375 -0.00302,0.215512 -0.09375,0.34375 -0.09375,0.34375 L 2.6875,13.9375 4.09375,15.34375 5.78125,14.375 c 0,0 0.1229911,-0.09744 0.34375,-0.09375 0.2720511,0.147787 0.5795915,0.23888 0.875,0.34375 0.033849,0.01202 0.059625,0.05108 0.09375,0.0625 C 7.4756199,14.874237 7.5,15.125 7.5,15.125 L 8,17 l 2,0 0.5,-1.875 c 0,0 0.02438,-0.250763 0.40625,-0.4375 0.03651,-0.01785 0.04988,-0.04632 0.09375,-0.0625 0.332335,-0.117979 0.666303,-0.23428 0.96875,-0.40625 0.177303,0.0173 0.28125,0.09375 0.28125,0.09375 l 1.65625,0.96875 1.40625,-1.40625 -0.96875,-1.65625 c 0,0 -0.07645,-0.103947 -0.09375,-0.28125 0.162527,-0.290859 0.262063,-0.619368 0.375,-0.9375 0.01618,-0.04387 0.04465,-0.05724 0.0625,-0.09375 C 14.874237,10.52438 15.125,10.5 15.125,10.5 L 17,10 17,8 15.125,7.5 c 0,0 -0.250763,-0.024382 -0.4375,-0.40625 C 14.669647,7.0572406 14.641181,7.0438697 14.625,7 14.55912,6.8144282 14.520616,6.6141566 14.4375,6.4375 c -0.224363,-0.4866 0,-0.71875 0,-0.71875 L 15.40625,4.0625 14,2.625 l -1.65625,1 c 0,0 -0.253337,0.1695664 -0.71875,-0.03125 l -0.03125,0 C 11.405359,3.5035185 11.198648,3.4455201 11,3.375 10.95613,3.3588185 10.942759,3.3303534 10.90625,3.3125 10.524382,3.125763 10.5,2.875 10.5,2.875 L 10,1 8,1 z m 1,5 c 1.656854,0 3,1.3431458 3,3 0,1.656854 -1.343146,3 -3,3 C 7.3431458,12 6,10.656854 6,9 6,7.3431458 7.3431458,6 9,6 z"); + path1.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#72a7d0" + }); + + var serviceTaskIcon = paper.set(); + serviceTaskIcon.push(path1); + + serviceTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawScriptTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("m 5,2 0,0.094 c 0.23706,0.064 0.53189,0.1645 0.8125,0.375 0.5582,0.4186 1.05109,1.228 1.15625,2.5312 l 8.03125,0 1,0 1,0 c 0,-3 -2,-3 -2,-3 l -10,0 z M 4,3 4,13 2,13 c 0,3 2,3 2,3 l 9,0 c 0,0 2,0 2,-3 L 15,6 6,6 6,5.5 C 6,4.1111 5.5595,3.529 5.1875,3.25 4.8155,2.971 4.5,3 4.5,3 L 4,3 z"); + path1.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#72a7d0" + }); + + var scriptTaskIcon = paper.set(); + scriptTaskIcon.push(path1); + + scriptTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawBusinessRuleTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("m 1,2 0,14 16,0 0,-14 z m 1.45458,5.6000386 2.90906,0 0,2.7999224 -2.90906,0 z m 4.36364,0 8.72718,0 0,2.7999224 -8.72718,0 z m -4.36364,4.1998844 2.90906,0 0,2.800116 -2.90906,0 z m 4.36364,0 8.72718,0 0,2.800116 -8.72718,0 z"); + path1.attr({ + "stroke": "none", + "fill": "#72a7d0" + }); + + var businessRuleTaskIcon = paper.set(); + businessRuleTaskIcon.push(path1); + + businessRuleTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawSendTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("M 1 3 L 9 11 L 17 3 L 1 3 z M 1 5 L 1 13 L 5 9 L 1 5 z M 17 5 L 13 9 L 17 13 L 17 5 z M 6 10 L 1 15 L 17 15 L 12 10 L 9 13 L 6 10 z"); + path1.attr({ + "stroke": "none", + "fill": "#16964d" + }); + + var sendTaskIcon = paper.set(); + sendTaskIcon.push(path1); + + sendTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawManualTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("m 17,9.3290326 c -0.0069,0.5512461 -0.455166,1.0455894 -0.940778,1.0376604 l -5.792746,0 c 0.0053,0.119381 0.0026,0.237107 0.0061,0.355965 l 5.154918,0 c 0.482032,-0.0096 0.925529,0.49051 0.919525,1.037574 -0.0078,0.537128 -0.446283,1.017531 -0.919521,1.007683 l -5.245273,0 c -0.01507,0.104484 -0.03389,0.204081 -0.05316,0.301591 l 2.630175,0 c 0.454137,-0.0096 0.872112,0.461754 0.866386,0.977186 C 13.619526,14.554106 13.206293,15.009498 12.75924,15 L 3.7753054,15 C 3.6045812,15 3.433552,14.94423 3.2916363,14.837136 c -0.00174,0 -0.00436,0 -0.00609,0 C 1.7212035,14.367801 0.99998255,11.458641 1,11.458641 L 1,7.4588393 c 0,0 0.6623144,-1.316333 1.8390583,-2.0872584 1.1767614,-0.7711868 6.8053358,-2.40497 7.2587847,-2.8052901 0.453484,-0.40032 1.660213,1.4859942 0.04775,2.4010487 C 8.5332315,5.882394 8.507351,5.7996113 8.4370292,5.7936859 l 6.3569748,-0.00871 c 0.497046,-0.00958 0.952273,0.5097676 0.94612,1.0738232 -0.0053,0.556126 -0.456176,1.0566566 -0.94612,1.0496854 l -4.72435,0 c 0.01307,0.1149374 0.0244,0.2281319 0.03721,0.3498661 l 5.952195,0 c 0.494517,-0.00871 0.947906,0.5066305 0.940795,1.0679848 z"); + path1.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#d1b575" + }); + + var manualTaskIcon = paper.set(); + manualTaskIcon.push(path1); + + manualTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawReceiveTaskIcon(paper, startX, startY) +{ + var path = paper.path("m 0.5,2.5 0,13 17,0 0,-13 z M 2,4 6.5,8.5 2,13 z M 4,4 14,4 9,9 z m 12,0 0,9 -4.5,-4.5 z M 7.5,9.5 9,11 10.5,9.5 15,14 3,14 z"); + path.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#16964d" + }); + + startX += 4; + startY += 2; + + path.transform("T" + startX + "," + startY); + +} + +function _drawCamelTaskIcon(paper, startX, startY) +{ + var path = paper.path("m 8.1878027,15.383782 c -0.824818,-0.3427 0.375093,-1.1925 0.404055,-1.7743 0.230509,-0.8159 -0.217173,-1.5329 -0.550642,-2.2283 -0.106244,-0.5273 -0.03299,-1.8886005 -0.747194,-1.7818005 -0.712355,0.3776 -0.9225,1.2309005 -1.253911,1.9055005 -0.175574,1.0874 -0.630353,2.114 -0.775834,3.2123 -0.244009,0.4224 -1.741203,0.3888 -1.554386,-0.1397 0.651324,-0.3302 1.13227,-0.9222 1.180246,-1.6705 0.0082,-0.7042 -0.133578,-1.3681 0.302178,-2.0083 0.08617,-0.3202 0.356348,-1.0224005 -0.218996,-0.8051 -0.694517,0.2372 -1.651062,0.6128 -2.057645,-0.2959005 -0.696769,0.3057005 -1.102947,-0.611 -1.393127,-1.0565 -0.231079,-0.6218 -0.437041,-1.3041 -0.202103,-1.9476 -0.185217,-0.7514 -0.39751099,-1.5209 -0.35214999,-2.301 -0.243425,-0.7796 0.86000899,-1.2456 0.08581,-1.8855 -0.76078999,0.1964 -1.41630099,-0.7569 -0.79351899,-1.2877 0.58743,-0.52829998 1.49031699,-0.242 2.09856399,-0.77049998 0.816875,-0.3212 1.256619,0.65019998 1.923119,0.71939998 0.01194,0.7333 -0.0031,1.5042 -0.18417,2.2232 -0.194069,0.564 -0.811196,1.6968 0.06669,1.9398 0.738382,-0.173 1.095723,-0.9364 1.659041,-1.3729 0.727298,-0.3962 1.093982,-1.117 1.344137,-1.8675 0.400558,-0.8287 1.697676,-0.6854 1.955367,0.1758 0.103564,0.5511 0.9073983,1.7538 1.2472763,0.6846 0.121868,-0.6687 0.785541,-1.4454 1.518183,-1.0431 0.813587,0.4875 0.658233,1.6033 1.285504,2.2454 0.768715,0.8117 1.745394,1.4801 2.196633,2.5469 0.313781,0.8074 0.568552,1.707 0.496624,2.5733 -0.35485,0.8576005 -1.224508,-0.216 -0.64725,-0.7284 0.01868,-0.3794 -0.01834,-1.3264 -0.370249,-1.3272 -0.123187,0.7586 -0.152778,1.547 -0.10869,2.3154 0.270285,0.6662005 1.310741,0.7653005 1.060553,1.6763005 -0.03493,0.9801 0.294343,1.9505 0.148048,2.9272 -0.320479,0.2406 -0.79575,0.097 -1.185062,0.1512 -0.165725,0.3657 -0.40138,0.921 -1.020848,0.6744 -0.564671,0.1141 -1.246404,-0.266 -0.578559,-0.7715 0.679736,-0.5602 0.898618,-1.5362 0.687058,-2.3673 -0.529674,-1.108 -1.275984,-2.0954005 -1.839206,-3.1831005 -0.634619,-0.1004 -1.251945,0.6779 -1.956789,0.7408 -0.6065893,-0.038 -1.0354363,-0.06 -0.8495673,0.6969005 0.01681,0.711 0.152396,1.3997 0.157345,2.1104 0.07947,0.7464 0.171287,1.4944 0.238271,2.2351 0.237411,1.0076 -0.687542,1.1488 -1.414811,0.8598 z m 6.8675483,-1.8379 c 0.114364,-0.3658 0.206751,-1.2704 -0.114466,-1.3553 -0.152626,0.5835 -0.225018,1.1888 -0.227537,1.7919 0.147087,-0.1166 0.265559,-0.2643 0.342003,-0.4366 z"); + path.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#bd4848" + }); + + startX += 4; + startY += 2; + + path.transform("T" + startX + "," + startY); + +} + +function _drawMuleTaskIcon(paper, startX, startY) +{ + var path = paper.path("M 8,0 C 3.581722,0 0,3.5817 0,8 c 0,4.4183 3.581722,8 8,8 4.418278,0 8,-3.5817 8,-8 L 16,7.6562 C 15.813571,3.3775 12.282847,0 8,0 z M 5.1875,2.7812 8,7.3437 10.8125,2.7812 c 1.323522,0.4299 2.329453,1.5645 2.8125,2.8438 1.136151,2.8609 -0.380702,6.4569 -3.25,7.5937 -0.217837,-0.6102 -0.438416,-1.2022 -0.65625,-1.8125 0.701032,-0.2274 1.313373,-0.6949 1.71875,-1.3125 0.73624,-1.2317 0.939877,-2.6305 -0.03125,-4.3125 l -2.75,4.0625 -0.65625,0 -0.65625,0 -2.75,-4 C 3.5268433,7.6916 3.82626,8.862 4.5625,10.0937 4.967877,10.7113 5.580218,11.1788 6.28125,11.4062 6.063416,12.0165 5.842837,12.6085 5.625,13.2187 2.755702,12.0819 1.238849,8.4858 2.375,5.625 2.858047,4.3457 3.863978,3.2112 5.1875,2.7812 z"); + path.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#bd4848" + }); + + startX += 4; + startY += 2; + + path.transform("T" + startX + "," + startY); + +} + +function _drawAlfrescoPublishTaskIcon(paper, startX, startY) +{ + + startX += 2; + startY += 2; + + var path = paper.path("M4.11870968,2.12890323 L6.12954839,0.117935484 L3.10993548,0.118064516 L3.10270968,0.118064516 C1.42941935,0.118064516 0.0729032258,1.47458065 0.0729032258,3.14774194 C0.0729032258,4.82116129 1.42929032,6.17754839 3.10258065,6.17754839 C3.22967742,6.17754839 3.35470968,6.16877419 3.47767742,6.15354839 C2.8163871,4.85083871 3.02954839,3.21793548 4.11870968,2.12890323M6.57032258,3.144 L6.57032258,0.300258065 L4.43522581,2.4356129 L4.43006452,2.44064516 C3.24683871,3.62387097 3.24683871,5.54219355 4.43006452,6.72541935 C5.61329032,7.90864516 7.5316129,7.90864516 8.71483871,6.72541935 C8.80464516,6.6356129 8.88529032,6.54025806 8.96154839,6.44270968 C7.57341935,5.98864516 6.57045161,4.68387097 6.57032258,3.144"); + path.attr({"fill": "#87C040"}); + + var startX1 = startX + 1.419355; + var startY1 = startY + 8.387097; + path.transform("T" + startX1 + "," + startY1); + + path = paper.path("M10.4411613,10.5153548 L8.43032258,8.50451613 L8.43032258,11.5313548 C8.43032258,13.2047742 9.78683871,14.5611613 11.460129,14.5611613 C13.1334194,14.5611613 14.4899355,13.2047742 14.4899355,11.5314839 C14.4899355,11.4043871 14.4811613,11.2793548 14.4659355,11.1563871 C13.1632258,11.8178065 11.5303226,11.6045161 10.4411613,10.5153548M15.0376774,5.91935484 C14.947871,5.82954839 14.8526452,5.74890323 14.7550968,5.67264516 C14.3010323,7.06064516 12.996129,8.06374194 11.4563871,8.06374194 L8.61277419,8.06374194 L10.7529032,10.204 C11.936129,11.3872258 13.8545806,11.3872258 15.0376774,10.204 C16.2209032,9.02077419 16.2209032,7.10245161 15.0376774,5.91935484"); + path.attr({"fill": "#87C040"}); + path.transform("T" + startX + "," + startY); + + path = paper.path("M5.9083871,1.5636129 C5.78129032,1.5636129 5.65625806,1.57225806 5.53329032,1.58748387 C6.19458065,2.89032258 5.98141935,4.52309677 4.89225806,5.61225806 L2.88154839,7.62309677 L5.9083871,7.62309677 C7.58154839,7.62309677 8.93806452,6.26658065 8.93806452,4.59329032 C8.93819355,2.92 7.58167742,1.5636129 5.9083871,1.5636129"); + path.attr({"fill": "#ED9A2D"}); + var startX2 = startX + 5.548387; + path.transform("T" + startX2 + "," + startY); + path = paper.path("M4.58090323,1.0156129 C3.39767742,-0.167483871 1.47935484,-0.167483871 0.296129032,1.01574194 C0.206451613,1.10554839 0.125806452,1.20077419 0.0495483871,1.29845161 C1.43754839,1.75251613 2.44064516,3.05729032 2.44064516,4.59703226 L2.44064516,7.44077419 L4.57574194,5.30554839 L4.58090323,5.30051613 C5.76412903,4.11729032 5.76412903,2.19896774 4.58090323,1.0156129"); + path.attr({"fill": "#5698C6"}); + path.transform("T" + startX2 + "," + startY); + + path = paper.path("M5.54051613,5.61432258 L5.62670968,5.70425806 L7.54632258,7.62387097 L7.5483871,7.62387097 L7.5483871,4.604 L7.5483871,4.59677419 C7.5483871,2.92348387 6.19187097,1.56696774 4.51858065,1.56696774 C2.84529032,1.56696774 1.48877419,2.92335484 1.48890323,4.59664516 C1.48890323,4.72348387 1.49754839,4.84812903 1.51264516,4.97083871 C2.81625806,4.30993548 4.45122581,4.52503226 5.54051613,5.61432258M1.23251613,10.4292903 C1.25625806,10.3588387 1.28180645,10.2894194 1.30980645,10.2210323 C1.31329032,10.2123871 1.3163871,10.2036129 1.32,10.1952258 C1.35070968,10.1216774 1.38451613,10.0500645 1.42,9.97935484 C1.42774194,9.96374194 1.43574194,9.9483871 1.44387097,9.93277419 C1.4803871,9.86258065 1.51883871,9.79354839 1.55987097,9.72632258 C1.56425806,9.71909677 1.56903226,9.71225806 1.57341935,9.70529032 C1.6123871,9.64245161 1.65354839,9.58141935 1.6963871,9.52141935 C1.70516129,9.50903226 1.71380645,9.49651613 1.72283871,9.48425806 C1.76890323,9.42154839 1.81690323,9.36064516 1.86683871,9.30129032 C1.87703226,9.28916129 1.88735484,9.27741935 1.89780645,9.26567742 C1.94658065,9.20916129 1.99690323,9.15406452 2.04916129,9.10090323 C2.05380645,9.09625806 2.05806452,9.09135484 2.06270968,9.08670968 C2.11832258,9.03083871 2.17625806,8.97741935 2.23548387,8.92554839 C2.2483871,8.91419355 2.26129032,8.90296774 2.27432258,8.89187097 C2.33393548,8.84103226 2.39496774,8.79212903 2.45780645,8.74529032 C2.46606452,8.73922581 2.47470968,8.73354839 2.48296774,8.7276129 C2.54167742,8.68490323 2.60180645,8.64412903 2.66322581,8.60503226 C2.67535484,8.59729032 2.68735484,8.58929032 2.6996129,8.58167742 C2.76593548,8.54064516 2.83380645,8.50206452 2.90296774,8.46541935 C2.91754839,8.45780645 2.93225806,8.45045161 2.94696774,8.44296774 C3.016,8.40774194 3.08593548,8.37406452 3.15741935,8.34348387 C3.16090323,8.34206452 3.16425806,8.3403871 3.16774194,8.33883871 C3.24167742,8.30748387 3.31729032,8.27948387 3.39380645,8.25316129 C3.41032258,8.24748387 3.42670968,8.24180645 3.44335484,8.2363871 C3.51909677,8.21174194 3.59587097,8.18903226 3.67380645,8.16929032 C3.68567742,8.16645161 3.69793548,8.16387097 3.70980645,8.16116129 C3.78206452,8.14374194 3.85509677,8.12877419 3.92890323,8.116 C3.94270968,8.11367742 3.9563871,8.11083871 3.97019355,8.10877419 C4.05032258,8.09587097 4.13148387,8.08619355 4.21329032,8.07896774 C4.23096774,8.07741935 4.24877419,8.07625806 4.26645161,8.07483871 C4.35109677,8.06877419 4.43612903,8.06451613 4.52232258,8.06451613 L7.36606452,8.0643871 L5.22580645,5.92412903 C4.04258065,4.74103226 2.12412903,4.74090323 0.941032258,5.92412903 C-0.242193548,7.10735484 -0.242193548,9.02567742 0.941032258,10.2089032 C1.03070968,10.2985806 1.12464516,10.3814194 1.22206452,10.4575484 C1.22529032,10.448 1.22929032,10.4388387 1.23251613,10.4292903"); + path.attr({"fill": "#5698C6"}); + path.transform("T" + startX + "," + startY); + + path = paper.path("M5.23290323,5.92412903 L6.92748387,7.61870968 L4.64980645,7.61870968 L4.52064516,7.62141935 C3.13354839,7.62141935 1.96425806,6.68929032 1.60477419,5.41729032 C2.75870968,4.77019355 4.24619355,4.93754839 5.22787097,5.91909677 L5.23290323,5.92412903M7.54722581,4.59612903 L7.54722581,6.99264516 L5.93664516,5.38206452 L5.84348387,5.29264516 C4.86258065,4.31187097 4.69483871,2.82580645 5.34012903,1.67225806 C6.61367742,2.03070968 7.54722581,3.20090323 7.54722581,4.58890323 L7.54722581,4.59612903M10.1385806,5.29819355 L8.444,6.99290323 L8.444,4.71522581 L8.44129032,4.58606452 C8.44129032,3.19896774 9.37341935,2.02954839 10.6454194,1.67019355 C11.2925161,2.82412903 11.1251613,4.3116129 10.1436129,5.29316129 L10.1385806,5.29819355"); + path.attr({"fill": "#446BA5"}); + path.transform("T" + startX + "," + startY); + + path = paper.path("M11.4548387,7.61677419 L9.05832258,7.61677419 L10.6689032,6.00619355 L10.7583226,5.91303226 C11.7390968,4.93212903 13.2251613,4.7643871 14.3787097,5.40967742 C14.0202581,6.68322581 12.8500645,7.61677419 11.4620645,7.61677419 L11.4548387,7.61677419"); + path.attr({"fill": "#FFF101"}); + path.transform("T" + startX + "," + startY); + + path = paper.path("M10.7470968,10.192 L9.05251613,8.49741935 L11.3301935,8.49741935 L11.4593548,8.49470968 C12.8464516,8.49483871 14.0157419,9.42696774 14.3752258,10.6989677 C13.2211613,11.3459355 11.7338065,11.1787097 10.752129,10.1970323 L10.7470968,10.192M8.43729032,11.5174194 L8.43729032,9.12090323 L10.047871,10.7314839 L10.1411613,10.8209032 C11.1219355,11.8018065 11.2896774,13.2876129 10.6443871,14.4412903 C9.37083871,14.0828387 8.43729032,12.9127742 8.43729032,11.5245161 L8.43729032,11.5174194M5.86193548,10.8296774 L7.55651613,9.13496774 L7.55651613,11.4126452 L7.55922581,11.5418065 C7.55922581,12.9289032 6.62709677,14.0983226 5.35509677,14.4578065 C4.708,13.3036129 4.87535484,11.8162581 5.85690323,10.8347097 L5.86193548,10.8296774M4.53251613,8.50993548 L6.92903226,8.50993548 L5.31845161,10.1205161 L5.22903226,10.2136774 C4.24812903,11.1945806 2.76219355,11.3623226 1.60851613,10.7170323 C1.96709677,9.44335484 3.13716129,8.50993548 4.52529032,8.50993548 L4.53251613,8.50993548"); + path.attr({"fill": "#45AB47"}); + path.transform("T" + startX + "," + startY); +} + +function _drawHttpTaskIcon(paper, startX, startY) +{ + var path = paper.path("m 16.704699,5.9229055 q 0.358098,0 0.608767,0.2506681 0.250669,0.250668 0.250669,0.6087677 0,0.3580997 -0.250669,0.6087677 -0.250669,0.2506679 -0.608767,0.2506679 -0.358098,0 -0.608767,-0.2506679 -0.250669,-0.250668 -0.250669,-0.6087677 0,-0.3580997 0.250669,-0.6087677 0.250669,-0.2506681 0.608767,-0.2506681 z m 2.578308,-2.0053502 q -2.229162,0 -3.854034,0.6759125 -1.624871,0.6759067 -3.227361,2.2694472 -0.716197,0.725146 -1.575633,1.7457293 L 7.2329969,8.7876913 Q 7.0897576,8.8055849 7.000233,8.9309334 L 4.9948821,12.368677 q -0.035811,0.06267 -0.035811,0.143242 0,0.107426 0.080572,0.205905 l 0.5729577,0.572957 q 0.125334,0.116384 0.2864786,0.07162 l 2.4708789,-0.760963 2.5156417,2.515645 -0.76096,2.470876 q -0.009,0.02687 -0.009,0.08057 0,0.125338 0.08058,0.205905 l 0.572957,0.572958 q 0.170096,0.152194 0.349146,0.04476 l 3.437744,-2.005351 q 0.125335,-0.08953 0.143239,-0.232763 l 0.17905,-3.392986 q 1.02058,-0.859435 1.745729,-1.575629 1.67411,-1.6830612 2.309735,-3.2049805 0.635625,-1.5219191 0.635625,-3.8585111 0,-0.1253369 -0.08505,-0.2148575 -0.08505,-0.089526 -0.201431,-0.089526 z"); + path.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#16964d" + }); + + startX += -2; + startY += -2; + + path.transform("T" + startX + "," + startY); + +} + +function _drawShellTaskIcon(paper, startX, startY) { + var path = paper.path("m 1,2 0,14 16,0 0,-14 z m 1.4,3 12.7,0 0,10 -12.7,0 z"); + path.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#16964d" + }); + var text = paper.text(3, 9, ">_").attr({ + "font-size": "5px", + "fill": "#16964d" + }); + + startY += -2; + text.transform("T" + startX + "," + startY); + startX += -2; + path.transform("T" + startX + "," + startY); +} + +function _drawDecisionTaskIcon(paper, startX, startY) { + var path1 = paper.path("m 1,2 0,14 16,0 0,-14 z m 1.9,2.4000386 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m -8.67364,3.9 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m -8.67364,3.9 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z"); + path1.attr({ + "opacity": 1, + "stroke": "#000000", + "fill": "#F4F6F7" + }); + + var decisionTaskIcon = paper.set(); + decisionTaskIcon.push(path1); + + decisionTaskIcon.translate(startX, startY); + decisionTaskIcon.scale(0.7, 0.7); +} + +function _drawEventIcon(paper, element) +{ + if (element.eventDefinition && element.eventDefinition.type) + { + if ("timer" === element.eventDefinition.type) + { + _drawTimerIcon(paper, element); + } + else if ("error" === element.eventDefinition.type) + { + _drawErrorIcon(paper, element); + } + else if ("signal" === element.eventDefinition.type) + { + _drawSignalIcon(paper, element); + } + else if ("message" === element.eventDefinition.type) + { + _drawMessageIcon(paper, element); + } + } +} + +function _drawTimerIcon(paper, element) +{ + var x = element.x + (element.width / 2); + var y = element.y + (element.height / 2); + + var circle = paper.circle(x, y, 10); + + circle.attr({"stroke-width": 1, + "stroke": "black", + "fill": "none" + }); + + var path = paper.path("M 10 0 C 4.4771525 0 0 4.4771525 0 10 C 0 15.522847 4.4771525 20 10 20 C 15.522847 20 20 15.522847 20 10 C 20 4.4771525 15.522847 1.1842379e-15 10 0 z M 9.09375 1.03125 C 9.2292164 1.0174926 9.362825 1.0389311 9.5 1.03125 L 9.5 3.5 L 10.5 3.5 L 10.5 1.03125 C 15.063526 1.2867831 18.713217 4.9364738 18.96875 9.5 L 16.5 9.5 L 16.5 10.5 L 18.96875 10.5 C 18.713217 15.063526 15.063526 18.713217 10.5 18.96875 L 10.5 16.5 L 9.5 16.5 L 9.5 18.96875 C 4.9364738 18.713217 1.2867831 15.063526 1.03125 10.5 L 3.5 10.5 L 3.5 9.5 L 1.03125 9.5 C 1.279102 5.0736488 4.7225326 1.4751713 9.09375 1.03125 z M 9.5 5 L 9.5 8.0625 C 8.6373007 8.2844627 8 9.0680195 8 10 C 8 11.104569 8.8954305 12 10 12 C 10.931981 12 11.715537 11.362699 11.9375 10.5 L 14 10.5 L 14 9.5 L 11.9375 9.5 C 11.756642 8.7970599 11.20294 8.2433585 10.5 8.0625 L 10.5 5 L 9.5 5 z"); + path.attr({ + "stroke": "none", + "fill": "#585858" + }); + path.transform("T" + (element.x + 5) + "," + (element.y + 5)); + return path; +} + +function _drawErrorIcon(paper, element) +{ + var path = paper.path("M 22.820839,11.171502 L 19.36734,24.58992 L 13.54138,14.281819 L 9.3386512,20.071607 L 13.048949,6.8323057 L 18.996148,16.132659 L 22.820839,11.171502 z"); + + var fill = "none"; + var x = element.x - 1; + var y = element.y - 1; + if (element.type === "EndEvent") + { + fill = "black"; + x -= 1; + y -= 1; + } + + path.attr({ + "stroke": "black", + "stroke-width": 1, + "fill": fill + }); + + path.transform("T" + x + "," + y); + return path; +} + +function _drawSignalIcon(paper, element) +{ + var fill = "none"; + if (element.type === "ThrowEvent") + { + fill = "black"; + } + + var path = paper.path("M 8.7124971,21.247342 L 23.333334,21.247342 L 16.022915,8.5759512 L 8.7124971,21.247342 z"); + path.attr({ + "stroke": "black", + "stroke-width": 1, + "fill": fill + }); + path.transform("T" + (element.x - 1) + "," + (element.y - 1)); + return path; +} + +function _drawMessageIcon(paper, element) +{ + var fill = "none"; + if (element.type === "ThrowEvent") + { + fill = "black"; + } + + var path = paper.path("M 1 3 L 9 11 L 17 3 L 1 3 z M 1 5 L 1 13 L 5 9 L 1 5 z M 17 5 L 13 9 L 17 13 L 17 5 z M 6 10 L 1 15 L 17 15 L 12 10 L 9 13 L 6 10 z"); + path.attr({ + "stroke": "black", + "stroke-width": 1, + "fill": fill + }); + path.transform("T" + (element.x + 6) + "," + (element.y + 6)); + return path; +} diff --git a/snow-flowable/src/main/resources/static/display/displaymodel.css b/snow-flowable/src/main/resources/static/display/displaymodel.css new file mode 100644 index 0000000..272b258 --- /dev/null +++ b/snow-flowable/src/main/resources/static/display/displaymodel.css @@ -0,0 +1,24 @@ +div[class*='ui-tooltip-kisbpm-'] { + background-color: #ffffff; + border-color: #c5c5c5; + color: #4a4a4a; + font-family: Verdana; + font-size: 12px; +} + +div[class*='ui-tooltip-kisbpm-'] .qtip-content { + color: #4a4a4a; + background-color: #ffffff; + font-family: Verdana; + font-size: 12px; +} + +.ui-tooltip-kisbpm-bpmn .qtip-titlebar { + color: #FFFFFF; + font-size: 12px; + background: #2B414F; +} + +.ui-tooltip-kisbpm-bpmn .qtip-tip { + background-color: #2B414F; +} diff --git a/snow-flowable/src/main/resources/static/display/displaymodel.html b/snow-flowable/src/main/resources/static/display/displaymodel.html new file mode 100644 index 0000000..a6d5a9e --- /dev/null +++ b/snow-flowable/src/main/resources/static/display/displaymodel.html @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/display/displaymodel.js b/snow-flowable/src/main/resources/static/display/displaymodel.js new file mode 100644 index 0000000..9b81a69 --- /dev/null +++ b/snow-flowable/src/main/resources/static/display/displaymodel.js @@ -0,0 +1,317 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +var NORMAL_STROKE = 1; +var SEQUENCEFLOW_STROKE = 1.5; +var ASSOCIATION_STROKE = 2; +var TASK_STROKE = 1; +var TASK_HIGHLIGHT_STROKE = 2; +var CALL_ACTIVITY_STROKE = 2; +var ENDEVENT_STROKE = 3; + +var COMPLETED_COLOR= "#2632aa"; +var TEXT_COLOR= "#373e48"; +var CURRENT_COLOR= "#017501"; +var HOVER_COLOR= "#666666"; +var ACTIVITY_STROKE_COLOR = "#bbbbbb"; +var ACTIVITY_FILL_COLOR = "#f9f9f9"; +var MAIN_STROKE_COLOR = "#585858"; + +var TEXT_PADDING = 3; +var ARROW_WIDTH = 4; +var MARKER_WIDTH = 12; + +var TASK_FONT = {font: "11px Arial", opacity: 1, fill: Raphael.rgb(0, 0, 0)}; + +// icons +var ICON_SIZE = 16; +var ICON_PADDING = 4; + +var INITIAL_CANVAS_WIDTH; +var INITIAL_CANVAS_HEIGHT; + +var paper; +var viewBox; +var viewBoxWidth; +var viewBoxHeight; + +var canvasWidth; +var canvasHeight; + +var modelDiv = jQuery('#bpmnModel'); +var modelId = modelDiv.attr('data-model-id'); +var historyModelId = modelDiv.attr('data-history-id'); +var processDefinitionId = modelDiv.attr('data-process-definition-id'); +var modelType = modelDiv.attr('data-model-type'); + +// Support for custom background colors for activities +var customActivityColors = modelDiv.attr('data-activity-color-mapping'); +if (customActivityColors !== null && customActivityColors !== undefined && customActivityColors.length > 0) { + // Stored on the attribute as a string + customActivityColors = JSON.parse(customActivityColors); +} + +var customActivityToolTips = modelDiv.attr('data-activity-tooltips'); +if (customActivityToolTips !== null && customActivityToolTips !== undefined && customActivityToolTips.length > 0) { + // Stored on the attribute as a string + customActivityToolTips = JSON.parse(customActivityToolTips); +} + +// Support for custom opacity for activity backgrounds +var customActivityBackgroundOpacity = modelDiv.attr('data-activity-opacity'); + +var elementsAdded = new Array(); +var elementsRemoved = new Array(); + +function _showTip(htmlNode, element) +{ + + // Custom tooltip + var documentation = undefined; + if (customActivityToolTips) { + if (customActivityToolTips[element.name]) { + documentation = customActivityToolTips[element.name]; + } else if (customActivityToolTips[element.id]) { + documentation = customActivityToolTips[element.id]; + } else { + documentation = ''; // Show nothing if custom tool tips are enabled + } + } + + // Default tooltip, no custom tool tip set + if (documentation === undefined) { + var documentation = ""; + if (element.name && element.name.length > 0) { + documentation += "Name: " + element.name + "

"; + } + + if (element.properties) { + for (var i = 0; i < element.properties.length; i++) { + var propName = element.properties[i].name; + if (element.properties[i].type && element.properties[i].type === 'list') { + documentation += '' + propName + ':
'; + for (var j = 0; j < element.properties[i].value.length; j++) { + documentation += '' + element.properties[i].value[j] + '
'; + } + } + else { + documentation += '' + propName + ': ' + element.properties[i].value + '
'; + } + } + } + } + + var text = element.type + " "; + if (element.name && element.name.length > 0) + { + text += element.name; + } + else + { + text += element.id; + } + + htmlNode.qtip({ + content: { + text: documentation, + title: { + text: text + } + }, + position: { + my: 'top left', + at: 'bottom center', + viewport: jQuery('#bpmnModel') + }, + hide: { + fixed: true, delay: 500, + event: 'click mouseleave' + }, + style: { + classes: 'ui-tooltip-kisbpm-bpmn' + } + }); +} + +function _addHoverLogic(element, type, defaultColor) +{ + var strokeColor = _bpmnGetColor(element, defaultColor); + var topBodyRect = null; + if (type === "rect") + { + topBodyRect = paper.rect(element.x, element.y, element.width, element.height); + } + else if (type === "circle") + { + var x = element.x + (element.width / 2); + var y = element.y + (element.height / 2); + topBodyRect = paper.circle(x, y, 15); + } + else if (type === "rhombus") + { + topBodyRect = paper.path("M" + element.x + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + (element.y + element.height) + + "L" + (element.x + element.width) + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + element.y + "z" + ); + } + + var opacity = 0; + var fillColor = "#ffffff"; + if (jQuery.inArray(element.id, elementsAdded) >= 0) + { + opacity = 0.2; + fillColor = "green"; + } + + if (jQuery.inArray(element.id, elementsRemoved) >= 0) + { + opacity = 0.2; + fillColor = "red"; + } + + topBodyRect.attr({ + "opacity": opacity, + "stroke" : "none", + "fill" : fillColor + }); + _showTip(jQuery(topBodyRect.node), element); + + topBodyRect.mouseover(function() { + paper.getById(element.id).attr({"stroke":HOVER_COLOR}); + }); + + topBodyRect.mouseout(function() { + paper.getById(element.id).attr({"stroke":strokeColor}); + }); +} + +function _zoom(zoomIn) +{ + var tmpCanvasWidth, tmpCanvasHeight; + if (zoomIn) + { + tmpCanvasWidth = canvasWidth * (1.0/0.90); + tmpCanvasHeight = canvasHeight * (1.0/0.90); + } + else + { + tmpCanvasWidth = canvasWidth * (1.0/1.10); + tmpCanvasHeight = canvasHeight * (1.0/1.10); + } + + if (tmpCanvasWidth != canvasWidth || tmpCanvasHeight != canvasHeight) + { + canvasWidth = tmpCanvasWidth; + canvasHeight = tmpCanvasHeight; + paper.setSize(canvasWidth, canvasHeight); + } +} + +var modelUrl; + +if (modelType == 'runtime') { + if (historyModelId) { + modelUrl = FLOWABLE.APP_URL.getProcessInstanceModelJsonHistoryUrl(historyModelId); + } else { + modelUrl = FLOWABLE.APP_URL.getProcessInstanceModelJsonUrl(modelId); + } +} else if (modelType == 'design') { + if (historyModelId) { + modelUrl = FLOWABLE.APP_URL.getModelHistoryModelJsonUrl(modelId, historyModelId); + } else { + modelUrl = FLOWABLE.APP_URL.getModelModelJsonUrl(modelId); + } +} else if (modelType == 'process-definition') { + modelUrl = FLOWABLE.APP_URL.getProcessDefinitionModelJsonUrl(processDefinitionId); +} + +var request = jQuery.ajax({ + type: 'get', + url: modelUrl + '?nocaching=' + new Date().getTime() +}); + +request.success(function(data, textStatus, jqXHR) { + + if ((!data.elements || data.elements.length == 0) && (!data.pools || data.pools.length == 0)) return; + + INITIAL_CANVAS_WIDTH = data.diagramWidth; + + if (modelType == 'design') { + INITIAL_CANVAS_WIDTH += 20; + } else { + INITIAL_CANVAS_WIDTH += 30; + } + + INITIAL_CANVAS_HEIGHT = data.diagramHeight + 50; + canvasWidth = INITIAL_CANVAS_WIDTH; + canvasHeight = INITIAL_CANVAS_HEIGHT; + viewBoxWidth = INITIAL_CANVAS_WIDTH; + viewBoxHeight = INITIAL_CANVAS_HEIGHT; + + if (modelType == 'design') { + var headerBarHeight = 170; + var offsetY = 0; + if (jQuery(window).height() > (canvasHeight + headerBarHeight)) + { + offsetY = (jQuery(window).height() - headerBarHeight - canvasHeight) / 2; + } + + if (offsetY > 50) { + offsetY = 50; + } + + jQuery('#bpmnModel').css('marginTop', offsetY); + } + + jQuery('#bpmnModel').width(INITIAL_CANVAS_WIDTH); + jQuery('#bpmnModel').height(INITIAL_CANVAS_HEIGHT); + paper = Raphael(document.getElementById('bpmnModel'), canvasWidth, canvasHeight); + paper.setViewBox(0, 0, viewBoxWidth, viewBoxHeight, false); + paper.renderfix(); + + if (data.pools) + { + for (var i = 0; i < data.pools.length; i++) + { + var pool = data.pools[i]; + _drawPool(pool); + } + } + + var modelElements = data.elements; + for (var i = 0; i < modelElements.length; i++) + { + var element = modelElements[i]; + //try { + var drawFunction = eval("_draw" + element.type); + drawFunction(element); + //} catch(err) {console.log(err);} + } + + if (data.flows) + { + for (var i = 0; i < data.flows.length; i++) + { + var flow = data.flows[i]; + if (flow.type === 'sequenceFlow') { + _drawFlow(flow); + } else if (flow.type === 'association') { + _drawAssociation(flow); + } + } + } +}); + +request.error(function(jqXHR, textStatus, errorThrown) { + alert("error"); +}); diff --git a/snow-flowable/src/main/resources/static/display/jquery.qtip.min.css b/snow-flowable/src/main/resources/static/display/jquery.qtip.min.css new file mode 100644 index 0000000..aef428d --- /dev/null +++ b/snow-flowable/src/main/resources/static/display/jquery.qtip.min.css @@ -0,0 +1,2 @@ +/* qTip2 v2.2.0 basic css3 | qtip2.com | Licensed MIT, GPL | Wed Dec 18 2013 05:02:24 */ +.qtip{position:absolute;left:-28000px;top:-28000px;display:none;max-width:280px;min-width:50px;font-size:10.5px;line-height:12px;direction:ltr;box-shadow:none;padding:0}.qtip-content{position:relative;padding:5px 9px;overflow:hidden;text-align:left;word-wrap:break-word}.qtip-titlebar{position:relative;padding:5px 35px 5px 10px;overflow:hidden;border-width:0 0 1px;font-weight:700}.qtip-titlebar+.qtip-content{border-top-width:0!important}.qtip-close{position:absolute;right:-9px;top:-9px;cursor:pointer;outline:medium none;border-width:1px;border-style:solid;border-color:transparent}.qtip-titlebar .qtip-close{right:4px;top:50%;margin-top:-9px}* html .qtip-titlebar .qtip-close{top:16px}.qtip-titlebar .ui-icon,.qtip-icon .ui-icon{display:block;text-indent:-1000em;direction:ltr}.qtip-icon,.qtip-icon .ui-icon{-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;text-decoration:none}.qtip-icon .ui-icon{width:18px;height:14px;line-height:14px;text-align:center;text-indent:0;font:400 bold 10px/13px Tahoma,sans-serif;color:inherit;background:transparent none no-repeat -100em -100em}.qtip-focus{}.qtip-hover{}.qtip-default{border-width:1px;border-style:solid;border-color:#F1D031;background-color:#FFFFA3;color:#555}.qtip-default .qtip-titlebar{background-color:#FFEF93}.qtip-default .qtip-icon{border-color:#CCC;background:#F1F1F1;color:#777}.qtip-default .qtip-titlebar .qtip-close{border-color:#AAA;color:#111} .qtip-light{background-color:#fff;border-color:#E2E2E2;color:#454545}.qtip-light .qtip-titlebar{background-color:#f1f1f1} .qtip-dark{background-color:#505050;border-color:#303030;color:#f3f3f3}.qtip-dark .qtip-titlebar{background-color:#404040}.qtip-dark .qtip-icon{border-color:#444}.qtip-dark .qtip-titlebar .ui-state-hover{border-color:#303030} .qtip-cream{background-color:#FBF7AA;border-color:#F9E98E;color:#A27D35}.qtip-cream .qtip-titlebar{background-color:#F0DE7D}.qtip-cream .qtip-close .qtip-icon{background-position:-82px 0} .qtip-red{background-color:#F78B83;border-color:#D95252;color:#912323}.qtip-red .qtip-titlebar{background-color:#F06D65}.qtip-red .qtip-close .qtip-icon{background-position:-102px 0}.qtip-red .qtip-icon{border-color:#D95252}.qtip-red .qtip-titlebar .ui-state-hover{border-color:#D95252} .qtip-green{background-color:#CAED9E;border-color:#90D93F;color:#3F6219}.qtip-green .qtip-titlebar{background-color:#B0DE78}.qtip-green .qtip-close .qtip-icon{background-position:-42px 0} .qtip-blue{background-color:#E5F6FE;border-color:#ADD9ED;color:#5E99BD}.qtip-blue .qtip-titlebar{background-color:#D0E9F5}.qtip-blue .qtip-close .qtip-icon{background-position:-2px 0}.qtip-shadow{-webkit-box-shadow:1px 1px 3px 1px rgba(0,0,0,.15);-moz-box-shadow:1px 1px 3px 1px rgba(0,0,0,.15);box-shadow:1px 1px 3px 1px rgba(0,0,0,.15)}.qtip-rounded,.qtip-tipsy,.qtip-bootstrap{-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.qtip-rounded .qtip-titlebar{-moz-border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.qtip-youtube{-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-webkit-box-shadow:0 0 3px #333;-moz-box-shadow:0 0 3px #333;box-shadow:0 0 3px #333;color:#fff;border-width:0;background:#4A4A4A;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#4A4A4A),color-stop(100%,#000));background-image:-webkit-linear-gradient(top,#4A4A4A 0,#000 100%);background-image:-moz-linear-gradient(top,#4A4A4A 0,#000 100%);background-image:-ms-linear-gradient(top,#4A4A4A 0,#000 100%);background-image:-o-linear-gradient(top,#4A4A4A 0,#000 100%)}.qtip-youtube .qtip-titlebar{background-color:#4A4A4A;background-color:rgba(0,0,0,0)}.qtip-youtube .qtip-content{padding:.75em;font:12px arial,sans-serif;filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr=#4a4a4a, EndColorStr=#000000);-ms-filter:"progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr=#4a4a4a, EndColorStr=#000000);"}.qtip-youtube .qtip-icon{border-color:#222}.qtip-youtube .qtip-titlebar .ui-state-hover{border-color:#303030}.qtip-jtools{background:#232323;background:rgba(0,0,0,.7);background-image:-webkit-gradient(linear,left top,left bottom,from(#717171),to(#232323));background-image:-moz-linear-gradient(top,#717171,#232323);background-image:-webkit-linear-gradient(top,#717171,#232323);background-image:-ms-linear-gradient(top,#717171,#232323);background-image:-o-linear-gradient(top,#717171,#232323);border:2px solid #ddd;border:2px solid rgba(241,241,241,1);-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-webkit-box-shadow:0 0 12px #333;-moz-box-shadow:0 0 12px #333;box-shadow:0 0 12px #333}.qtip-jtools .qtip-titlebar{background-color:transparent;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171, endColorstr=#4A4A4A);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171, endColorstr=#4A4A4A)"}.qtip-jtools .qtip-content{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A, endColorstr=#232323);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A, endColorstr=#232323)"}.qtip-jtools .qtip-titlebar,.qtip-jtools .qtip-content{background:transparent;color:#fff;border:0 dashed transparent}.qtip-jtools .qtip-icon{border-color:#555}.qtip-jtools .qtip-titlebar .ui-state-hover{border-color:#333}.qtip-cluetip{-webkit-box-shadow:4px 4px 5px rgba(0,0,0,.4);-moz-box-shadow:4px 4px 5px rgba(0,0,0,.4);box-shadow:4px 4px 5px rgba(0,0,0,.4);background-color:#D9D9C2;color:#111;border:0 dashed transparent}.qtip-cluetip .qtip-titlebar{background-color:#87876A;color:#fff;border:0 dashed transparent}.qtip-cluetip .qtip-icon{border-color:#808064}.qtip-cluetip .qtip-titlebar .ui-state-hover{border-color:#696952;color:#696952}.qtip-tipsy{background:#000;background:rgba(0,0,0,.87);color:#fff;border:0 solid transparent;font-size:11px;font-family:'Lucida Grande',sans-serif;font-weight:700;line-height:16px;text-shadow:0 1px #000}.qtip-tipsy .qtip-titlebar{padding:6px 35px 0 10px;background-color:transparent}.qtip-tipsy .qtip-content{padding:6px 10px}.qtip-tipsy .qtip-icon{border-color:#222;text-shadow:none}.qtip-tipsy .qtip-titlebar .ui-state-hover{border-color:#303030}.qtip-tipped{border:3px solid #959FA9;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;background-color:#F9F9F9;color:#454545;font-weight:400;font-family:serif}.qtip-tipped .qtip-titlebar{border-bottom-width:0;color:#fff;background:#3A79B8;background-image:-webkit-gradient(linear,left top,left bottom,from(#3A79B8),to(#2E629D));background-image:-webkit-linear-gradient(top,#3A79B8,#2E629D);background-image:-moz-linear-gradient(top,#3A79B8,#2E629D);background-image:-ms-linear-gradient(top,#3A79B8,#2E629D);background-image:-o-linear-gradient(top,#3A79B8,#2E629D);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8, endColorstr=#2E629D);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8, endColorstr=#2E629D)"}.qtip-tipped .qtip-icon{border:2px solid #285589;background:#285589}.qtip-tipped .qtip-icon .ui-icon{background-color:#FBFBFB;color:#555}.qtip-bootstrap{font-size:14px;line-height:20px;color:#333;padding:1px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.qtip-bootstrap .qtip-titlebar{padding:8px 14px;margin:0;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.qtip-bootstrap .qtip-titlebar .qtip-close{right:11px;top:45%;border-style:none}.qtip-bootstrap .qtip-content{padding:9px 14px}.qtip-bootstrap .qtip-icon{background:transparent}.qtip-bootstrap .qtip-icon .ui-icon{width:auto;height:auto;float:right;font-size:20px;font-weight:700;line-height:18px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.qtip-bootstrap .qtip-icon .ui-icon:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}.qtip:not(.ie9haxors) div.qtip-content,.qtip:not(.ie9haxors) div.qtip-titlebar{filter:none;-ms-filter:none}.qtip .qtip-tip{margin:0 auto;overflow:hidden;z-index:10}x:-o-prefocus,.qtip .qtip-tip{visibility:hidden}.qtip .qtip-tip,.qtip .qtip-tip .qtip-vml,.qtip .qtip-tip canvas{position:absolute;color:#123456;background:transparent;border:0 dashed transparent}.qtip .qtip-tip canvas{top:0;left:0}.qtip .qtip-tip .qtip-vml{behavior:url(#default#VML);display:inline-block;visibility:visible}#qtip-overlay{position:fixed;left:0;top:0;width:100%;height:100%}#qtip-overlay.blurs{cursor:pointer}#qtip-overlay div{position:absolute;left:0;top:0;width:100%;height:100%;background-color:#000;opacity:.7;filter:alpha(opacity=70);-ms-filter:"alpha(Opacity=70)"} \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/display/jquery.qtip.min.js b/snow-flowable/src/main/resources/static/display/jquery.qtip.min.js new file mode 100644 index 0000000..25bf424 --- /dev/null +++ b/snow-flowable/src/main/resources/static/display/jquery.qtip.min.js @@ -0,0 +1,5 @@ +/* qTip2 v2.2.0 tips viewport svg modal | qtip2.com | Licensed MIT, GPL | Wed Dec 18 2013 05:02:22 */ + +!function(a,b,c){!function(a){"use strict";"function"==typeof define&&define.amd?define(["jquery"],a):jQuery&&!jQuery.fn.qtip&&a(jQuery)}(function(d){"use strict";function e(a,b,c,e){this.id=c,this.target=a,this.tooltip=F,this.elements={target:a},this._id=S+"-"+c,this.timers={img:{}},this.options=b,this.plugins={},this.cache={event:{},target:d(),disabled:E,attr:e,onTooltip:E,lastClass:""},this.rendered=this.destroyed=this.disabled=this.waiting=this.hiddenDuringWait=this.positioning=this.triggering=E}function f(a){return a===F||"object"!==d.type(a)}function g(a){return!(d.isFunction(a)||a&&a.attr||a.length||"object"===d.type(a)&&(a.jquery||a.then))}function h(a){var b,c,e,h;return f(a)?E:(f(a.metadata)&&(a.metadata={type:a.metadata}),"content"in a&&(b=a.content,f(b)||b.jquery||b.done?b=a.content={text:c=g(b)?E:b}:c=b.text,"ajax"in b&&(e=b.ajax,h=e&&e.once!==E,delete b.ajax,b.text=function(a,b){var f=c||d(this).attr(b.options.content.attr)||"Loading...",g=d.ajax(d.extend({},e,{context:b})).then(e.success,F,e.error).then(function(a){return a&&h&&b.set("content.text",a),a},function(a,c,d){b.destroyed||0===a.status||b.set("content.text",c+": "+d)});return h?f:(b.set("content.text",f),g)}),"title"in b&&(f(b.title)||(b.button=b.title.button,b.title=b.title.text),g(b.title||E)&&(b.title=E))),"position"in a&&f(a.position)&&(a.position={my:a.position,at:a.position}),"show"in a&&f(a.show)&&(a.show=a.show.jquery?{target:a.show}:a.show===D?{ready:D}:{event:a.show}),"hide"in a&&f(a.hide)&&(a.hide=a.hide.jquery?{target:a.hide}:{event:a.hide}),"style"in a&&f(a.style)&&(a.style={classes:a.style}),d.each(R,function(){this.sanitize&&this.sanitize(a)}),a)}function i(a,b){for(var c,d=0,e=a,f=b.split(".");e=e[f[d++]];)d0?setTimeout(d.proxy(a,this),b):(a.call(this),void 0)}function n(a){return this.tooltip.hasClass(ab)?E:(clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this.timers.show=m.call(this,function(){this.toggle(D,a)},this.options.show.delay),void 0)}function o(a){if(this.tooltip.hasClass(ab))return E;var b=d(a.relatedTarget),c=b.closest(W)[0]===this.tooltip[0],e=b[0]===this.options.show.target[0];if(clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this!==b[0]&&"mouse"===this.options.position.target&&c||this.options.hide.fixed&&/mouse(out|leave|move)/.test(a.type)&&(c||e))try{a.preventDefault(),a.stopImmediatePropagation()}catch(f){}else this.timers.hide=m.call(this,function(){this.toggle(E,a)},this.options.hide.delay,this)}function p(a){return this.tooltip.hasClass(ab)||!this.options.hide.inactive?E:(clearTimeout(this.timers.inactive),this.timers.inactive=m.call(this,function(){this.hide(a)},this.options.hide.inactive),void 0)}function q(a){this.rendered&&this.tooltip[0].offsetWidth>0&&this.reposition(a)}function r(a,c,e){d(b.body).delegate(a,(c.split?c:c.join(hb+" "))+hb,function(){var a=y.api[d.attr(this,U)];a&&!a.disabled&&e.apply(a,arguments)})}function s(a,c,f){var g,i,j,k,l,m=d(b.body),n=a[0]===b?m:a,o=a.metadata?a.metadata(f.metadata):F,p="html5"===f.metadata.type&&o?o[f.metadata.name]:F,q=a.data(f.metadata.name||"qtipopts");try{q="string"==typeof q?d.parseJSON(q):q}catch(r){}if(k=d.extend(D,{},y.defaults,f,"object"==typeof q?h(q):F,h(p||o)),i=k.position,k.id=c,"boolean"==typeof k.content.text){if(j=a.attr(k.content.attr),k.content.attr===E||!j)return E;k.content.text=j}if(i.container.length||(i.container=m),i.target===E&&(i.target=n),k.show.target===E&&(k.show.target=n),k.show.solo===D&&(k.show.solo=i.container.closest("body")),k.hide.target===E&&(k.hide.target=n),k.position.viewport===D&&(k.position.viewport=i.container),i.container=i.container.eq(0),i.at=new A(i.at,D),i.my=new A(i.my),a.data(S))if(k.overwrite)a.qtip("destroy",!0);else if(k.overwrite===E)return E;return a.attr(T,c),k.suppress&&(l=a.attr("title"))&&a.removeAttr("title").attr(cb,l).attr("title",""),g=new e(a,k,c,!!j),a.data(S,g),a.one("remove.qtip-"+c+" removeqtip.qtip-"+c,function(){var a;(a=d(this).data(S))&&a.destroy(!0)}),g}function t(a){return a.charAt(0).toUpperCase()+a.slice(1)}function u(a,b){var d,e,f=b.charAt(0).toUpperCase()+b.slice(1),g=(b+" "+sb.join(f+" ")+f).split(" "),h=0;if(rb[b])return a.css(rb[b]);for(;d=g[h++];)if((e=a.css(d))!==c)return rb[b]=d,e}function v(a,b){return Math.ceil(parseFloat(u(a,b)))}function w(a,b){this._ns="tip",this.options=b,this.offset=b.offset,this.size=[b.width,b.height],this.init(this.qtip=a)}function x(a,b){this.options=b,this._ns="-modal",this.init(this.qtip=a)}var y,z,A,B,C,D=!0,E=!1,F=null,G="x",H="y",I="width",J="height",K="top",L="left",M="bottom",N="right",O="center",P="flipinvert",Q="shift",R={},S="qtip",T="data-hasqtip",U="data-qtip-id",V=["ui-widget","ui-tooltip"],W="."+S,X="click dblclick mousedown mouseup mousemove mouseleave mouseenter".split(" "),Y=S+"-fixed",Z=S+"-default",$=S+"-focus",_=S+"-hover",ab=S+"-disabled",bb="_replacedByqTip",cb="oldtitle",db={ie:function(){for(var a=3,c=b.createElement("div");(c.innerHTML="")&&c.getElementsByTagName("i")[0];);return a>4?a:0/0}(),iOS:parseFloat((""+(/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_",".").replace("_",""))||E};z=e.prototype,z._when=function(a){return d.when.apply(d,a)},z.render=function(a){if(this.rendered||this.destroyed)return this;var b,c=this,e=this.options,f=this.cache,g=this.elements,h=e.content.text,i=e.content.title,j=e.content.button,k=e.position,l=("."+this._id+" ",[]);return d.attr(this.target[0],"aria-describedby",this._id),this.tooltip=g.tooltip=b=d("
",{id:this._id,"class":[S,Z,e.style.classes,S+"-pos-"+e.position.my.abbrev()].join(" "),width:e.style.width||"",height:e.style.height||"",tracking:"mouse"===k.target&&k.adjust.mouse,role:"alert","aria-live":"polite","aria-atomic":E,"aria-describedby":this._id+"-content","aria-hidden":D}).toggleClass(ab,this.disabled).attr(U,this.id).data(S,this).appendTo(k.container).append(g.content=d("
",{"class":S+"-content",id:this._id+"-content","aria-atomic":D})),this.rendered=-1,this.positioning=D,i&&(this._createTitle(),d.isFunction(i)||l.push(this._updateTitle(i,E))),j&&this._createButton(),d.isFunction(h)||l.push(this._updateContent(h,E)),this.rendered=D,this._setWidget(),d.each(R,function(a){var b;"render"===this.initialize&&(b=this(c))&&(c.plugins[a]=b)}),this._unassignEvents(),this._assignEvents(),this._when(l).then(function(){c._trigger("render"),c.positioning=E,c.hiddenDuringWait||!e.show.ready&&!a||c.toggle(D,f.event,E),c.hiddenDuringWait=E}),y.api[this.id]=this,this},z.destroy=function(a){function b(){if(!this.destroyed){this.destroyed=D;var a=this.target,b=a.attr(cb);this.rendered&&this.tooltip.stop(1,0).find("*").remove().end().remove(),d.each(this.plugins,function(){this.destroy&&this.destroy()}),clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this._unassignEvents(),a.removeData(S).removeAttr(U).removeAttr(T).removeAttr("aria-describedby"),this.options.suppress&&b&&a.attr("title",b).removeAttr(cb),this._unbind(a),this.options=this.elements=this.cache=this.timers=this.plugins=this.mouse=F,delete y.api[this.id]}}return this.destroyed?this.target:(a===D&&"hide"!==this.triggering||!this.rendered?b.call(this):(this.tooltip.one("tooltiphidden",d.proxy(b,this)),!this.triggering&&this.hide()),this.target)},B=z.checks={builtin:{"^id$":function(a,b,c,e){var f=c===D?y.nextid:c,g=S+"-"+f;f!==E&&f.length>0&&!d("#"+g).length?(this._id=g,this.rendered&&(this.tooltip[0].id=this._id,this.elements.content[0].id=this._id+"-content",this.elements.title[0].id=this._id+"-title")):a[b]=e},"^prerender":function(a,b,c){c&&!this.rendered&&this.render(this.options.show.ready)},"^content.text$":function(a,b,c){this._updateContent(c)},"^content.attr$":function(a,b,c,d){this.options.content.text===this.target.attr(d)&&this._updateContent(this.target.attr(c))},"^content.title$":function(a,b,c){return c?(c&&!this.elements.title&&this._createTitle(),this._updateTitle(c),void 0):this._removeTitle()},"^content.button$":function(a,b,c){this._updateButton(c)},"^content.title.(text|button)$":function(a,b,c){this.set("content."+b,c)},"^position.(my|at)$":function(a,b,c){"string"==typeof c&&(a[b]=new A(c,"at"===b))},"^position.container$":function(a,b,c){this.rendered&&this.tooltip.appendTo(c)},"^show.ready$":function(a,b,c){c&&(!this.rendered&&this.render(D)||this.toggle(D))},"^style.classes$":function(a,b,c,d){this.rendered&&this.tooltip.removeClass(d).addClass(c)},"^style.(width|height)":function(a,b,c){this.rendered&&this.tooltip.css(b,c)},"^style.widget|content.title":function(){this.rendered&&this._setWidget()},"^style.def":function(a,b,c){this.rendered&&this.tooltip.toggleClass(Z,!!c)},"^events.(render|show|move|hide|focus|blur)$":function(a,b,c){this.rendered&&this.tooltip[(d.isFunction(c)?"":"un")+"bind"]("tooltip"+b,c)},"^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)":function(){if(this.rendered){var a=this.options.position;this.tooltip.attr("tracking","mouse"===a.target&&a.adjust.mouse),this._unassignEvents(),this._assignEvents()}}}},z.get=function(a){if(this.destroyed)return this;var b=i(this.options,a.toLowerCase()),c=b[0][b[1]];return c.precedance?c.string():c};var eb=/^position\.(my|at|adjust|target|container|viewport)|style|content|show\.ready/i,fb=/^prerender|show\.ready/i;z.set=function(a,b){if(this.destroyed)return this;{var c,e=this.rendered,f=E,g=this.options;this.checks}return"string"==typeof a?(c=a,a={},a[c]=b):a=d.extend({},a),d.each(a,function(b,c){if(e&&fb.test(b))return delete a[b],void 0;var h,j=i(g,b.toLowerCase());h=j[0][j[1]],j[0][j[1]]=c&&c.nodeType?d(c):c,f=eb.test(b)||f,a[b]=[j[0],j[1],c,h]}),h(g),this.positioning=D,d.each(a,d.proxy(j,this)),this.positioning=E,this.rendered&&this.tooltip[0].offsetWidth>0&&f&&this.reposition("mouse"===g.position.target?F:this.cache.event),this},z._update=function(a,b){var c=this,e=this.cache;return this.rendered&&a?(d.isFunction(a)&&(a=a.call(this.elements.target,e.event,this)||""),d.isFunction(a.then)?(e.waiting=D,a.then(function(a){return e.waiting=E,c._update(a,b)},F,function(a){return c._update(a,b)})):a===E||!a&&""!==a?E:(a.jquery&&a.length>0?b.empty().append(a.css({display:"block",visibility:"visible"})):b.html(a),this._waitForContent(b).then(function(a){a.images&&a.images.length&&c.rendered&&c.tooltip[0].offsetWidth>0&&c.reposition(e.event,!a.length)}))):E},z._waitForContent=function(a){var b=this.cache;return b.waiting=D,(d.fn.imagesLoaded?a.imagesLoaded():d.Deferred().resolve([])).done(function(){b.waiting=E}).promise()},z._updateContent=function(a,b){this._update(a,this.elements.content,b)},z._updateTitle=function(a,b){this._update(a,this.elements.title,b)===E&&this._removeTitle(E)},z._createTitle=function(){var a=this.elements,b=this._id+"-title";a.titlebar&&this._removeTitle(),a.titlebar=d("
",{"class":S+"-titlebar "+(this.options.style.widget?k("header"):"")}).append(a.title=d("
",{id:b,"class":S+"-title","aria-atomic":D})).insertBefore(a.content).delegate(".qtip-close","mousedown keydown mouseup keyup mouseout",function(a){d(this).toggleClass("ui-state-active ui-state-focus","down"===a.type.substr(-4))}).delegate(".qtip-close","mouseover mouseout",function(a){d(this).toggleClass("ui-state-hover","mouseover"===a.type)}),this.options.content.button&&this._createButton()},z._removeTitle=function(a){var b=this.elements;b.title&&(b.titlebar.remove(),b.titlebar=b.title=b.button=F,a!==E&&this.reposition())},z.reposition=function(c,e){if(!this.rendered||this.positioning||this.destroyed)return this;this.positioning=D;var f,g,h=this.cache,i=this.tooltip,j=this.options.position,k=j.target,l=j.my,m=j.at,n=j.viewport,o=j.container,p=j.adjust,q=p.method.split(" "),r=i.outerWidth(E),s=i.outerHeight(E),t=0,u=0,v=i.css("position"),w={left:0,top:0},x=i[0].offsetWidth>0,y=c&&"scroll"===c.type,z=d(a),A=o[0].ownerDocument,B=this.mouse;if(d.isArray(k)&&2===k.length)m={x:L,y:K},w={left:k[0],top:k[1]};else if("mouse"===k)m={x:L,y:K},!B||!B.pageX||!p.mouse&&c&&c.pageX?c&&c.pageX||((!p.mouse||this.options.show.distance)&&h.origin&&h.origin.pageX?c=h.origin:(!c||c&&("resize"===c.type||"scroll"===c.type))&&(c=h.event)):c=B,"static"!==v&&(w=o.offset()),A.body.offsetWidth!==(a.innerWidth||A.documentElement.clientWidth)&&(g=d(b.body).offset()),w={left:c.pageX-w.left+(g&&g.left||0),top:c.pageY-w.top+(g&&g.top||0)},p.mouse&&y&&B&&(w.left-=(B.scrollX||0)-z.scrollLeft(),w.top-=(B.scrollY||0)-z.scrollTop());else{if("event"===k?c&&c.target&&"scroll"!==c.type&&"resize"!==c.type?h.target=d(c.target):c.target||(h.target=this.elements.target):"event"!==k&&(h.target=d(k.jquery?k:this.elements.target)),k=h.target,k=d(k).eq(0),0===k.length)return this;k[0]===b||k[0]===a?(t=db.iOS?a.innerWidth:k.width(),u=db.iOS?a.innerHeight:k.height(),k[0]===a&&(w={top:(n||k).scrollTop(),left:(n||k).scrollLeft()})):R.imagemap&&k.is("area")?f=R.imagemap(this,k,m,R.viewport?q:E):R.svg&&k&&k[0].ownerSVGElement?f=R.svg(this,k,m,R.viewport?q:E):(t=k.outerWidth(E),u=k.outerHeight(E),w=k.offset()),f&&(t=f.width,u=f.height,g=f.offset,w=f.position),w=this.reposition.offset(k,w,o),(db.iOS>3.1&&db.iOS<4.1||db.iOS>=4.3&&db.iOS<4.33||!db.iOS&&"fixed"===v)&&(w.left-=z.scrollLeft(),w.top-=z.scrollTop()),(!f||f&&f.adjustable!==E)&&(w.left+=m.x===N?t:m.x===O?t/2:0,w.top+=m.y===M?u:m.y===O?u/2:0)}return w.left+=p.x+(l.x===N?-r:l.x===O?-r/2:0),w.top+=p.y+(l.y===M?-s:l.y===O?-s/2:0),R.viewport?(w.adjusted=R.viewport(this,w,j,t,u,r,s),g&&w.adjusted.left&&(w.left+=g.left),g&&w.adjusted.top&&(w.top+=g.top)):w.adjusted={left:0,top:0},this._trigger("move",[w,n.elem||n],c)?(delete w.adjusted,e===E||!x||isNaN(w.left)||isNaN(w.top)||"mouse"===k||!d.isFunction(j.effect)?i.css(w):d.isFunction(j.effect)&&(j.effect.call(i,this,d.extend({},w)),i.queue(function(a){d(this).css({opacity:"",height:""}),db.ie&&this.style.removeAttribute("filter"),a()})),this.positioning=E,this):this},z.reposition.offset=function(a,c,e){function f(a,b){c.left+=b*a.scrollLeft(),c.top+=b*a.scrollTop()}if(!e[0])return c;var g,h,i,j,k=d(a[0].ownerDocument),l=!!db.ie&&"CSS1Compat"!==b.compatMode,m=e[0];do"static"!==(h=d.css(m,"position"))&&("fixed"===h?(i=m.getBoundingClientRect(),f(k,-1)):(i=d(m).position(),i.left+=parseFloat(d.css(m,"borderLeftWidth"))||0,i.top+=parseFloat(d.css(m,"borderTopWidth"))||0),c.left-=i.left+(parseFloat(d.css(m,"marginLeft"))||0),c.top-=i.top+(parseFloat(d.css(m,"marginTop"))||0),g||"hidden"===(j=d.css(m,"overflow"))||"visible"===j||(g=d(m)));while(m=m.offsetParent);return g&&(g[0]!==k[0]||l)&&f(g,1),c};var gb=(A=z.reposition.Corner=function(a,b){a=(""+a).replace(/([A-Z])/," $1").replace(/middle/gi,O).toLowerCase(),this.x=(a.match(/left|right/i)||a.match(/center/)||["inherit"])[0].toLowerCase(),this.y=(a.match(/top|bottom|center/i)||["inherit"])[0].toLowerCase(),this.forceY=!!b;var c=a.charAt(0);this.precedance="t"===c||"b"===c?H:G}).prototype;gb.invert=function(a,b){this[a]=this[a]===L?N:this[a]===N?L:b||this[a]},gb.string=function(){var a=this.x,b=this.y;return a===b?a:this.precedance===H||this.forceY&&"center"!==b?b+" "+a:a+" "+b},gb.abbrev=function(){var a=this.string().split(" ");return a[0].charAt(0)+(a[1]&&a[1].charAt(0)||"")},gb.clone=function(){return new A(this.string(),this.forceY)},z.toggle=function(a,c){var e=this.cache,f=this.options,g=this.tooltip;if(c){if(/over|enter/.test(c.type)&&/out|leave/.test(e.event.type)&&f.show.target.add(c.target).length===f.show.target.length&&g.has(c.relatedTarget).length)return this;e.event=l(c)}if(this.waiting&&!a&&(this.hiddenDuringWait=D),!this.rendered)return a?this.render(1):this;if(this.destroyed||this.disabled)return this;var h,i,j,k=a?"show":"hide",m=this.options[k],n=(this.options[a?"hide":"show"],this.options.position),o=this.options.content,p=this.tooltip.css("width"),q=this.tooltip.is(":visible"),r=a||1===m.target.length,s=!c||m.target.length<2||e.target[0]===c.target;return(typeof a).search("boolean|number")&&(a=!q),h=!g.is(":animated")&&q===a&&s,i=h?F:!!this._trigger(k,[90]),this.destroyed?this:(i!==E&&a&&this.focus(c),!i||h?this:(d.attr(g[0],"aria-hidden",!a),a?(e.origin=l(this.mouse),d.isFunction(o.text)&&this._updateContent(o.text,E),d.isFunction(o.title)&&this._updateTitle(o.title,E),!C&&"mouse"===n.target&&n.adjust.mouse&&(d(b).bind("mousemove."+S,this._storeMouse),C=D),p||g.css("width",g.outerWidth(E)),this.reposition(c,arguments[2]),p||g.css("width",""),m.solo&&("string"==typeof m.solo?d(m.solo):d(W,m.solo)).not(g).not(m.target).qtip("hide",d.Event("tooltipsolo"))):(clearTimeout(this.timers.show),delete e.origin,C&&!d(W+'[tracking="true"]:visible',m.solo).not(g).length&&(d(b).unbind("mousemove."+S),C=E),this.blur(c)),j=d.proxy(function(){a?(db.ie&&g[0].style.removeAttribute("filter"),g.css("overflow",""),"string"==typeof m.autofocus&&d(this.options.show.autofocus,g).focus(),this.options.show.target.trigger("qtip-"+this.id+"-inactive")):g.css({display:"",visibility:"",opacity:"",left:"",top:""}),this._trigger(a?"visible":"hidden")},this),m.effect===E||r===E?(g[k](),j()):d.isFunction(m.effect)?(g.stop(1,1),m.effect.call(g,this),g.queue("fx",function(a){j(),a()})):g.fadeTo(90,a?1:0,j),a&&m.target.trigger("qtip-"+this.id+"-inactive"),this))},z.show=function(a){return this.toggle(D,a)},z.hide=function(a){return this.toggle(E,a)},z.focus=function(a){if(!this.rendered||this.destroyed)return this;var b=d(W),c=this.tooltip,e=parseInt(c[0].style.zIndex,10),f=y.zindex+b.length;return c.hasClass($)||this._trigger("focus",[f],a)&&(e!==f&&(b.each(function(){this.style.zIndex>e&&(this.style.zIndex=this.style.zIndex-1)}),b.filter("."+$).qtip("blur",a)),c.addClass($)[0].style.zIndex=f),this},z.blur=function(a){return!this.rendered||this.destroyed?this:(this.tooltip.removeClass($),this._trigger("blur",[this.tooltip.css("zIndex")],a),this)},z.disable=function(a){return this.destroyed?this:("toggle"===a?a=!(this.rendered?this.tooltip.hasClass(ab):this.disabled):"boolean"!=typeof a&&(a=D),this.rendered&&this.tooltip.toggleClass(ab,a).attr("aria-disabled",a),this.disabled=!!a,this)},z.enable=function(){return this.disable(E)},z._createButton=function(){var a=this,b=this.elements,c=b.tooltip,e=this.options.content.button,f="string"==typeof e,g=f?e:"Close tooltip";b.button&&b.button.remove(),b.button=e.jquery?e:d("",{"class":"qtip-close "+(this.options.style.widget?"":S+"-icon"),title:g,"aria-label":g}).prepend(d("",{"class":"ui-icon ui-icon-close",html:"×"})),b.button.appendTo(b.titlebar||c).attr("role","button").click(function(b){return c.hasClass(ab)||a.hide(b),E})},z._updateButton=function(a){if(!this.rendered)return E;var b=this.elements.button;a?this._createButton():b.remove()},z._setWidget=function(){var a=this.options.style.widget,b=this.elements,c=b.tooltip,d=c.hasClass(ab);c.removeClass(ab),ab=a?"ui-state-disabled":"qtip-disabled",c.toggleClass(ab,d),c.toggleClass("ui-helper-reset "+k(),a).toggleClass(Z,this.options.style.def&&!a),b.content&&b.content.toggleClass(k("content"),a),b.titlebar&&b.titlebar.toggleClass(k("header"),a),b.button&&b.button.toggleClass(S+"-icon",!a)},z._storeMouse=function(a){(this.mouse=l(a)).type="mousemove"},z._bind=function(a,b,c,e,f){var g="."+this._id+(e?"-"+e:"");b.length&&d(a).bind((b.split?b:b.join(g+" "))+g,d.proxy(c,f||this))},z._unbind=function(a,b){d(a).unbind("."+this._id+(b?"-"+b:""))};var hb="."+S;d(function(){r(W,["mouseenter","mouseleave"],function(a){var b="mouseenter"===a.type,c=d(a.currentTarget),e=d(a.relatedTarget||a.target),f=this.options;b?(this.focus(a),c.hasClass(Y)&&!c.hasClass(ab)&&clearTimeout(this.timers.hide)):"mouse"===f.position.target&&f.hide.event&&f.show.target&&!e.closest(f.show.target[0]).length&&this.hide(a),c.toggleClass(_,b)}),r("["+U+"]",X,p)}),z._trigger=function(a,b,c){var e=d.Event("tooltip"+a);return e.originalEvent=c&&d.extend({},c)||this.cache.event||F,this.triggering=a,this.tooltip.trigger(e,[this].concat(b||[])),this.triggering=E,!e.isDefaultPrevented()},z._bindEvents=function(a,b,c,e,f,g){if(e.add(c).length===e.length){var h=[];b=d.map(b,function(b){var c=d.inArray(b,a);return c>-1?(h.push(a.splice(c,1)[0]),void 0):b}),h.length&&this._bind(c,h,function(a){var b=this.rendered?this.tooltip[0].offsetWidth>0:!1;(b?g:f).call(this,a)})}this._bind(c,a,f),this._bind(e,b,g)},z._assignInitialEvents=function(a){function b(a){return this.disabled||this.destroyed?E:(this.cache.event=l(a),this.cache.target=a?d(a.target):[c],clearTimeout(this.timers.show),this.timers.show=m.call(this,function(){this.render("object"==typeof a||e.show.ready)},e.show.delay),void 0)}var e=this.options,f=e.show.target,g=e.hide.target,h=e.show.event?d.trim(""+e.show.event).split(" "):[],i=e.hide.event?d.trim(""+e.hide.event).split(" "):[];/mouse(over|enter)/i.test(e.show.event)&&!/mouse(out|leave)/i.test(e.hide.event)&&i.push("mouseleave"),this._bind(f,"mousemove",function(a){this._storeMouse(a),this.cache.onTarget=D}),this._bindEvents(h,i,f,g,b,function(){clearTimeout(this.timers.show)}),(e.show.ready||e.prerender)&&b.call(this,a)},z._assignEvents=function(){var c=this,e=this.options,f=e.position,g=this.tooltip,h=e.show.target,i=e.hide.target,j=f.container,k=f.viewport,l=d(b),m=(d(b.body),d(a)),r=e.show.event?d.trim(""+e.show.event).split(" "):[],s=e.hide.event?d.trim(""+e.hide.event).split(" "):[];d.each(e.events,function(a,b){c._bind(g,"toggle"===a?["tooltipshow","tooltiphide"]:["tooltip"+a],b,null,g)}),/mouse(out|leave)/i.test(e.hide.event)&&"window"===e.hide.leave&&this._bind(l,["mouseout","blur"],function(a){/select|option/.test(a.target.nodeName)||a.relatedTarget||this.hide(a)}),e.hide.fixed?i=i.add(g.addClass(Y)):/mouse(over|enter)/i.test(e.show.event)&&this._bind(i,"mouseleave",function(){clearTimeout(this.timers.show)}),(""+e.hide.event).indexOf("unfocus")>-1&&this._bind(j.closest("html"),["mousedown","touchstart"],function(a){var b=d(a.target),c=this.rendered&&!this.tooltip.hasClass(ab)&&this.tooltip[0].offsetWidth>0,e=b.parents(W).filter(this.tooltip[0]).length>0;b[0]===this.target[0]||b[0]===this.tooltip[0]||e||this.target.has(b[0]).length||!c||this.hide(a)}),"number"==typeof e.hide.inactive&&(this._bind(h,"qtip-"+this.id+"-inactive",p),this._bind(i.add(g),y.inactiveEvents,p,"-inactive")),this._bindEvents(r,s,h,i,n,o),this._bind(h.add(g),"mousemove",function(a){if("number"==typeof e.hide.distance){var b=this.cache.origin||{},c=this.options.hide.distance,d=Math.abs;(d(a.pageX-b.pageX)>=c||d(a.pageY-b.pageY)>=c)&&this.hide(a)}this._storeMouse(a)}),"mouse"===f.target&&f.adjust.mouse&&(e.hide.event&&this._bind(h,["mouseenter","mouseleave"],function(a){this.cache.onTarget="mouseenter"===a.type}),this._bind(l,"mousemove",function(a){this.rendered&&this.cache.onTarget&&!this.tooltip.hasClass(ab)&&this.tooltip[0].offsetWidth>0&&this.reposition(a)})),(f.adjust.resize||k.length)&&this._bind(d.event.special.resize?k:m,"resize",q),f.adjust.scroll&&this._bind(m.add(f.container),"scroll",q)},z._unassignEvents=function(){var c=[this.options.show.target[0],this.options.hide.target[0],this.rendered&&this.tooltip[0],this.options.position.container[0],this.options.position.viewport[0],this.options.position.container.closest("html")[0],a,b];this._unbind(d([]).pushStack(d.grep(c,function(a){return"object"==typeof a})))},y=d.fn.qtip=function(a,b,e){var f=(""+a).toLowerCase(),g=F,i=d.makeArray(arguments).slice(1),j=i[i.length-1],k=this[0]?d.data(this[0],S):F;return!arguments.length&&k||"api"===f?k:"string"==typeof a?(this.each(function(){var a=d.data(this,S);if(!a)return D;if(j&&j.timeStamp&&(a.cache.event=j),!b||"option"!==f&&"options"!==f)a[f]&&a[f].apply(a,i);else{if(e===c&&!d.isPlainObject(b))return g=a.get(b),E;a.set(b,e)}}),g!==F?g:this):"object"!=typeof a&&arguments.length?void 0:(k=h(d.extend(D,{},a)),this.each(function(a){var b,c;return c=d.isArray(k.id)?k.id[a]:k.id,c=!c||c===E||c.length<1||y.api[c]?y.nextid++:c,b=s(d(this),c,k),b===E?D:(y.api[c]=b,d.each(R,function(){"initialize"===this.initialize&&this(b)}),b._assignInitialEvents(j),void 0)}))},d.qtip=e,y.api={},d.each({attr:function(a,b){if(this.length){var c=this[0],e="title",f=d.data(c,"qtip");if(a===e&&f&&"object"==typeof f&&f.options.suppress)return arguments.length<2?d.attr(c,cb):(f&&f.options.content.attr===e&&f.cache.attr&&f.set("content.text",b),this.attr(cb,b))}return d.fn["attr"+bb].apply(this,arguments)},clone:function(a){var b=(d([]),d.fn["clone"+bb].apply(this,arguments));return a||b.filter("["+cb+"]").attr("title",function(){return d.attr(this,cb)}).removeAttr(cb),b}},function(a,b){if(!b||d.fn[a+bb])return D;var c=d.fn[a+bb]=d.fn[a];d.fn[a]=function(){return b.apply(this,arguments)||c.apply(this,arguments)}}),d.ui||(d["cleanData"+bb]=d.cleanData,d.cleanData=function(a){for(var b,c=0;(b=d(a[c])).length;c++)if(b.attr(T))try{b.triggerHandler("removeqtip")}catch(e){}d["cleanData"+bb].apply(this,arguments)}),y.version="2.2.0",y.nextid=0,y.inactiveEvents=X,y.zindex=15e3,y.defaults={prerender:E,id:E,overwrite:D,suppress:D,content:{text:D,attr:"title",title:E,button:E},position:{my:"top left",at:"bottom right",target:E,container:E,viewport:E,adjust:{x:0,y:0,mouse:D,scroll:D,resize:D,method:"flipinvert flipinvert"},effect:function(a,b){d(this).animate(b,{duration:200,queue:E})}},show:{target:E,event:"mouseenter",effect:D,delay:90,solo:E,ready:E,autofocus:E},hide:{target:E,event:"mouseleave",effect:D,delay:0,fixed:E,inactive:E,leave:"window",distance:E},style:{classes:"",widget:E,width:E,height:E,def:D},events:{render:F,move:F,show:F,hide:F,toggle:F,visible:F,hidden:F,focus:F,blur:F}};var ib,jb="margin",kb="border",lb="color",mb="background-color",nb="transparent",ob=" !important",pb=!!b.createElement("canvas").getContext,qb=/rgba?\(0, 0, 0(, 0)?\)|transparent|#123456/i,rb={},sb=["Webkit","O","Moz","ms"];if(pb)var tb=a.devicePixelRatio||1,ub=function(){var a=b.createElement("canvas").getContext("2d");return a.backingStorePixelRatio||a.webkitBackingStorePixelRatio||a.mozBackingStorePixelRatio||a.msBackingStorePixelRatio||a.oBackingStorePixelRatio||1}(),vb=tb/ub;else var wb=function(a,b,c){return"'};d.extend(w.prototype,{init:function(a){var b,c;c=this.element=a.elements.tip=d("
",{"class":S+"-tip"}).prependTo(a.tooltip),pb?(b=d("").appendTo(this.element)[0].getContext("2d"),b.lineJoin="miter",b.miterLimit=1e5,b.save()):(b=wb("shape",'coordorigin="0,0"',"position:absolute;"),this.element.html(b+b),a._bind(d("*",c).add(c),["click","mousedown"],function(a){a.stopPropagation()},this._ns)),a._bind(a.tooltip,"tooltipmove",this.reposition,this._ns,this),this.create()},_swapDimensions:function(){this.size[0]=this.options.height,this.size[1]=this.options.width},_resetDimensions:function(){this.size[0]=this.options.width,this.size[1]=this.options.height},_useTitle:function(a){var b=this.qtip.elements.titlebar;return b&&(a.y===K||a.y===O&&this.element.position().top+this.size[1]/2+this.options.offsetl&&!qb.test(e[1])&&(e[0]=e[1]),this.border=l=p.border!==D?p.border:l):this.border=l=0,k=this.size=this._calculateSize(b),n.css({width:k[0],height:k[1],lineHeight:k[1]+"px"}),j=b.precedance===H?[s(r.x===L?l:r.x===N?k[0]-q[0]-l:(k[0]-q[0])/2),s(r.y===K?k[1]-q[1]:0)]:[s(r.x===L?k[0]-q[0]:0),s(r.y===K?l:r.y===M?k[1]-q[1]-l:(k[1]-q[1])/2)],pb?(g=o[0].getContext("2d"),g.restore(),g.save(),g.clearRect(0,0,6e3,6e3),h=this._calculateTip(r,q,vb),i=this._calculateTip(r,this.size,vb),o.attr(I,k[0]*vb).attr(J,k[1]*vb),o.css(I,k[0]).css(J,k[1]),this._drawCoords(g,i),g.fillStyle=e[1],g.fill(),g.translate(j[0]*vb,j[1]*vb),this._drawCoords(g,h),g.fillStyle=e[0],g.fill()):(h=this._calculateTip(r),h="m"+h[0]+","+h[1]+" l"+h[2]+","+h[3]+" "+h[4]+","+h[5]+" xe",j[2]=l&&/^(r|b)/i.test(b.string())?8===db.ie?2:1:0,o.css({coordsize:k[0]+l+" "+(k[1]+l),antialias:""+(r.string().indexOf(O)>-1),left:j[0]-j[2]*Number(f===G),top:j[1]-j[2]*Number(f===H),width:k[0]+l,height:k[1]+l}).each(function(a){var b=d(this);b[b.prop?"prop":"attr"]({coordsize:k[0]+l+" "+(k[1]+l),path:h,fillcolor:e[0],filled:!!a,stroked:!a}).toggle(!(!l&&!a)),!a&&b.html(wb("stroke",'weight="'+2*l+'px" color="'+e[1]+'" miterlimit="1000" joinstyle="miter"'))})),a.opera&&setTimeout(function(){m.tip.css({display:"inline-block",visibility:"visible"})},1),c!==E&&this.calculate(b,k)},calculate:function(a,b){if(!this.enabled)return E;var c,e,f=this,g=this.qtip.elements,h=this.element,i=this.options.offset,j=(g.tooltip.hasClass("ui-widget"),{});return a=a||this.corner,c=a.precedance,b=b||this._calculateSize(a),e=[a.x,a.y],c===G&&e.reverse(),d.each(e,function(d,e){var h,k,l;e===O?(h=c===H?L:K,j[h]="50%",j[jb+"-"+h]=-Math.round(b[c===H?0:1]/2)+i):(h=f._parseWidth(a,e,g.tooltip),k=f._parseWidth(a,e,g.content),l=f._parseRadius(a),j[e]=Math.max(-f.border,d?k:i+(l>h?l:-h))) +}),j[a[c]]-=b[c===G?0:1],h.css({margin:"",top:"",bottom:"",left:"",right:""}).css(j),j},reposition:function(a,b,d){function e(a,b,c,d,e){a===Q&&j.precedance===b&&k[d]&&j[c]!==O?j.precedance=j.precedance===G?H:G:a!==Q&&k[d]&&(j[b]=j[b]===O?k[d]>0?d:e:j[b]===d?e:d)}function f(a,b,e){j[a]===O?p[jb+"-"+b]=o[a]=g[jb+"-"+b]-k[b]:(h=g[e]!==c?[k[b],-g[b]]:[-k[b],g[b]],(o[a]=Math.max(h[0],h[1]))>h[0]&&(d[b]-=k[b],o[b]=E),p[g[e]!==c?e:b]=o[a])}if(this.enabled){var g,h,i=b.cache,j=this.corner.clone(),k=d.adjusted,l=b.options.position.adjust.method.split(" "),m=l[0],n=l[1]||l[0],o={left:E,top:E,x:0,y:0},p={};this.corner.fixed!==D&&(e(m,G,H,L,N),e(n,H,G,K,M),j.string()===i.corner.string()||i.cornerTop===k.top&&i.cornerLeft===k.left||this.update(j,E)),g=this.calculate(j),g.right!==c&&(g.left=-g.right),g.bottom!==c&&(g.top=-g.bottom),g.user=this.offset,(o.left=m===Q&&!!k.left)&&f(G,L,N),(o.top=n===Q&&!!k.top)&&f(H,K,M),this.element.css(p).toggle(!(o.x&&o.y||j.x===O&&o.y||j.y===O&&o.x)),d.left-=g.left.charAt?g.user:m!==Q||o.top||!o.left&&!o.top?g.left+this.border:0,d.top-=g.top.charAt?g.user:n!==Q||o.left||!o.left&&!o.top?g.top+this.border:0,i.cornerLeft=k.left,i.cornerTop=k.top,i.corner=j.clone()}},destroy:function(){this.qtip._unbind(this.qtip.tooltip,this._ns),this.qtip.elements.tip&&this.qtip.elements.tip.find("*").remove().end().remove()}}),ib=R.tip=function(a){return new w(a,a.options.style.tip)},ib.initialize="render",ib.sanitize=function(a){if(a.style&&"tip"in a.style){var b=a.style.tip;"object"!=typeof b&&(b=a.style.tip={corner:b}),/string|boolean/i.test(typeof b.corner)||(b.corner=D)}},B.tip={"^position.my|style.tip.(corner|mimic|border)$":function(){this.create(),this.qtip.reposition()},"^style.tip.(height|width)$":function(a){this.size=[a.width,a.height],this.update(),this.qtip.reposition()},"^content.title|style.(classes|widget)$":function(){this.update()}},d.extend(D,y.defaults,{style:{tip:{corner:D,mimic:E,width:6,height:6,border:D,offset:0}}}),R.viewport=function(c,d,e,f,g,h,i){function j(a,b,c,e,f,g,h,i,j){var k=d[f],m=v[a],t=w[a],u=c===Q,x=m===f?j:m===g?-j:-j/2,y=t===f?i:t===g?-i:-i/2,z=r[f]+s[f]-(o?0:n[f]),A=z-k,B=k+j-(h===I?p:q)-z,C=x-(v.precedance===a||m===v[b]?y:0)-(t===O?i/2:0);return u?(C=(m===f?1:-1)*x,d[f]+=A>0?A:B>0?-B:0,d[f]=Math.max(-n[f]+s[f],k-C,Math.min(Math.max(-n[f]+s[f]+(h===I?p:q),k+C),d[f],"center"===m?k-x:1e9))):(e*=c===P?2:0,A>0&&(m!==f||B>0)?(d[f]-=C+e,l.invert(a,f)):B>0&&(m!==g||A>0)&&(d[f]-=(m===O?-C:C)+e,l.invert(a,g)),d[f]B&&(d[f]=k,l=v.clone())),d[f]-k}var k,l,m,n,o,p,q,r,s,t=e.target,u=c.elements.tooltip,v=e.my,w=e.at,x=e.adjust,y=x.method.split(" "),z=y[0],A=y[1]||y[0],B=e.viewport,C=e.container,D=c.cache,F={left:0,top:0};return B.jquery&&t[0]!==a&&t[0]!==b.body&&"none"!==x.method?(n=C.offset()||F,o="static"===C.css("position"),k="fixed"===u.css("position"),p=B[0]===a?B.width():B.outerWidth(E),q=B[0]===a?B.height():B.outerHeight(E),r={left:k?0:B.scrollLeft(),top:k?0:B.scrollTop()},s=B.offset()||F,("shift"!==z||"shift"!==A)&&(l=v.clone()),F={left:"none"!==z?j(G,H,z,x.x,L,N,I,f,h):0,top:"none"!==A?j(H,G,A,x.y,K,M,J,g,i):0},l&&D.lastClass!==(m=S+"-pos-"+l.abbrev())&&u.removeClass(c.cache.lastClass).addClass(c.cache.lastClass=m),F):F},R.polys={polygon:function(a,b){var c,d,e,f={width:0,height:0,position:{top:1e10,right:0,bottom:0,left:1e10},adjustable:E},g=0,h=[],i=1,j=1,k=0,l=0;for(g=a.length;g--;)c=[parseInt(a[--g],10),parseInt(a[g+1],10)],c[0]>f.position.right&&(f.position.right=c[0]),c[0]f.position.bottom&&(f.position.bottom=c[1]),c[1]0&&e>0&&i>0&&j>0;)for(d=Math.floor(d/2),e=Math.floor(e/2),b.x===L?i=d:b.x===N?i=f.width-d:i+=Math.floor(d/2),b.y===K?j=e:b.y===M?j=f.height-e:j+=Math.floor(e/2),g=h.length;g--&&!(h.length<2);)k=h[g][0]-f.position.left,l=h[g][1]-f.position.top,(b.x===L&&k>=i||b.x===N&&i>=k||b.x===O&&(i>k||k>f.width-i)||b.y===K&&l>=j||b.y===M&&j>=l||b.y===O&&(j>l||l>f.height-j))&&h.splice(g,1);f.position={left:h[0][0],top:h[0][1]}}return f},rect:function(a,b,c,d){return{width:Math.abs(c-a),height:Math.abs(d-b),position:{left:Math.min(a,c),top:Math.min(b,d)}}},_angles:{tc:1.5,tr:7/4,tl:5/4,bc:.5,br:.25,bl:.75,rc:2,lc:1,c:0},ellipse:function(a,b,c,d,e){var f=R.polys._angles[e.abbrev()],g=0===f?0:c*Math.cos(f*Math.PI),h=d*Math.sin(f*Math.PI);return{width:2*c-Math.abs(g),height:2*d-Math.abs(h),position:{left:a+g,top:b+h},adjustable:E}},circle:function(a,b,c,d){return R.polys.ellipse(a,b,c,c,d)}},R.svg=function(a,c,e){for(var f,g,h,i,j,k,l,m,n,o,p,q=d(b),r=c[0],s=d(r.ownerSVGElement),t=1,u=1,v=!0;!r.getBBox;)r=r.parentNode;if(!r.getBBox||!r.parentNode)return E;f=s.attr("width")||s.width()||parseInt(s.css("width"),10),g=s.attr("height")||s.height()||parseInt(s.css("height"),10);var w=(parseInt(c.css("stroke-width"),10)||0)/2;switch(w&&(t+=w/f,u+=w/g),r.nodeName){case"ellipse":case"circle":o=R.polys.ellipse(r.cx.baseVal.value,r.cy.baseVal.value,(r.rx||r.r).baseVal.value+w,(r.ry||r.r).baseVal.value+w,e);break;case"line":case"polygon":case"polyline":for(n=r.points||[{x:r.x1.baseVal.value,y:r.y1.baseVal.value},{x:r.x2.baseVal.value,y:r.y2.baseVal.value}],o=[],m=-1,k=n.numberOfItems||n.length;++mparseInt(h[0].style.zIndex,10),b||e.closest(W)[0]===h[0]||c(e),g=a.target===k[k.length-1]}}var f,g,h,i,j=this,k={};d.extend(j,{init:function(){return i=j.elem=d("
",{id:"qtip-overlay",html:"
",mousedown:function(){return E}}).hide(),d(b.body).bind("focusin"+Ab,e),d(b).bind("keydown"+Ab,function(a){f&&f.options.show.modal.escape&&27===a.keyCode&&f.hide(a)}),i.bind("click"+Ab,function(a){f&&f.options.show.modal.blur&&f.hide(a)}),j},update:function(b){f=b,k=b.options.show.modal.stealfocus!==E?b.tooltip.find("*").filter(function(){return a(this)}):[]},toggle:function(a,e,g){var k=(d(b.body),a.tooltip),l=a.options.show.modal,m=l.effect,n=e?"show":"hide",o=i.is(":visible"),p=d(Ab).filter(":visible:not(:animated)").not(k);return j.update(a),e&&l.stealfocus!==E&&c(d(":focus")),i.toggleClass("blurs",l.blur),e&&i.appendTo(b.body),i.is(":animated")&&o===e&&h!==E||!e&&p.length?j:(i.stop(D,E),d.isFunction(m)?m.call(i,e):m===E?i[n]():i.fadeTo(parseInt(g,10)||90,e?1:0,function(){e||i.hide()}),e||i.queue(function(a){i.css({left:"",top:""}),d(Ab).length||i.detach(),a()}),h=e,f.destroyed&&(f=F),j)}}),j.init()},yb=new yb,d.extend(x.prototype,{init:function(a){var b=a.tooltip;return this.options.on?(a.elements.overlay=yb.elem,b.addClass(zb).css("z-index",y.modal_zindex+d(Ab).length),a._bind(b,["tooltipshow","tooltiphide"],function(a,c,e){var f=a.originalEvent;if(a.target===b[0])if(f&&"tooltiphide"===a.type&&/mouse(leave|enter)/.test(f.type)&&d(f.relatedTarget).closest(yb.elem[0]).length)try{a.preventDefault()}catch(g){}else(!f||f&&"tooltipsolo"!==f.type)&&this.toggle(a,"tooltipshow"===a.type,e)},this._ns,this),a._bind(b,"tooltipfocus",function(a,c){if(!a.isDefaultPrevented()&&a.target===b[0]){var e=d(Ab),f=y.modal_zindex+e.length,g=parseInt(b[0].style.zIndex,10);yb.elem[0].style.zIndex=f-1,e.each(function(){this.style.zIndex>g&&(this.style.zIndex-=1)}),e.filter("."+$).qtip("blur",a.originalEvent),b.addClass($)[0].style.zIndex=f,yb.update(c);try{a.preventDefault()}catch(h){}}},this._ns,this),a._bind(b,"tooltiphide",function(a){a.target===b[0]&&d(Ab).filter(":visible").not(b).last().qtip("focus",a)},this._ns,this),void 0):this},toggle:function(a,b,c){return a&&a.isDefaultPrevented()?this:(yb.toggle(this.qtip,!!b,c),void 0)},destroy:function(){this.qtip.tooltip.removeClass(zb),this.qtip._unbind(this.qtip.tooltip,this._ns),yb.toggle(this.qtip,E),delete this.qtip.elements.overlay}}),xb=R.modal=function(a){return new x(a,a.options.show.modal)},xb.sanitize=function(a){a.show&&("object"!=typeof a.show.modal?a.show.modal={on:!!a.show.modal}:"undefined"==typeof a.show.modal.on&&(a.show.modal.on=D))},y.modal_zindex=y.zindex-200,xb.initialize="render",B.modal={"^show.modal.(on|blur)$":function(){this.destroy(),this.init(),this.qtip.elems.overlay.toggle(this.qtip.tooltip[0].offsetWidth>0)}},d.extend(D,y.defaults,{show:{modal:{on:E,effect:D,blur:D,stealfocus:D,escape:D}}})})}(window,document); +//# sourceMappingURL=http://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.0//var/www/qtip2/build/tmp/tmp-11954vgjofvk/jquery.qtip.min.map \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/display/package.json b/snow-flowable/src/main/resources/static/display/package.json new file mode 100644 index 0000000..29c70e5 --- /dev/null +++ b/snow-flowable/src/main/resources/static/display/package.json @@ -0,0 +1,37 @@ +{ + "name": "displaymodel", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": { + "grunt": "0.4.2", + "grunt-autoprefixer": "0.4.0", + "grunt-bower-install": "0.7.0", + "grunt-concurrent": "0.4.1", + "grunt-contrib-clean": "0.5.0", + "grunt-contrib-coffee": "0.7.0", + "grunt-contrib-compass": "0.6.0", + "grunt-contrib-concat": "0.3.0", + "grunt-contrib-connect": "0.5.0", + "grunt-contrib-copy": "0.4.1", + "grunt-contrib-cssmin": "0.7.0", + "grunt-contrib-htmlmin": "0.1.3", + "grunt-contrib-imagemin": "0.3.0", + "grunt-contrib-jshint": "0.7.1", + "grunt-contrib-uglify": "0.2.0", + "grunt-contrib-watch": "0.5.2", + "grunt-google-cdn": "0.2.0", + "grunt-newer": "0.5.4", + "grunt-ng-annotate": "0.5.0", + "grunt-rev": "0.1.0", + "grunt-svgmin": "0.2.0", + "grunt-usemin": "2.0.0", + "jshint-stylish": "0.1.3", + "load-grunt-tasks": "0.2.0", + "time-grunt": "0.2.1", + "grunt-text-replace": "0.3.11", + "grunt-contrib-rename": "0.0.3" + }, + "engines": { + "node": ">=0.8.0" + } +} diff --git a/snow-flowable/src/main/resources/static/display/raphael.min.js b/snow-flowable/src/main/resources/static/display/raphael.min.js new file mode 100644 index 0000000..a901777 --- /dev/null +++ b/snow-flowable/src/main/resources/static/display/raphael.min.js @@ -0,0 +1 @@ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Raphael=e():t.Raphael=e()}(window,function(){return function(t){var e={};function r(i){if(e[i])return e[i].exports;var n=e[i]={i:i,l:!1,exports:{}};return t[i].call(n.exports,n,n.exports,r),n.l=!0,n.exports}return r.m=t,r.c=e,r.d=function(t,e,i){r.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:i})},r.r=function(t){Object.defineProperty(t,"__esModule",{value:!0})},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=4)}([function(t,e,r){var i,n;i=[r(3)],void 0===(n=function(t){function e(i){if(e.is(i,"function"))return r?i():t.on("raphael.DOMload",i);if(e.is(i,T))return e._engine.create[c](e,i.splice(0,3+e.is(i[0],A))).add(i);var n=Array.prototype.slice.call(arguments,0);if(e.is(n[n.length-1],"function")){var a=n.pop();return r?a.call(e._engine.create[c](e,n)):t.on("raphael.DOMload",function(){a.call(e._engine.create[c](e,n))})}return e._engine.create[c](e,arguments)}e.version="2.2.0",e.eve=t;var r,i,n=/[, ]+/,a={circle:1,rect:1,path:1,ellipse:1,text:1,image:1},s=/\{(\d+)\}/g,o="hasOwnProperty",l={doc:document,win:window},h={was:Object.prototype[o].call(l.win,"Raphael"),is:l.win.Raphael},u=function(){this.ca=this.customAttributes={}},c="apply",f="concat",p="ontouchstart"in l.win||l.win.DocumentTouch&&l.doc instanceof DocumentTouch,d="",g=" ",x=String,v="split",y="click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel"[v](g),m={mousedown:"touchstart",mousemove:"touchmove",mouseup:"touchend"},b=x.prototype.toLowerCase,_=Math,w=_.max,k=_.min,B=_.abs,C=_.pow,S=_.PI,A="number",T="array",M=Object.prototype.toString,E=(e._ISURL=/^url\(['"]?(.+?)['"]?\)$/i,/^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\))\s*$/i),N={NaN:1,Infinity:1,"-Infinity":1},L=/^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/,P=_.round,z=parseFloat,F=parseInt,R=x.prototype.toUpperCase,j=e._availableAttrs={"arrow-end":"none","arrow-start":"none",blur:0,"clip-rect":"0 0 1e9 1e9",cursor:"default",cx:0,cy:0,fill:"#fff","fill-opacity":1,font:'10px "Arial"',"font-family":'"Arial"',"font-size":"10","font-style":"normal","font-weight":400,gradient:0,height:0,href:"http://raphaeljs.com/","letter-spacing":0,opacity:1,path:"M0,0",r:0,rx:0,ry:0,src:"",stroke:"#000","stroke-dasharray":"","stroke-linecap":"butt","stroke-linejoin":"butt","stroke-miterlimit":0,"stroke-opacity":1,"stroke-width":1,target:"_blank","text-anchor":"middle",title:"Raphael",transform:"",width:0,x:0,y:0,class:""},I=e._availableAnimAttrs={blur:A,"clip-rect":"csv",cx:A,cy:A,fill:"colour","fill-opacity":A,"font-size":A,height:A,opacity:A,path:"path",r:A,rx:A,ry:A,stroke:"colour","stroke-opacity":A,"stroke-width":A,transform:"transform",width:A,x:A,y:A},D=/[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/,q={hs:1,rg:1},O=/,?([achlmqrstvxz]),?/gi,V=/([achlmrqstvz])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/gi,Y=/([rstm])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/gi,W=/(-?\d*\.?\d*(?:e[\-+]?\d+)?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/gi,G=(e._radial_gradient=/^r(?:\(([^,]+?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*([^\)]+?)\))?/,{}),H=function(t,e){return z(t)-z(e)},X=function(t){return t},U=e._rectPath=function(t,e,r,i,n){return n?[["M",t+n,e],["l",r-2*n,0],["a",n,n,0,0,1,n,n],["l",0,i-2*n],["a",n,n,0,0,1,-n,n],["l",2*n-r,0],["a",n,n,0,0,1,-n,-n],["l",0,2*n-i],["a",n,n,0,0,1,n,-n],["z"]]:[["M",t,e],["l",r,0],["l",0,i],["l",-r,0],["z"]]},$=function(t,e,r,i){return null==i&&(i=r),[["M",t,e],["m",0,-i],["a",r,i,0,1,1,0,2*i],["a",r,i,0,1,1,0,-2*i],["z"]]},Z=e._getPath={path:function(t){return t.attr("path")},circle:function(t){var e=t.attrs;return $(e.cx,e.cy,e.r)},ellipse:function(t){var e=t.attrs;return $(e.cx,e.cy,e.rx,e.ry)},rect:function(t){var e=t.attrs;return U(e.x,e.y,e.width,e.height,e.r)},image:function(t){var e=t.attrs;return U(e.x,e.y,e.width,e.height)},text:function(t){var e=t._getBBox();return U(e.x,e.y,e.width,e.height)},set:function(t){var e=t._getBBox();return U(e.x,e.y,e.width,e.height)}},Q=e.mapPath=function(t,e){if(!e)return t;var r,i,n,a,s,o,l;for(n=0,s=(t=At(t)).length;n',(J=K.firstChild).style.behavior="url(#default#VML)",!J||"object"!=typeof J.adj)return e.type=d;K=null}function tt(t){if("function"==typeof t||Object(t)!==t)return t;var e=new t.constructor;for(var r in t)t[o](r)&&(e[r]=tt(t[r]));return e}e.svg=!(e.vml="VML"==e.type),e._Paper=u,e.fn=i=u.prototype=e.prototype,e._id=0,e.is=function(t,e){return"finite"==(e=b.call(e))?!N[o](+t):"array"==e?t instanceof Array:"null"==e&&null===t||e==typeof t&&null!==t||"object"==e&&t===Object(t)||"array"==e&&Array.isArray&&Array.isArray(t)||M.call(t).slice(8,-1).toLowerCase()==e},e.angle=function(t,r,i,n,a,s){if(null==a){var o=t-i,l=r-n;return o||l?(180+180*_.atan2(-l,-o)/S+360)%360:0}return e.angle(t,r,a,s)-e.angle(i,n,a,s)},e.rad=function(t){return t%360*S/180},e.deg=function(t){return Math.round(180*t/S%360*1e3)/1e3},e.snapTo=function(t,r,i){if(i=e.is(i,"finite")?i:10,e.is(t,T)){for(var n=t.length;n--;)if(B(t[n]-r)<=i)return t[n]}else{var a=r%(t=+t);if(at-i)return r-a+t}return r};var et,rt;e.createUUID=(et=/[xy]/g,rt=function(t){var e=16*_.random()|0;return("x"==t?e:3&e|8).toString(16)},function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(et,rt).toUpperCase()});e.setWindow=function(r){t("raphael.setWindow",e,l.win,r),l.win=r,l.doc=l.win.document,e._engine.initWin&&e._engine.initWin(l.win)};var it=function(t){if(e.vml){var r,i=/^\s+|\s+$/g;try{var n=new ActiveXObject("htmlfile");n.write(""),n.close(),r=n.body}catch(t){r=createPopup().document.body}var a=r.createTextRange();it=ht(function(t){try{r.style.color=x(t).replace(i,d);var e=a.queryCommandValue("ForeColor");return"#"+("000000"+(e=(255&e)<<16|65280&e|(16711680&e)>>>16).toString(16)).slice(-6)}catch(t){return"none"}})}else{var s=l.doc.createElement("i");s.title="Raphaël Colour Picker",s.style.display="none",l.doc.body.appendChild(s),it=ht(function(t){return s.style.color=t,l.doc.defaultView.getComputedStyle(s,d).getPropertyValue("color")})}return it(t)},nt=function(){return"hsb("+[this.h,this.s,this.b]+")"},at=function(){return"hsl("+[this.h,this.s,this.l]+")"},st=function(){return this.hex},ot=function(t,r,i){if(null==r&&e.is(t,"object")&&"r"in t&&"g"in t&&"b"in t&&(i=t.b,r=t.g,t=t.r),null==r&&e.is(t,"string")){var n=e.getRGB(t);t=n.r,r=n.g,i=n.b}return(t>1||r>1||i>1)&&(t/=255,r/=255,i/=255),[t,r,i]},lt=function(t,r,i,n){var a={r:t*=255,g:r*=255,b:i*=255,hex:e.rgb(t,r,i),toString:st};return e.is(n,"finite")&&(a.opacity=n),a};function ht(t,e,r){return function i(){var n=Array.prototype.slice.call(arguments,0),a=n.join("␀"),s=i.cache=i.cache||{},l=i.count=i.count||[];return s[o](a)?(function(t,e){for(var r=0,i=t.length;r=1e3&&delete s[l.shift()],l.push(a),s[a]=t[c](e,n),r?r(s[a]):s[a])}}e.color=function(t){var r;return e.is(t,"object")&&"h"in t&&"s"in t&&"b"in t?(r=e.hsb2rgb(t),t.r=r.r,t.g=r.g,t.b=r.b,t.hex=r.hex):e.is(t,"object")&&"h"in t&&"s"in t&&"l"in t?(r=e.hsl2rgb(t),t.r=r.r,t.g=r.g,t.b=r.b,t.hex=r.hex):(e.is(t,"string")&&(t=e.getRGB(t)),e.is(t,"object")&&"r"in t&&"g"in t&&"b"in t?(r=e.rgb2hsl(t),t.h=r.h,t.s=r.s,t.l=r.l,r=e.rgb2hsb(t),t.v=r.b):(t={hex:"none"}).r=t.g=t.b=t.h=t.s=t.v=t.l=-1),t.toString=st,t},e.hsb2rgb=function(t,e,r,i){var n,a,s,o,l;return this.is(t,"object")&&"h"in t&&"s"in t&&"b"in t&&(r=t.b,e=t.s,i=t.o,t=t.h),o=(l=r*e)*(1-B((t=(t*=360)%360/60)%2-1)),n=a=s=r-l,lt(n+=[l,o,0,0,o,l][t=~~t],a+=[o,l,l,o,0,0][t],s+=[0,0,o,l,l,o][t],i)},e.hsl2rgb=function(t,e,r,i){var n,a,s,o,l;return this.is(t,"object")&&"h"in t&&"s"in t&&"l"in t&&(r=t.l,e=t.s,t=t.h),(t>1||e>1||r>1)&&(t/=360,e/=100,r/=100),t=(t*=360)%360/60,o=(l=2*e*(r<.5?r:1-r))*(1-B(t%2-1)),n=a=s=r-l/2,lt(n+=[l,o,0,0,o,l][t=~~t],a+=[o,l,l,o,0,0][t],s+=[0,0,o,l,l,o][t],i)},e.rgb2hsb=function(t,e,r){var i,n;return t=(r=ot(t,e,r))[0],e=r[1],r=r[2],{h:((0==(n=(i=w(t,e,r))-k(t,e,r))?null:i==t?(e-r)/n:i==e?(r-t)/n+2:(t-e)/n+4)+360)%6*60/360,s:0==n?0:n/i,b:i,toString:nt}},e.rgb2hsl=function(t,e,r){var i,n,a,s;return t=(r=ot(t,e,r))[0],e=r[1],r=r[2],i=((n=w(t,e,r))+(a=k(t,e,r)))/2,{h:((0==(s=n-a)?null:n==t?(e-r)/s:n==e?(r-t)/s+2:(t-e)/s+4)+360)%6*60/360,s:0==s?0:i<.5?s/(2*i):s/(2-2*i),l:i,toString:at}},e._path2string=function(){return this.join(",").replace(O,"$1")};e._preload=function(t,e){var r=l.doc.createElement("img");r.style.cssText="position:absolute;left:-9999em;top:-9999em",r.onload=function(){e.call(this),this.onload=null,l.doc.body.removeChild(this)},r.onerror=function(){l.doc.body.removeChild(this)},l.doc.body.appendChild(r),r.src=t};function ut(){return this.hex}function ct(t,e){for(var r=[],i=0,n=t.length;n-2*!e>i;i+=2){var a=[{x:+t[i-2],y:+t[i-1]},{x:+t[i],y:+t[i+1]},{x:+t[i+2],y:+t[i+3]},{x:+t[i+4],y:+t[i+5]}];e?i?n-4==i?a[3]={x:+t[0],y:+t[1]}:n-2==i&&(a[2]={x:+t[0],y:+t[1]},a[3]={x:+t[2],y:+t[3]}):a[0]={x:+t[n-2],y:+t[n-1]}:n-4==i?a[3]=a[2]:i||(a[0]={x:+t[i],y:+t[i+1]}),r.push(["C",(-a[0].x+6*a[1].x+a[2].x)/6,(-a[0].y+6*a[1].y+a[2].y)/6,(a[1].x+6*a[2].x-a[3].x)/6,(a[1].y+6*a[2].y-a[3].y)/6,a[2].x,a[2].y])}return r}e.getRGB=ht(function(t){if(!t||(t=x(t)).indexOf("-")+1)return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:ut};if("none"==t)return{r:-1,g:-1,b:-1,hex:"none",toString:ut};!q[o](t.toLowerCase().substring(0,2))&&"#"!=t.charAt()&&(t=it(t));var r,i,n,a,s,l,h=t.match(E);return h?(h[2]&&(n=F(h[2].substring(5),16),i=F(h[2].substring(3,5),16),r=F(h[2].substring(1,3),16)),h[3]&&(n=F((s=h[3].charAt(3))+s,16),i=F((s=h[3].charAt(2))+s,16),r=F((s=h[3].charAt(1))+s,16)),h[4]&&(l=h[4][v](D),r=z(l[0]),"%"==l[0].slice(-1)&&(r*=2.55),i=z(l[1]),"%"==l[1].slice(-1)&&(i*=2.55),n=z(l[2]),"%"==l[2].slice(-1)&&(n*=2.55),"rgba"==h[1].toLowerCase().slice(0,4)&&(a=z(l[3])),l[3]&&"%"==l[3].slice(-1)&&(a/=100)),h[5]?(l=h[5][v](D),r=z(l[0]),"%"==l[0].slice(-1)&&(r*=2.55),i=z(l[1]),"%"==l[1].slice(-1)&&(i*=2.55),n=z(l[2]),"%"==l[2].slice(-1)&&(n*=2.55),("deg"==l[0].slice(-3)||"°"==l[0].slice(-1))&&(r/=360),"hsba"==h[1].toLowerCase().slice(0,4)&&(a=z(l[3])),l[3]&&"%"==l[3].slice(-1)&&(a/=100),e.hsb2rgb(r,i,n,a)):h[6]?(l=h[6][v](D),r=z(l[0]),"%"==l[0].slice(-1)&&(r*=2.55),i=z(l[1]),"%"==l[1].slice(-1)&&(i*=2.55),n=z(l[2]),"%"==l[2].slice(-1)&&(n*=2.55),("deg"==l[0].slice(-3)||"°"==l[0].slice(-1))&&(r/=360),"hsla"==h[1].toLowerCase().slice(0,4)&&(a=z(l[3])),l[3]&&"%"==l[3].slice(-1)&&(a/=100),e.hsl2rgb(r,i,n,a)):((h={r:r,g:i,b:n,toString:ut}).hex="#"+(16777216|n|i<<8|r<<16).toString(16).slice(1),e.is(a,"finite")&&(h.opacity=a),h)):{r:-1,g:-1,b:-1,hex:"none",error:1,toString:ut}},e),e.hsb=ht(function(t,r,i){return e.hsb2rgb(t,r,i).hex}),e.hsl=ht(function(t,r,i){return e.hsl2rgb(t,r,i).hex}),e.rgb=ht(function(t,e,r){function i(t){return t+.5|0}return"#"+(16777216|i(r)|i(e)<<8|i(t)<<16).toString(16).slice(1)}),e.getColor=function(t){var e=this.getColor.start=this.getColor.start||{h:0,s:1,b:t||.75},r=this.hsb2rgb(e.h,e.s,e.b);return e.h+=.075,e.h>1&&(e.h=0,e.s-=.2,e.s<=0&&(this.getColor.start={h:0,s:1,b:e.b})),r.hex},e.getColor.reset=function(){delete this.start},e.parsePathString=function(t){if(!t)return null;var r=ft(t);if(r.arr)return mt(r.arr);var i={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0},n=[];return e.is(t,T)&&e.is(t[0],T)&&(n=mt(t)),n.length||x(t).replace(V,function(t,e,r){var a=[],s=e.toLowerCase();if(r.replace(W,function(t,e){e&&a.push(+e)}),"m"==s&&a.length>2&&(n.push([e][f](a.splice(0,2))),s="l",e="m"==e?"l":"L"),"r"==s)n.push([e][f](a));else for(;a.length>=i[s]&&(n.push([e][f](a.splice(0,i[s]))),i[s]););}),n.toString=e._path2string,r.arr=mt(n),n},e.parseTransformString=ht(function(t){if(!t)return null;var r=[];return e.is(t,T)&&e.is(t[0],T)&&(r=mt(t)),r.length||x(t).replace(Y,function(t,e,i){var n=[];b.call(e);i.replace(W,function(t,e){e&&n.push(+e)}),r.push([e][f](n))}),r.toString=e._path2string,r});var ft=function(t){var e=ft.ps=ft.ps||{};return e[t]?e[t].sleep=100:e[t]={sleep:100},setTimeout(function(){for(var r in e)e[o](r)&&r!=t&&(e[r].sleep--,!e[r].sleep&&delete e[r])}),e[t]};function pt(t,e,r,i,n){return t*(t*(-3*e+9*r-9*i+3*n)+6*e-12*r+6*i)-3*e+3*r}function dt(t,e,r,i,n,a,s,o,l){null==l&&(l=1);for(var h=(l=l>1?1:l<0?0:l)/2,u=[-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816],c=[.2491,.2491,.2335,.2335,.2032,.2032,.1601,.1601,.1069,.1069,.0472,.0472],f=0,p=0;p<12;p++){var d=h*u[p]+h,g=pt(d,t,r,n,s),x=pt(d,e,i,a,o),v=g*g+x*x;f+=c[p]*_.sqrt(v)}return h*f}function gt(t,e,r,i,n,a,s,o){if(!(w(t,r)w(n,s)||w(e,i)w(a,o))){var l=(t-r)*(a-o)-(e-i)*(n-s);if(l){var h=((t*i-e*r)*(n-s)-(t-r)*(n*o-a*s))/l,u=((t*i-e*r)*(a-o)-(e-i)*(n*o-a*s))/l,c=+h.toFixed(2),f=+u.toFixed(2);if(!(c<+k(t,r).toFixed(2)||c>+w(t,r).toFixed(2)||c<+k(n,s).toFixed(2)||c>+w(n,s).toFixed(2)||f<+k(e,i).toFixed(2)||f>+w(e,i).toFixed(2)||f<+k(a,o).toFixed(2)||f>+w(a,o).toFixed(2)))return{x:h,y:u}}}}function xt(t,r,i){var n=e.bezierBBox(t),a=e.bezierBBox(r);if(!e.isBBoxIntersect(n,a))return i?0:[];for(var s=dt.apply(0,t),o=dt.apply(0,r),l=w(~~(s/5),1),h=w(~~(o/5),1),u=[],c=[],f={},p=i?0:[],d=0;d=0&&A<=1.001&&T>=0&&T<=1.001&&(i?p++:p.push({x:S.x,y:S.y,t1:k(A,1),t2:k(T,1)}))}}return p}function vt(t,r,i){t=e._path2curve(t),r=e._path2curve(r);for(var n,a,s,o,l,h,u,c,f,p,d=i?0:[],g=0,x=t.length;gy||v=t.x&&e<=t.x2&&r>=t.y&&r<=t.y2},e.isBBoxIntersect=function(t,r){var i=e.isPointInsideBBox;return i(r,t.x,t.y)||i(r,t.x2,t.y)||i(r,t.x,t.y2)||i(r,t.x2,t.y2)||i(t,r.x,r.y)||i(t,r.x2,r.y)||i(t,r.x,r.y2)||i(t,r.x2,r.y2)||(t.xr.x||r.xt.x)&&(t.yr.y||r.yt.y)},e.pathIntersection=function(t,e){return vt(t,e)},e.pathIntersectionNumber=function(t,e){return vt(t,e,1)},e.isPointInsidePath=function(t,r,i){var n=e.pathBBox(t);return e.isPointInsideBBox(n,r,i)&&vt(t,[["M",r,i],["H",n.x2+10]],1)%2==1},e._removedFactory=function(e){return function(){t("raphael.log",null,"Raphaël: you are calling to method “"+e+"” of removed object",e)}};var yt=e.pathBBox=function(t){var e=ft(t);if(e.bbox)return tt(e.bbox);if(!t)return{x:0,y:0,width:0,height:0,x2:0,y2:0};for(var r,i=0,n=0,a=[],s=[],o=0,l=(t=At(t)).length;o1&&(r*=m=_.sqrt(m),i*=m);var b=r*r,w=i*i,k=(a==s?-1:1)*_.sqrt(B((b*w-b*y*y-w*x*x)/(b*y*y+w*x*x))),C=k*r*y/i+(t+o)/2,A=k*-i*x/r+(e+l)/2,T=_.asin(((e-A)/i).toFixed(9)),M=_.asin(((l-A)/i).toFixed(9));T=tM&&(T-=2*S),!s&&M>T&&(M-=2*S)}var E=M-T;if(B(E)>c){var N=M,L=o,P=l;M=T+c*(s&&M>T?1:-1),o=C+r*_.cos(M),l=A+i*_.sin(M),d=Bt(o,l,r,i,n,0,s,L,P,[M,N,C,A])}E=M-T;var z=_.cos(T),F=_.sin(T),R=_.cos(M),j=_.sin(M),I=_.tan(E/4),D=4/3*r*I,q=4/3*i*I,O=[t,e],V=[t+D*F,e-q*z],Y=[o+D*j,l-q*R],W=[o,l];if(V[0]=2*O[0]-V[0],V[1]=2*O[1]-V[1],h)return[V,Y,W][f](d);for(var G=[],H=0,X=(d=[V,Y,W][f](d).join()[v](",")).length;H"1e12"&&(p=.5),B(d)>"1e12"&&(d=.5),p>0&&p<1&&(l=Ct(t,e,r,i,n,a,s,o,p),x.push(l.x),g.push(l.y)),d>0&&d<1&&(l=Ct(t,e,r,i,n,a,s,o,d),x.push(l.x),g.push(l.y)),h=a-2*i+e-(o-2*a+i),f=e-i,p=(-(u=2*(i-e)-2*(a-i))+_.sqrt(u*u-4*h*f))/2/h,d=(-u-_.sqrt(u*u-4*h*f))/2/h,B(p)>"1e12"&&(p=.5),B(d)>"1e12"&&(d=.5),p>0&&p<1&&(l=Ct(t,e,r,i,n,a,s,o,p),x.push(l.x),g.push(l.y)),d>0&&d<1&&(l=Ct(t,e,r,i,n,a,s,o,d),x.push(l.x),g.push(l.y)),{min:{x:k[c](0,x),y:k[c](0,g)},max:{x:w[c](0,x),y:w[c](0,g)}}}),At=e._path2curve=ht(function(t,e){var r=!e&&ft(t);if(!e&&r.curve)return mt(r.curve);for(var i=_t(t),n=e&&_t(e),a={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},s={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},o=function(t,e,r){var i,n;if(!t)return["C",e.x,e.y,e.x,e.y,e.x,e.y];switch(!(t[0]in{T:1,Q:1})&&(e.qx=e.qy=null),t[0]){case"M":e.X=t[1],e.Y=t[2];break;case"A":t=["C"][f](Bt[c](0,[e.x,e.y][f](t.slice(1))));break;case"S":"C"==r||"S"==r?(i=2*e.x-e.bx,n=2*e.y-e.by):(i=e.x,n=e.y),t=["C",i,n][f](t.slice(1));break;case"T":"Q"==r||"T"==r?(e.qx=2*e.x-e.qx,e.qy=2*e.y-e.qy):(e.qx=e.x,e.qy=e.y),t=["C"][f](kt(e.x,e.y,e.qx,e.qy,t[1],t[2]));break;case"Q":e.qx=t[1],e.qy=t[2],t=["C"][f](kt(e.x,e.y,t[1],t[2],t[3],t[4]));break;case"L":t=["C"][f](wt(e.x,e.y,t[1],t[2]));break;case"H":t=["C"][f](wt(e.x,e.y,t[1],e.y));break;case"V":t=["C"][f](wt(e.x,e.y,e.x,t[1]));break;case"Z":t=["C"][f](wt(e.x,e.y,e.X,e.Y))}return t},l=function(t,e){if(t[e].length>7){t[e].shift();for(var r=t[e];r.length;)u[e]="A",n&&(p[e]="A"),t.splice(e++,0,["C"][f](r.splice(0,6)));t.splice(e,1),v=w(i.length,n&&n.length||0)}},h=function(t,e,r,a,s){t&&e&&"M"==t[s][0]&&"M"!=e[s][0]&&(e.splice(s,0,["M",a.x,a.y]),r.bx=0,r.by=0,r.x=t[s][1],r.y=t[s][2],v=w(i.length,n&&n.length||0))},u=[],p=[],d="",g="",x=0,v=w(i.length,n&&n.length||0);x.01;)u/=2,h=dt(t,e,r,i,n,a,s,o,c+=(hn){if(r&&!f.start){if(c+=["C"+(u=Xt(s,o,l[1],l[2],l[3],l[4],l[5],l[6],n-p)).start.x,u.start.y,u.m.x,u.m.y,u.x,u.y],a)return c;f.start=c,c=["M"+u.x,u.y+"C"+u.n.x,u.n.y,u.end.x,u.end.y,l[5],l[6]].join(),p+=h,s=+l[5],o=+l[6];continue}if(!t&&!r)return{x:(u=Xt(s,o,l[1],l[2],l[3],l[4],l[5],l[6],n-p)).x,y:u.y,alpha:u.alpha}}p+=h,s=+l[5],o=+l[6]}c+=l.shift()+l}return f.end=c,(u=t?p:r?f:e.findDotsAtSegment(s,o,l[0],l[1],l[2],l[3],l[4],l[5],1)).alpha&&(u={x:u.x,y:u.y,alpha:u.alpha}),u}},$t=Ut(1),Zt=Ut(),Qt=Ut(0,1);e.getTotalLength=$t,e.getPointAtLength=Zt,e.getSubpath=function(t,e,r){if(this.getTotalLength(t)-r<1e-6)return Qt(t,e).end;var i=Qt(t,r,1);return e?Qt(i,e).end:i},Yt.getTotalLength=function(){var t=this.getPath();if(t)return this.node.getTotalLength?this.node.getTotalLength():$t(t)},Yt.getPointAtLength=function(t){var e=this.getPath();if(e)return Zt(e,t)},Yt.getPath=function(){var t,r=e._getPath[this.type];if("text"!=this.type&&"set"!=this.type)return r&&(t=r(this)),t},Yt.getSubpath=function(t,r){var i=this.getPath();if(i)return e.getSubpath(i,t,r)};var Jt=e.easing_formulas={linear:function(t){return t},"<":function(t){return C(t,1.7)},">":function(t){return C(t,.48)},"<>":function(t){var e=.48-t/1.04,r=_.sqrt(.1734+e*e),i=r-e,n=-r-e,a=C(B(i),1/3)*(i<0?-1:1)+C(B(n),1/3)*(n<0?-1:1)+.5;return 3*(1-a)*a*a+a*a*a},backIn:function(t){var e=1.70158;return t*t*((e+1)*t-e)},backOut:function(t){var e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},elastic:function(t){return t==!!t?t:C(2,-10*t)*_.sin(2*S*(t-.075)/.3)+1},bounce:function(t){var e=7.5625,r=2.75;return t<1/r?e*t*t:t<2/r?e*(t-=1.5/r)*t+.75:t<2.5/r?e*(t-=2.25/r)*t+.9375:e*(t-=2.625/r)*t+.984375}};Jt.easeIn=Jt["ease-in"]=Jt["<"],Jt.easeOut=Jt["ease-out"]=Jt[">"],Jt.easeInOut=Jt["ease-in-out"]=Jt["<>"],Jt["back-in"]=Jt.backIn,Jt["back-out"]=Jt.backOut;var Kt=[],te=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){setTimeout(t,16)},ee=function(){for(var r=+new Date,i=0;i1&&!n.next){for(s in d)d[o](s)&&(y[s]=n.totalOrigin[s]);n.el.attr(y),ae(n.anim,n.el,n.anim.percents[0],null,n.totalOrigin,n.repeat-1)}n.next&&!n.stop&&ae(n.anim,n.el,n.next,null,n.totalOrigin,n.repeat)}}}Kt.length&&te(ee)},re=function(t){return t>255?255:t<0?0:t};function ie(t,e,r,i,n,a){var s=3*e,o=3*(i-e)-s,l=1-s-o,h=3*r,u=3*(n-r)-h,c=1-h-u;function f(t){return((l*t+o)*t+s)*t}return function(t,e){var r=function(t,e){var r,i,n,a,h,u;for(n=t,u=0;u<8;u++){if(a=f(n)-t,B(a)i)return i;for(;ra?r=n:i=n,n=(i-r)/2+r}return n}(t,e);return((c*r+u)*r+h)*r}(t,1/(200*a))}function ne(t,e){var r=[],i={};if(this.ms=e,this.times=1,t){for(var n in t)t[o](n)&&(i[z(n)]=t[n],r.push(z(n)));r.sort(H)}this.anim=i,this.top=r[r.length-1],this.percents=r}function ae(r,i,a,s,l,h){a=z(a);var u,c,p,d,g,y,m=r.ms,b={},_={},w={};if(s)for(B=0,C=Kt.length;Bs*r.top){a=r.percents[B],g=r.percents[B-1]||0,m=m/r.top*(a-g),d=r.percents[B+1],u=r.anim[a];break}s&&i.attr(r.anim[r.percents[B]])}if(u){if(c)c.initstatus=s,c.start=new Date-c.ms*s;else{for(var S in u)if(u[o](S)&&(I[o](S)||i.paper.customAttributes[o](S)))switch(b[S]=i.attr(S),null==b[S]&&(b[S]=j[S]),_[S]=u[S],I[S]){case A:w[S]=(_[S]-b[S])/m;break;case"colour":b[S]=e.getRGB(b[S]);var T=e.getRGB(_[S]);w[S]={r:(T.r-b[S].r)/m,g:(T.g-b[S].g)/m,b:(T.b-b[S].b)/m};break;case"path":var M=At(b[S],_[S]),E=M[1];for(b[S]=M[0],w[S]=[],B=0,C=b[S].length;Bh&&(h=c)}!t[h+="%"].callback&&(t[h].callback=n)}return new ne(t,r)},Yt.animate=function(t,r,i,n){if(this.removed)return n&&n.call(this),this;var a=t instanceof ne?t:e.animation(t,r,i,n);return ae(a,this,a.percents[0],null,this.attr()),this},Yt.setTime=function(t,e){return t&&null!=e&&this.status(t,k(e,t.ms)/t.ms),this},Yt.status=function(t,e){var r,i,n=[],a=0;if(null!=e)return ae(t,this,-1,k(e,1)),this;for(r=Kt.length;a"));var U=H.getBoundingClientRect();A.W=g.w=(U.right-U.left)/100,A.H=g.h=(U.bottom-U.top)/100,A.X=g.x,A.Y=g.y+A.H/2,("x"in l||"y"in l)&&(A.path.v=t.format("m{0},{1}l{2},{1}",a(g.x*y),a(g.y*y),a(g.x*y)+1));for(var $=["x","y","text","font","font-family","font-weight","font-style","font-size"],Z=0,Q=$.length;Z.25&&(r=n.sqrt(.25-o(e-.5,2))*(2*(r>.5)-1)+.5),h=e+c+r),f})).split(/\s*\-\s*/),"linear"==l){var u=a.shift();if(u=-i(u),isNaN(u))return null}var p=t._parseDots(a);if(!p)return null;if(e=e.shape||e.node,p.length){e.removeChild(s),s.on=!0,s.method="none",s.color=p[0].color,s.color2=p[p.length-1].color;for(var d=[],g=0,x=p.length;g')}}catch(t){k=function(t){return e.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="rvml">')}}},t._engine.initWin(t._g.win),t._engine.create=function(){var e=t._getContainer.apply(0,arguments),r=e.container,i=e.height,n=e.width,a=e.x,s=e.y;if(!r)throw new Error("VML container not found.");var o=new t._Paper,l=o.canvas=t._g.doc.createElement("div"),h=l.style;return a=a||0,s=s||0,n=n||512,i=i||342,o.width=n,o.height=i,n==+n&&(n+="px"),i==+i&&(i+="px"),o.coordsize=216e5+c+216e5,o.coordorigin="0 0",o.span=t._g.doc.createElement("span"),o.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;",l.appendChild(o.span),h.cssText=t.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden",n,i),1==r?(t._g.doc.body.appendChild(l),h.left=a+"px",h.top=s+"px",h.position="absolute"):r.firstChild?r.insertBefore(l,r.firstChild):r.appendChild(l),o.renderfix=function(){},o},t.prototype.clear=function(){t.eve("raphael.clear",this),this.canvas.innerHTML=f,this.span=t._g.doc.createElement("span"),this.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;",this.canvas.appendChild(this.span),this.bottom=this.top=null},t.prototype.remove=function(){for(var e in t.eve("raphael.remove",this),this.canvas.parentNode.removeChild(this.canvas),this)this[e]="function"==typeof this[e]?t._removedFactory(e):null;return!0};var M=t.st;for(var E in T)T[e](E)&&!M[e](E)&&(M[E]=function(t){return function(){var e=arguments;return this.forEach(function(r){r[t].apply(r,e)})}}(E))}}.apply(e,i))||(t.exports=n)},function(t,e,r){var i,n;i=[r(0)],void 0===(n=function(t){if(!t||t.svg){var e="hasOwnProperty",r=String,i=parseFloat,n=parseInt,a=Math,s=a.max,o=a.abs,l=a.pow,h=/[, ]+/,u=t.eve,c="",f=" ",p="http://www.w3.org/1999/xlink",d={block:"M5,0 0,2.5 5,5z",classic:"M5,0 0,2.5 5,5 3.5,3 3.5,2z",diamond:"M2.5,0 5,2.5 2.5,5 0,2.5z",open:"M6,1 1,3.5 6,6",oval:"M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z"},g={};t.toString=function(){return"Your browser supports SVG.\nYou are running Raphaël "+this.version};var x=function(i,n){if(n)for(var a in"string"==typeof i&&(i=x(i)),n)n[e](a)&&("xlink:"==a.substring(0,6)?i.setAttributeNS(p,a.substring(6),r(n[a])):i.setAttribute(a,r(n[a])));else(i=t._g.doc.createElementNS("http://www.w3.org/2000/svg",i)).style&&(i.style.webkitTapHighlightColor="rgba(0,0,0,0)");return i},v=function(e,n){var h="linear",u=e.id+n,f=.5,p=.5,d=e.node,g=e.paper,v=d.style,m=t._g.doc.getElementById(u);if(!m){if(n=(n=r(n).replace(t._radial_gradient,function(t,e,r){if(h="radial",e&&r){f=i(e);var n=2*((p=i(r))>.5)-1;l(f-.5,2)+l(p-.5,2)>.25&&(p=a.sqrt(.25-l(f-.5,2))*n+.5)&&.5!=p&&(p=p.toFixed(5)-1e-5*n)}return c})).split(/\s*\-\s*/),"linear"==h){var b=n.shift();if(b=-i(b),isNaN(b))return null;var _=[0,0,a.cos(t.rad(b)),a.sin(t.rad(b))],w=1/(s(o(_[2]),o(_[3]))||1);_[2]*=w,_[3]*=w,_[2]<0&&(_[0]=-_[2],_[2]=0),_[3]<0&&(_[1]=-_[3],_[3]=0)}var k=t._parseDots(n);if(!k)return null;if(u=u.replace(/[\(\)\s,\xb0#]/g,"_"),e.gradient&&u!=e.gradient.id&&(g.defs.removeChild(e.gradient),delete e.gradient),!e.gradient){m=x(h+"Gradient",{id:u}),e.gradient=m,x(m,"radial"==h?{fx:f,fy:p}:{x1:_[0],y1:_[1],x2:_[2],y2:_[3],gradientTransform:e.matrix.invert()}),g.defs.appendChild(m);for(var B=0,C=k.length;B1?P.opacity/100:P.opacity});case"stroke":P=t.getRGB(g),l.setAttribute(d,P.hex),"stroke"==d&&P[e]("opacity")&&x(l,{"stroke-opacity":P.opacity>1?P.opacity/100:P.opacity}),"stroke"==d&&i._.arrows&&("startString"in i._.arrows&&b(i,i._.arrows.startString),"endString"in i._.arrows&&b(i,i._.arrows.endString,1));break;case"gradient":("circle"==i.type||"ellipse"==i.type||"r"!=r(g).charAt())&&v(i,g);break;case"opacity":u.gradient&&!u[e]("stroke-opacity")&&x(l,{"stroke-opacity":g>1?g/100:g});case"fill-opacity":if(u.gradient){(z=t._g.doc.getElementById(l.getAttribute("fill").replace(/^url\(#|\)$/g,c)))&&(F=z.getElementsByTagName("stop"),x(F[F.length-1],{"stop-opacity":g}));break}default:"font-size"==d&&(g=n(g,10)+"px");var R=d.replace(/(\-.)/g,function(t){return t.substring(1).toUpperCase()});l.style[R]=g,i._.dirty=1,l.setAttribute(d,g)}}B(i,a),l.style.visibility=f},B=function(i,a){if("text"==i.type&&(a[e]("text")||a[e]("font")||a[e]("font-size")||a[e]("x")||a[e]("y"))){var s=i.attrs,o=i.node,l=o.firstChild?n(t._g.doc.defaultView.getComputedStyle(o.firstChild,c).getPropertyValue("font-size"),10):10;if(a[e]("text")){for(s.text=a.text;o.firstChild;)o.removeChild(o.firstChild);for(var h,u=r(a.text).split("\n"),f=[],p=0,d=u.length;p1)for(var i=0,n=r.length;i 0) { + for (var i = 0; i < $scope.assignment.idm.candidateUsers.length; i++) { + $scope.popup.assignmentObject.idm.candidateUsers.push($scope.assignment.idm.candidateUsers[i]); + } + } + + if ($scope.assignment.idm.candidateGroups && $scope.assignment.idm.candidateGroups.length > 0) { + for (var i = 0; i < $scope.assignment.idm.candidateGroups.length; i++) { + $scope.popup.assignmentObject.idm.candidateGroups.push($scope.assignment.idm.candidateGroups[i]); + } + } + } + } + + //fill the static area + if ($scope.assignment.assignee) { + $scope.popup.assignmentObject.static.assignee = $scope.assignment.assignee; + } + + if ($scope.assignment.candidateUsers && $scope.assignment.candidateUsers.length > 0) { + for (var i = 0; i < $scope.assignment.candidateUsers.length; i++) { + $scope.popup.assignmentObject.static.candidateUsers.push($scope.assignment.candidateUsers[i]); + } + } + + if ($scope.assignment.candidateGroups && $scope.assignment.candidateGroups.length > 0) { + for (var i = 0; i < $scope.assignment.candidateGroups.length; i++) { + $scope.popup.assignmentObject.static.candidateGroups.push($scope.assignment.candidateGroups[i]); + } + } + + initStaticContextForEditing($scope); + + $scope.$watch('popup.groupFilter', function () { + $scope.updateGroupFilter(); + }); + + $scope.$watch('popup.filter', function() { + $scope.updateFilter(); + }); + + $scope.updateFilter = function() { + if ($scope.popup.oldFilter == undefined || $scope.popup.oldFilter != $scope.popup.filter) { + if (!$scope.popup.filter) { + $scope.popup.oldFilter = ''; + } else { + $scope.popup.oldFilter = $scope.popup.filter; + } + + if ($scope.popup.filter !== null && $scope.popup.filter !== undefined) { + UserService.getFilteredUsers($scope.popup.filter).then(function (result) { + var filteredUsers = []; + for (var i=0; i= 0 && $scope.popup.selectedIndex < users.length) { + user = users[$scope.popup.selectedIndex]; + } + } + + if (user) { + if ("user" == $scope.assignmentOption.id) { + $scope.popup.assignmentObject.idm.assignee = user; + } else if ("users" == $scope.assignmentOption.id) { + + // Only add if not yet part of candidate users + var found = false; + if ($scope.popup.assignmentObject.idm.candidateUsers) { + for (var i = 0; i < $scope.popup.assignmentObject.idm.candidateUsers.length; i++) { + if ($scope.popup.assignmentObject.idm.candidateUsers[i].id === user.id) { + found = true; + break; + } + } + } + + if (!found) { + $scope.addCandidateUser(user); + } + } + } + }; + + $scope.confirmEmail = function() { + if ("user" == $scope.assignmentOption.id) { + $scope.popup.assignmentObject.idm.assignee = {email: $scope.popup.email}; + } else if ("users" == $scope.assignmentOption.id) { + + // Only add if not yet part of candidate users + var found = false; + if ($scope.popup.assignmentObject.idm.candidateUsers) { + for (var i = 0; i < $scope.popup.assignmentObject.idm.candidateUsers.length; i++) { + + if ($scope.popup.assignmentObject.idm.candidateUsers[i].id) { + if ($scope.popup.assignmentObject.idm.candidateUsers[i].id === user.id) { + found = true; + break; + } + } else if ($scope.popup.assignmentObject.idm.candidateUsers[i].email) { + if ($scope.popup.assignmentObject.idm.candidateUsers[i].email === $scope.popup.email) { + found = true; + break; + } + } + } + } + + if (!found) { + $scope.addCandidateUser({email: $scope.popup.email}); + } + } + }; + + $scope.confirmGroup = function(group) { + if (!group) { + // Selection is done with keyboard, use selection index + var groups = $scope.popup.groupResults; + if ($scope.popup.selectedGroupIndex >= 0 && $scope.popup.selectedGroupIndex < groups.length) { + group = groups[$scope.popup.selectedGroupIndex]; + } + } + + if (group) { + // Only add if not yet part of candidate groups + var found = false; + if ($scope.popup.assignmentObject.idm.candidateGroups) { + for (var i = 0; i < $scope.popup.assignmentObject.idm.candidateGroups.length; i++) { + if ($scope.popup.assignmentObject.idm.candidateGroups[i].id === group.id) { + found = true; + break; + } + } + } + + if (!found) { + $scope.addCandidateGroup(group); + } + } + }; + + $scope.addCandidateUser = function(user) { + $scope.popup.assignmentObject.idm.candidateUsers.push(user); + }; + + $scope.removeCandidateUser = function(user) { + var users = $scope.popup.assignmentObject.idm.candidateUsers; + var indexToRemove = -1; + for (var i = 0; i < users.length; i++) { + if (user.id) { + if (user.id === users[i].id) { + indexToRemove = i; + break; + } + } else { + if (user.email === users[i].email) { + indexToRemove = i; + break; + } + } + } + if (indexToRemove >= 0) { + users.splice(indexToRemove, 1); + } + }; + + $scope.addCandidateGroup = function(group) { + $scope.popup.assignmentObject.idm.candidateGroups.push(group); + }; + + $scope.removeCandidateGroup = function(group) { + var groups = $scope.popup.assignmentObject.idm.candidateGroups; + var indexToRemove = -1; + for (var i = 0; i < groups.length; i++) { + if (group.id == groups[i].id) { + indexToRemove = i; + break; + } + } + if (indexToRemove >= 0) { + groups.splice(indexToRemove, 1); + } + }; + + $scope.resetSelection = function() { + if ($scope.popup.userResults && $scope.popup.userResults.length > 0) { + $scope.popup.selectedIndex = 0; + } else { + $scope.popup.selectedIndex = -1; + } + }; + + $scope.nextUser = function() { + var users = $scope.popup.userResults; + if (users && users.length > 0 && $scope.popup.selectedIndex < users.length -1) { + $scope.popup.selectedIndex += 1; + } + }; + + $scope.previousUser = function() { + var users = $scope.popup.userResults; + if (users && users.length > 0 && $scope.popup.selectedIndex > 0) { + $scope.popup.selectedIndex -= 1; + } + }; + + $scope.resetGroupSelection = function() { + if ($scope.popup.groupResults && $scope.popup.groupResults.length > 0) { + $scope.popup.selectedGroupIndex = 0; + } else { + $scope.popup.selectedGroupIndex = -1; + } + }; + + $scope.nextGroup = function() { + var groups = $scope.popup.groupResults; + if (groups && groups.length > 0 && $scope.popup.selectedGroupIndex < groups.length -1) { + $scope.popup.selectedGroupIndex += 1; + } + }; + + $scope.previousGroup = function() { + var groups = $scope.popup.groupResults; + if (groups && groups.length > 0 && $scope.popup.selectedGroupIndex > 0) { + $scope.popup.selectedGroupIndex -= 1; + } + }; + + $scope.removeAssignee = function() { + $scope.popup.assignmentObject.idm.assignee = undefined; + }; + + // Click handler for + button after enum value + $scope.addCandidateUserValue = function(index) { + $scope.popup.assignmentObject.static.candidateUsers.splice(index + 1, 0, {value: ''}); + }; + + // Click handler for - button after enum value + $scope.removeCandidateUserValue = function(index) { + $scope.popup.assignmentObject.static.candidateUsers.splice(index, 1); + }; + + // Click handler for + button after enum value + $scope.addCandidateGroupValue = function(index) { + $scope.popup.assignmentObject.static.candidateGroups.splice(index + 1, 0, {value: ''}); + }; + + // Click handler for - button after enum value + $scope.removeCandidateGroupValue = function(index) { + $scope.popup.assignmentObject.static.candidateGroups.splice(index, 1); + }; + + $scope.setSearchType = function() { + $scope.popup.assignmentObject.assignmentSourceType = 'search'; + }; + + $scope.allSteps = EDITOR.UTIL.collectSortedElementsFromPrecedingElements($scope.selectedShape); + + $scope.save = function () { + + handleAssignmentInput($scope.popup.assignmentObject.static); + + $scope.assignment.type = $scope.popup.assignmentObject.type; + + if ('idm' === $scope.popup.assignmentObject.type) { // IDM + $scope.popup.assignmentObject.static = undefined; + + //Construct an IDM object to be saved to the process model. + var idm = {type: $scope.assignmentOption.id}; + if ('user' == idm.type) { + if ($scope.popup.assignmentObject.idm.assignee) { + idm.assignee = $scope.popup.assignmentObject.idm.assignee; + } + } else if ('users' == idm.type) { + if ($scope.popup.assignmentObject.idm.candidateUsers && $scope.popup.assignmentObject.idm.candidateUsers.length > 0) { + idm.candidateUsers = $scope.popup.assignmentObject.idm.candidateUsers; + } + } else if ('groups' == idm.type) { + if ($scope.popup.assignmentObject.idm.candidateGroups && $scope.popup.assignmentObject.idm.candidateGroups.length > 0) { + idm.candidateGroups = $scope.popup.assignmentObject.idm.candidateGroups; + } + } + $scope.assignment.idm = idm; + $scope.assignment.assignee = undefined; + $scope.assignment.candidateUsers = undefined; + $scope.assignment.candidateGroups = undefined; + + } + + if ('static' === $scope.popup.assignmentObject.type) { // IDM + $scope.popup.assignmentObject.idm = undefined; + $scope.assignment.idm = undefined; + $scope.assignment.assignee = $scope.popup.assignmentObject.static.assignee; + $scope.assignment.candidateUsers = $scope.popup.assignmentObject.static.candidateUsers; + $scope.assignment.candidateGroups = $scope.popup.assignmentObject.static.candidateGroups; + } + + $scope.property.value = {}; + $scope.property.value.assignment = $scope.assignment; + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + // Close button handler + $scope.close = function() { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + var handleAssignmentInput = function ($assignment) { + + function isEmptyString(value) { + return (value === undefined || value === null || value.trim().length === 0); + } + + if (isEmptyString($assignment.assignee)){ + $assignment.assignee = undefined; + } + var toRemoveIndexes; + var removedItems=0; + var i = 0; + if ($assignment.candidateUsers) { + toRemoveIndexes = []; + for (i = 0; i < $assignment.candidateUsers.length; i++) { + if (isEmptyString($assignment.candidateUsers[i].value)) { + toRemoveIndexes[toRemoveIndexes.length] = i; + } + } + + if (toRemoveIndexes.length == $assignment.candidateUsers.length) { + $assignment.candidateUsers = undefined; + } else { + removedItems=0; + for (i = 0; i < toRemoveIndexes.length; i++) { + $assignment.candidateUsers.splice(toRemoveIndexes[i]-removedItems, 1); + removedItems++; + } + } + } + + if ($assignment.candidateGroups) { + toRemoveIndexes = []; + for (i = 0; i < $assignment.candidateGroups.length; i++) { + if (isEmptyString($assignment.candidateGroups[i].value)) { + toRemoveIndexes[toRemoveIndexes.length] = i; + } + } + + if (toRemoveIndexes.length == $assignment.candidateGroups.length) { + $assignment.candidateGroups = undefined; + } else { + removedItems=0; + for (i = 0; i < toRemoveIndexes.length; i++) { + $assignment.candidateGroups.splice(toRemoveIndexes[i]-removedItems, 1); + removedItems++; + } + } + } + }; + + function initStaticContextForEditing($scope) { + if (!$scope.popup.assignmentObject.static.candidateUsers || $scope.popup.assignmentObject.static.candidateUsers.length==0) { + $scope.popup.assignmentObject.static.candidateUsers = [{value: ''}]; + } + if (!$scope.popup.assignmentObject.static.candidateGroups || $scope.popup.assignmentObject.static.candidateGroups.length==0) { + $scope.popup.assignmentObject.static.candidateGroups = [{value: ''}]; + } + } +}]); diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-calledelementtype-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-calledelementtype-controller.js new file mode 100644 index 0000000..c07775c --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-calledelementtype-controller.js @@ -0,0 +1,28 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Call activity calledElement type property + */ + +angular.module('flowableModeler').controller('FlowableCalledElementTypeCtrl', [ '$scope', function($scope) { + + if ($scope.property.value == undefined && $scope.property.value == null) + { + $scope.property.value = 'key'; + } + + $scope.calledElementTypeChanged = function() { + $scope.updatePropertyInModel($scope.property); + }; +}]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-case-reference-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-case-reference-controller.js new file mode 100644 index 0000000..1f3d02e --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-case-reference-controller.js @@ -0,0 +1,80 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowableCaseReferenceCtrl', + [ '$scope', '$modal', '$http', function($scope, $modal, $http) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/case-reference-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); +}]); + +angular.module('flowableModeler').controller('FlowableCaseReferencePopupCtrl', [ '$scope', '$http', 'editorManager', function($scope, $http, editorManager) { + + $scope.state = {'loadingCases' : true, 'error' : false}; + + // Close button handler + $scope.close = function() { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + // Selecting/deselecting a case + $scope.selectCase = function(caseModel, $event) { + $event.stopPropagation(); + if ($scope.selectedCase && $scope.selectedCase.id && caseModel.id == $scope.selectedCase.id) { + // un-select the current selection + $scope.selectedCase = null; + } else { + $scope.selectedCase = caseModel; + } + }; + + // Saving the selected value + $scope.save = function() { + if ($scope.selectedCase) { + $scope.property.value = {'id' : $scope.selectedCase.id, 'name' : $scope.selectedCase.name}; + } else { + $scope.property.value = null; + } + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + $scope.loadCases = function() { + var modelMetaData = editorManager.getBaseModelData(); + $http.get(FLOWABLE.APP_URL.getCaseModelsUrl('?excludeId=' + modelMetaData.modelId)) + .success( + function(response) { + $scope.state.loadingCases = false; + $scope.state.caseError = false; + $scope.caseModels = response.data; + }) + .error( + function(data, status, headers, config) { + $scope.state.loadingCases = false; + $scope.state.caseError = true; + }); + }; + + if ($scope.property && $scope.property.value && $scope.property.value.id) { + $scope.selectedCase = $scope.property.value; + } + + $scope.loadCases(); +}]); diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-condition-expression-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-condition-expression-controller.js new file mode 100644 index 0000000..0ef677e --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-condition-expression-controller.js @@ -0,0 +1,59 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Condition expression + */ + +angular.module('flowableModeler').controller('FlowableConditionExpressionCtrl', [ '$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 + _internalCreateModal(opts, $modal, $scope); +}]); + +angular.module('flowableModeler').controller('FlowableConditionExpressionPopupCtrl', + [ '$rootScope', '$scope', '$translate', 'FormBuilderService', function($rootScope, $scope, $translate, FormBuilderService) { + + // Put json representing assignment on scope + if ($scope.property.value !== undefined && $scope.property.value !== null + && $scope.property.value.expression !== undefined + && $scope.property.value.expression !== null) { + + $scope.expression = $scope.property.value.expression; + + } else if ($scope.property.value !== undefined && $scope.property.value !== null) { + $scope.expression = {type: 'static', staticValue: $scope.property.value}; + + } else { + $scope.expression = {}; + } + + $scope.save = function() { + $scope.property.value = {expression: $scope.expression}; + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + // Close button handler + $scope.close = function() { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + +}]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-custom-controllers.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-custom-controllers.js new file mode 100644 index 0000000..72ac304 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-custom-controllers.js @@ -0,0 +1,12 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-data-properties-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-data-properties-controller.js new file mode 100644 index 0000000..547bd30 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-data-properties-controller.js @@ -0,0 +1,330 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Data Properties + */ + +angular.module('flowableModeler').controller('FlowableDataPropertiesCtrl', + ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/data-properties-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); + }]); + +angular.module('flowableModeler').controller('FlowableDataPropertiesPopupCtrl', + ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) { + + // Put json representing data properties on scope + if ($scope.property.value !== undefined && $scope.property.value !== null + && $scope.property.value.items !== undefined + && $scope.property.value.items !== 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.dataProperties = angular.copy($scope.property.value.items); + + for (var i = 0; i < $scope.dataProperties.length; i++) { + var dataProperty = $scope.dataProperties[i]; + if (dataProperty.enumValues && dataProperty.enumValues.length > 0) { + for (var j = 0; j < dataProperty.enumValues.length; j++) { + var enumValue = dataProperty.enumValues[j]; + if (!enumValue.id && !enumValue.name && enumValue.value) { + enumValue.id = enumValue.value; + enumValue.name = enumValue.value; + } + } + } + } + + } else { + $scope.dataProperties = []; + } + + $scope.enumValues = []; + + $scope.translationsRetrieved = false; + + $scope.labels = {}; + + var idPromise = $translate('PROPERTY.DATAPROPERTIES.ID'); + var namePromise = $translate('PROPERTY.DATAPROPERTIES.NAME'); + var typePromise = $translate('PROPERTY.DATAPROPERTIES.TYPE'); + var valuePromise = $translate('PROPERTY.DATAPROPERTIES.VALUE'); + + $q.all([idPromise, namePromise, typePromise, valuePromise]).then(function (results) { + $scope.labels.idLabel = results[0]; + $scope.labels.nameLabel = results[1]; + $scope.labels.typeLabel = results[2]; + $scope.labels.valueLabel = results[3]; + $scope.translationsRetrieved = true; + + // Config for grid + $scope.gridOptions = { + data: $scope.dataProperties, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{field: 'dataproperty_id', displayName: $scope.labels.idLabel}, + {field: 'dataproperty_name', displayName: $scope.labels.nameLabel}, + {field: 'dataproperty_type', displayName: $scope.labels.typeLabel}, + {field: 'dataproperty_value', displayName: $scope.labels.valueLabel}] + }; + + $scope.enumGridOptions = { + data: $scope.enumValues, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{ field: 'id', displayName: $scope.labels.idLabel }, + { field: 'name', displayName: $scope.labels.nameLabel}] + } + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedProperty = row.entity; + $scope.selectedEnumValue = undefined; + if ($scope.selectedProperty && $scope.selectedProperty.enumValues) { + $scope.enumValues.length = 0; + for (var i = 0; i < $scope.selectedProperty.enumValues.length; i++) { + $scope.enumValues.push($scope.selectedProperty.enumValues[i]); + } + } + }); + }; + + $scope.enumGridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.enumGridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedEnumValue = row.entity; + }); + }; + }); + + // Handler for when the value of the type dropdown changes + $scope.propertyTypeChanged = function () { + + // Check date. If date, show date pattern + if ($scope.selectedProperty.type === 'date') { + $scope.selectedProperty.datePattern = 'MM-dd-yyyy hh:mm'; + } else { + delete $scope.selectedProperty.datePattern; + } + + // Check enum. If enum, show list of options + if ($scope.selectedProperty.type === 'enum') { + $scope.selectedProperty.enumValues = [ {id: 'value1', name: 'Value 1'}, {id: 'value2', name: 'Value 2'}]; + $scope.enumValues.length = 0; + for (var i = 0; i < $scope.selectedProperty.enumValues.length; i++) { + $scope.enumValues.push($scope.selectedProperty.enumValues[i]); + } + + } else { + delete $scope.selectedProperty.enumValues; + $scope.enumValues.length = 0; + } + }; + + // Click handler for add button + var propertyIndex = 1; + $scope.addNewProperty = function () { + var newProperty = { + dataproperty_id: 'new_data_object_' + propertyIndex++, + dataproperty_name: '', + dataproperty_type: 'string', + readable: true, + writable: true + }; + + $scope.dataProperties.push(newProperty); + + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newProperty); + }); + }; + + // Click handler for remove button + $scope.removeProperty = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.dataProperties.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + $scope.dataProperties.splice(index, 1); + + if ($scope.dataProperties.length == 0) { + $scope.selectedProperty = undefined; + } + + $timeout(function() { + if ($scope.dataProperties.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.dataProperties[0]); + } + }); + } + }; + + // Click handler for up button + $scope.movePropertyUp = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.dataProperties.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.dataProperties[index]; + $scope.dataProperties.splice(index, 1); + $timeout(function(){ + $scope.dataProperties.splice(index + -1, 0, temp); + $timeout(function() { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.movePropertyDown = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.dataProperties.indexOf(selectedItems[0]); + if (index != $scope.dataProperties.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.dataProperties[index]; + $scope.dataProperties.splice(index, 1); + $timeout(function(){ + $scope.dataProperties.splice(index + 1, 0, temp); + $timeout(function() { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + $scope.addNewEnumValue = function() { + if ($scope.selectedProperty) { + var newEnumValue = { id : '', name : ''}; + $scope.selectedProperty.enumValues.push(newEnumValue); + $scope.enumValues.push(newEnumValue); + + $timeout(function () { + $scope.enumGridApi.selection.toggleRowSelection(newEnumValue); + }); + } + }; + + // Click handler for remove button + $scope.removeEnumValue = function() { + var selectedItems = $scope.enumGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.enumValues.indexOf(selectedItems[0]); + $scope.enumGridApi.selection.toggleRowSelection(selectedItems[0]); + + $scope.enumValues.splice(index, 1); + $scope.selectedProperty.enumValues.splice(index, 1); + + if ($scope.enumValues.length == 0) { + $scope.selectedEnumValue = undefined; + } + + $timeout(function () { + if ($scope.enumValues.length > 0) { + $scope.enumGridApi.selection.toggleRowSelection($scope.enumValues[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveEnumValueUp = function() { + var selectedItems = $scope.enumGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.enumValues.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.enumValues[index]; + $scope.enumValues.splice(index, 1); + $scope.selectedProperty.enumValues.splice(index, 1); + $timeout(function () { + $scope.enumValues.splice(index + -1, 0, temp); + $scope.selectedProperty.enumValues.splice(index + -1, 0, temp); + $timeout(function () { + $scope.enumGridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveEnumValueDown = function() { + var selectedItems = $scope.enumGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.enumValues.indexOf(selectedItems[0]); + if (index != $scope.enumValues.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.enumValues[index]; + $scope.enumValues.splice(index, 1); + $scope.selectedProperty.enumValues.splice(index, 1); + $timeout(function () { + $scope.enumValues.splice(index + 1, 0, temp); + $scope.selectedProperty.enumValues.splice(index + 1, 0, temp); + $timeout(function () { + $scope.enumGridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for save button + $scope.save = function () { + + if ($scope.dataProperties.length > 0) { + $scope.property.value = {}; + $scope.property.value.items = $scope.dataProperties; + } 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'; + }; + + }]) +; \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-decisiontable-reference-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-decisiontable-reference-controller.js new file mode 100644 index 0000000..a2b697c --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-decisiontable-reference-controller.js @@ -0,0 +1,288 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowableDecisionTableReferenceCtrl', + [ '$scope', '$modal', '$http', function($scope, $modal, $http) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/decisiontable-reference-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); +}]); + +angular.module('flowableModeler').controller('FlowableDecisionTableReferencePopupCtrl', ['$rootScope', '$scope', '$http', '$location', 'editorManager', + function($rootScope, $scope, $http, $location, editorManager) { + + $scope.state = { + 'loadingDecisionTables': true, + 'decisionTableError': false + }; + + $scope.popup = { + 'state': 'decisionTableReference' + }; + + $scope.foldersBreadCrumbs = []; + + // Make click outside dialog also call close. + $scope.$parent.$on('modal.hide.before', function() { + $scope.close(); + $scope.$parent.$apply(); + }); + + // Close button handler + $scope.close = function() { + $scope.property.newVariablesMapping = undefined; + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + // Selecting/deselecting a decision table + $scope.selectDecisionTable = function(decisionTable, $event) { + $event.stopPropagation(); + if ($scope.selectedDecisionTable && $scope.selectedDecisionTable.id && decisionTable.id == $scope.selectedDecisionTable.id) { + // un-select the current selection + $scope.selectedDecisionTable = null; + } else { + $scope.selectedDecisionTable = decisionTable; + } + }; + + $scope.isSelected = function () { + if ($scope.selectedDecisionTable && $scope.selectedDecisionTable.id) { + return true; + } + return false; + }; + + // Saving the selected value + $scope.save = function() { + if ($scope.selectedDecisionTable) { + $scope.property.value = { + 'id': $scope.selectedDecisionTable.id, + 'name': $scope.selectedDecisionTable.name, + 'key': $scope.selectedDecisionTable.key + }; + + } else { + $scope.property.value = null; + } + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + // Open the selected value + $scope.open = function() { + if ($scope.selectedDecisionTable) { + $scope.property.value = { + 'id': $scope.selectedDecisionTable.id, + 'name': $scope.selectedDecisionTable.name, + 'key': $scope.selectedDecisionTable.key + }; + $scope.updatePropertyInModel($scope.property); + + var modelMetaData = editorManager.getBaseModelData(); + var json = editorManager.getModel(); + json = JSON.stringify(json); + + var params = { + modeltype: modelMetaData.model.modelType, + json_xml: json, + name: modelMetaData.name, + key: modelMetaData.key, + description: modelMetaData.description, + newversion: false, + lastUpdated: modelMetaData.lastUpdated + }; + + // Update + $http({ + method: 'POST', + data: params, + ignoreErrors: true, + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' + }, + transformRequest: function (obj) { + var str = []; + for (var p in obj) { + str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); + } + return str.join("&"); + }, + url: FLOWABLE.URL.putModel(modelMetaData.modelId) + }) + + .success(function(data, status, headers, config) { + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_SAVED + }); + + $rootScope.addHistoryItem($scope.selectedShape.resourceId); + $location.path('decision-table-editor/' + $scope.selectedDecisionTable.id); + }) + .error(function(data, status, headers, config) { + + }); + + $scope.close(); + } + }; + + $scope.newDecisionTable = function() { + $scope.property.value.variablesmapping = []; + + $scope.popup.state = 'newDecisionTable'; + + var modelMetaData = editorManager.getBaseModelData(); + + $scope.model = { + loading: false, + decisionTable: { + name: '', + key: '', + description: '', + modelType: 4 + }, + defaultStencilSet: undefined, + decisionTableStencilSets: [] + }; + }; + + $scope.createDecisionTable = function() { + + if (!$scope.model.decisionTable.name || $scope.model.decisionTable.name.length == 0 || + !$scope.model.decisionTable.key || $scope.model.decisionTable.key.length == 0) { + + return; + } + + var stencilSetId = $scope.model.decisionTable.stencilSet; + $scope.model.loading = true; + + $http({ + method: 'POST', + url: FLOWABLE.APP_URL.getModelsUrl(), + data: $scope.model.decisionTable + }). + success(function(data, status, headers, config) { + + var newDecisionTableId = data.id; + $scope.property.value = { + 'id': newDecisionTableId, + 'name': data.name, + 'key': data.key + }; + $scope.updatePropertyInModel($scope.property); + + var modelMetaData = editorManager.getBaseModelData(); + var json = editorManager.getModel(); + json = JSON.stringify(json); + + var params = { + modeltype: modelMetaData.model.modelType, + json_xml: json, + name: modelMetaData.name, + key: modelMetaData.key, + description: modelMetaData.description, + newversion: false, + lastUpdated: modelMetaData.lastUpdated, + stencilSet: stencilSetId + }; + + // Update + $http({ + method: 'POST', + data: params, + ignoreErrors: true, + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' + }, + transformRequest: function (obj) { + var str = []; + for (var p in obj) { + str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); + } + return str.join("&"); + }, + url: FLOWABLE.URL.putModel(modelMetaData.modelId) + }) + + .success(function(data, status, headers, config) { + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_SAVED + }); + + $scope.model.loading = false; + $scope.$hide(); + + $rootScope.addHistoryItem($scope.selectedShape.resourceId); + $location.path('decision-table-editor/' + newDecisionTableId); + }) + .error(function(data, status, headers, config) { + $scope.model.loading = false; + $scope.$hide(); + }); + + }). + error(function(data, status, headers, config) { + $scope.model.loading = false; + $scope.model.errorMessage = data.message; + }); + }; + + $scope.cancel = function() { + $scope.close(); + }; + + $scope.resetCurrent = function () { + for (var i = 0, found = false; i < $scope.decisionTables.length && found === false; i++) { + var table = $scope.decisionTables[i]; + if (table.id === $scope.property.value.id) { + $scope.selectedDecisionTable = table; + found = true; + } + } + }; + + $scope.loadDecisionTables = function() { + var modelMetaData = editorManager.getBaseModelData(); + $http.get(FLOWABLE.APP_URL.getDecisionTableModelsUrl()) + .success( + function(response) { + $scope.state.loadingDecisionTables = false; + $scope.state.decisionTableError = false; + $scope.decisionTables = response.data; + $scope.resetCurrent(); + }) + .error( + function(data, status, headers, config) { + $scope.state.loadingDecisionTables = false; + $scope.state.decisionTableError = true; + }); + }; + + if ($scope.property && $scope.property.value && $scope.property.value.id) { + $scope.selectedDecisionTable = $scope.property.value; + $scope.storedId = $scope.property.value.id; + } + + $scope.loadDecisionTables(); + } +]); diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-default-controllers.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-default-controllers.js new file mode 100644 index 0000000..c31fe4d --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-default-controllers.js @@ -0,0 +1,118 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * String controller + */ + +angular.module('flowableModeler').controller('FlowableStringPropertyCtrl', [ '$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 enter is pressed + if (keyEvent && keyEvent.which === 13) { + keyEvent.preventDefault(); + $scope.inputBlurred(); // we want to do the same as if the user would blur the input field + } + // else; do nothing + }; + + $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 + */ + +angular.module('flowableModeler').controller('FlowableBooleanPropertyCtrl', ['$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.get('oryx-defaultflow'); + if (defaultFlowProp) { + flows[i].setProperty('oryx-defaultflow', false, true); + } + } + } + } + } + } + } + $scope.updatePropertyInModel($scope.property); + }; + +}]); + +/* + * Text controller + */ + +angular.module('flowableModeler').controller('FlowableTextPropertyCtrl', [ '$scope', '$modal', '$timeout', function($scope, $modal, $timeout) { + + var opts = { + template: 'editor-app/configuration/properties/text-popup.html?version=' + Date.now(), + scope: $scope, + prefixEvent: 'textModalEvent' + }; + + $scope.$on('textModalEvent.hide.before', function() { + $timeout(function() { + $scope.property.mode = 'read'; + }, 0); + }); + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); +}]); + +angular.module('flowableModeler').controller('FlowableTextPropertyPopupCtrl', ['$scope', function($scope) { + + $scope.save = function() { + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + $scope.close = function() { + $scope.property.mode = 'read'; + $scope.$hide(); + }; +}]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-duedate-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-duedate-controller.js new file mode 100644 index 0000000..50ff9dd --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-duedate-controller.js @@ -0,0 +1,126 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Due date + */ +'use strict'; + +angular.module('flowableModeler').controller('BpmnEditorDueDateCtrl', [ '$scope', '$modal', function($scope, $modal) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/duedate-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); +}]); + +angular.module('flowableModeler').controller('BpmnEditorDueDatePopupCtrl', + [ '$rootScope', '$scope', '$translate', function($rootScope, $scope, $translate) { + + // Put json representing assignment on scope + if ($scope.property.value !== undefined && $scope.property.value !== null) { + + if ($scope.property.value.duedate !== undefined && $scope.property.value.duedate !== null) { + $scope.popup = {'duedate': $scope.property.value.duedate}; + + } else if ($scope.property.value.duedateExpression !== undefined && $scope.property.value.duedateExpression !== null) { + $scope.popup = {'duedateExpression': $scope.property.value.duedateExpression}; + + } else { + $scope.popup = {'duedateExpression': $scope.property.value}; + } + + } else { + $scope.popup = {}; + } + + $scope.taskDueDateOptions = [ + {id: "none", title: $translate.instant('PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.NO-DUEDATE')}, + {id: "expression", title: $translate.instant('PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.EXPRESSION')}, + {id: "static", title: $translate.instant('PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.STATIC')}, + {id: "field", title: $translate.instant('PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.FIELD')} + ]; + + if (!$scope.popup.duedate && !$scope.popup.duedateExpression) { + // Default, first time opening the popup + $scope.popup.selectedDueDateOption = $scope.taskDueDateOptions[0].id; + + } else if (!$scope.popup.duedate) { + $scope.popup.selectedDueDateOption = $scope.taskDueDateOptions[1].id; + + } else { + + if ($scope.popup.duedate.fixed) { + $scope.popup.selectedDueDateOption = $scope.taskDueDateOptions[2].id; + + } else if ($scope.popup.duedate.field) { + $scope.popup.selectedDueDateOption = $scope.taskDueDateOptions[3].id; + + } else { + $scope.popup.selectedDueDateOption = $scope.taskDueDateOptions[0].id; + } + } + + $scope.dueDateOptionChanged = function() { + if ($scope.popup.selectedDueDateOption === 'expression') { + $scope.popup.duedate = undefined; + + } else if ($scope.popup.selectedDueDateOption === 'none') { + $scope.popup.duedate = undefined; + $scope.popup.duedateExpression = undefined; + + } else if ($scope.popup.selectedDueDateOption === 'static') { + $scope.popup.duedate = {'fixed': {}}; + $scope.popup.duedateExpression = undefined; + + } else if ($scope.popup.selectedDueDateOption === 'field') { + $scope.popup.duedate = {'field': {}}; + $scope.popup.duedateExpression = undefined; + } + }; + + $scope.setAddCalculationType = function() { + $scope.popup.duedate.field.taskDueDateCalculationType = 'add'; + }; + + $scope.setSubtractCalculationType = function() { + $scope.popup.duedate.field.taskDueDateCalculationType = 'subtract'; + }; + + $scope.allSteps = EDITOR.UTIL.collectSortedElementsFromPrecedingElements($scope.selectedShape); + + $scope.save = function () { + $scope.property.value = {}; + if ($scope.popup.duedate) { + $scope.property.value.duedate = $scope.popup.duedate; + + } else if ($scope.popup.duedateExpression) { + $scope.property.value.duedateExpression = $scope.popup.duedateExpression; + + } else { + $scope.property.value = ''; + } + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + // Close button handler + $scope.close = function() { + $scope.property.mode = 'read'; + $scope.$hide(); + }; +}]); diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-event-listeners-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-event-listeners-controller.js new file mode 100644 index 0000000..21f9ad4 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-event-listeners-controller.js @@ -0,0 +1,263 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Execution listeners + */ + +angular.module('flowableModeler').controller('FlowableEventListenersCtrl', + ['$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 + _internalCreateModal(opts, $modal, $scope); + }]); + +//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('flowableModeler').controller('FlowableEventListenersPopupCtrl', + ['$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.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 = []; + } + + $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: $scope.eventListeners, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{field: 'event', displayName: $scope.labels.eventLabel}, + {field: 'implementation', displayName: $scope.labels.implementationLabel}] + }; + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedListener = row.entity; + + if ($scope.selectedListener) { + var fields = $scope.selectedListener.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; + } + } + } else { + $scope.selectedListener.fields = []; + } + if (!$scope.selectedListener.events) { + $scope.selectedListener.events = [{event: ''}]; + } + } + }); + }; + }); + + + // Click handler for + button after enum value + $scope.addEventValue = function (index) { + $scope.selectedListener.events.splice(index + 1, 0, {event: ''}); + }; + + // Click handler for - button after enum value + $scope.removeEventValue = function (index) { + $scope.selectedListener.events.splice(index, 1); + $scope.listenerDetailsChanged(); + }; + + $scope.listenerDetailsChanged = function () { + var listener = $scope.selectedListener; + if (listener.events) { + var eventText = ''; + for (var i = 0; i < listener.events.length; i++) { + if (i > 0) { + eventText += ", "; + } + eventText += listener.events[i].event; + } + $scope.selectedListener.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.selectedListener.implementation = implementationText; + } + else { + if ($scope.selectedListener.className !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.className; + } + else if ($scope.selectedListener.delegateExpression !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.delegateExpression; + } + else { + $scope.selectedListener.implementation = ''; + } + } + }; + + // Click handler for add button + $scope.addNewListener = function () { + var newListener = { + event: '', + implementation: '', + className: '', + delegateExpression: '', + retrowEvent: false + }; + + $scope.eventListeners.push(newListener); + + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newListener); + }); + }; + + // Click handler for remove button + $scope.removeListener = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.eventListeners.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + $scope.eventListeners.splice(index, 1); + + if ($scope.eventListeners.length == 0) { + $scope.selectedListener = undefined; + } + + $timeout(function () { + if ($scope.eventListeners.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.eventListeners[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveListenerUp = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.eventListeners.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.eventListeners[index]; + $scope.eventListeners.splice(index, 1); + $timeout(function () { + $scope.eventListeners.splice(index + -1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveListenerDown = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.eventListeners.indexOf(selectedItems[0]); + if (index != $scope.eventListeners.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.eventListeners[index]; + $scope.eventListeners.splice(index, 1); + $timeout(function () { + $scope.eventListeners.splice(index + 1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // 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(); + }; + + }]); diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-execution-listeners-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-execution-listeners-controller.js new file mode 100644 index 0000000..3ca1310 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-execution-listeners-controller.js @@ -0,0 +1,358 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Execution listeners + */ + +angular.module('flowableModeler').controller('FlowableExecutionListenersCtrl', + ['$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 + _internalCreateModal(opts, $modal, $scope); + }]); + +angular.module('flowableModeler').controller('FlowableExecutionListenersPopupCtrl', + ['$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.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 = []; + } + + $scope.selectedListener = undefined; + $scope.selectedField = undefined; + $scope.fields = []; + $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: $scope.executionListeners, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{field: 'event', displayName: $scope.labels.eventLabel}, + {field: 'implementation', displayName: $scope.labels.implementationLabel}] + }; + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedListener = row.entity; + $scope.selectedField = undefined; + if ($scope.selectedListener) { + var fields = $scope.selectedListener.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; + } + } + } else { + $scope.selectedListener.fields = []; + } + + $scope.fields.length = 0; + for (var i = 0; i < $scope.selectedListener.fields.length; i++) { + $scope.fields.push($scope.selectedListener.fields[i]); + } + } + }); + }; + + // Config for field grid + $scope.gridFieldOptions = { + data: $scope.fields, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{field: 'name', displayName: $scope.labels.name}, + {field: 'implementation', displayName: $scope.labels.implementationLabel}] + }; + + $scope.gridFieldOptions.onRegisterApi = function (gridApi) { + // set gridApi on scope + $scope.fieldGridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedField = row.entity; + }); + }; + }); + + $scope.listenerDetailsChanged = function () { + if ($scope.selectedListener.className !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.className; + } else if ($scope.selectedListener.expression !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.expression; + } else if ($scope.selectedListener.delegateExpression !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.delegateExpression; + } else { + $scope.selectedListener.implementation = ''; + } + }; + + // Click handler for add button + $scope.addNewListener = function () { + var newListener = { + event: 'start', + implementation: '', + className: '', + expression: '', + delegateExpression: '' + }; + $scope.executionListeners.push(newListener); + + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newListener); + }); + }; + + // Click handler for remove button + $scope.removeListener = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.executionListeners.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + + $scope.executionListeners.splice(index, 1); + + if ($scope.executionListeners.length == 0) { + $scope.selectedListener = undefined; + } + + $timeout(function () { + if ($scope.executionListeners.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.executionListeners[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveListenerUp = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.executionListeners.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.executionListeners[index]; + $scope.executionListeners.splice(index, 1); + $timeout(function () { + $scope.executionListeners.splice(index + -1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveListenerDown = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.executionListeners.indexOf(selectedItems[0]); + if (index != $scope.executionListeners.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.executionListeners[index]; + $scope.executionListeners.splice(index, 1); + $timeout(function () { + $scope.executionListeners.splice(index + 1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + $scope.fieldDetailsChanged = function () { + if ($scope.selectedField.stringValue != '') { + $scope.selectedField.implementation = $scope.selectedField.stringValue; + } else if ($scope.selectedField.expression != '') { + $scope.selectedField.implementation = $scope.selectedField.expression; + } else if ($scope.selectedField.string != '') { + $scope.selectedField.implementation = $scope.selectedField.string; + } else { + $scope.selectedField.implementation = ''; + } + }; + + // Click handler for add button + $scope.addNewField = function () { + if ($scope.selectedListener) { + if ($scope.selectedListener.fields == undefined) { + $scope.selectedListener.fields = []; + } + + var newField = { + name: 'fieldName', + implementation: '', + stringValue: '', + expression: '', + string: '' + }; + $scope.fields.push(newField); + $scope.selectedListener.fields.push(newField); + + $timeout(function () { + $scope.fieldGridApi.selection.toggleRowSelection(newField); + }); + } + }; + + // Click handler for remove button + $scope.removeField = function () { + var selectedItems = $scope.fieldGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + $scope.fieldGridApi.selection.toggleRowSelection(selectedItems[0]); + + $scope.fields.splice(index, 1); + $scope.selectedListener.fields.splice(index, 1); + + if ($scope.fields.length == 0) { + $scope.selectedField = undefined; + } + + $timeout(function () { + if ($scope.fields.length > 0) { + $scope.fieldGridApi.selection.toggleRowSelection($scope.fields[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveFieldUp = function () { + var selectedItems = $scope.fieldGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.fields[index]; + $scope.fields.splice(index, 1); + $scope.selectedListener.fields.splice(index, 1); + $timeout(function () { + $scope.fields.splice(index + -1, 0, temp); + $scope.selectedListener.fields.splice(index + -1, 0, temp); + $timeout(function () { + $scope.fieldGridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveFieldDown = function () { + var selectedItems = $scope.fieldGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + if (index != $scope.fields.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.fields[index]; + $scope.fields.splice(index, 1); + $scope.selectedListener.fields.splice(index, 1); + $timeout(function () { + $scope.fields.splice(index + 1, 0, temp); + $scope.selectedListener.fields.splice(index + 1, 0, temp); + $timeout(function () { + $scope.fieldGridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // 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'; + }; + + }]); diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-fields-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-fields-controller.js new file mode 100644 index 0000000..2d9445b --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-fields-controller.js @@ -0,0 +1,206 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Task listeners + */ + +angular.module('flowableModeler').controller('FlowableFieldsCtrl', + ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/fields-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); + }]); + +angular.module('flowableModeler').controller('FlowableFieldsPopupCtrl', + ['$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.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 = []; + } + + $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: $scope.fields, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{field: 'name', displayName: $scope.labels.nameLabel}, + {field: 'implementation', displayName: $scope.labels.implementationLabel}] + }; + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedField = row.entity; + }); + }; + }); + + $scope.fieldDetailsChanged = function () { + if ($scope.selectedField.stringValue != '') { + $scope.selectedField.implementation = $scope.selectedField.stringValue; + } + else if ($scope.selectedField.expression != '') { + $scope.selectedField.implementation = $scope.selectedField.expression; + } + else if ($scope.selectedField.string != '') { + $scope.selectedField.implementation = $scope.selectedField.string; + } + else { + $scope.selectedField.implementation = ''; + } + }; + + // Click handler for add button + $scope.addNewField = function () { + var newField = { + name: 'fieldName', + implementation: '', + stringValue: '', + expression: '', + string: '' + }; + + $scope.fields.push(newField); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newField); + }); + }; + + // Click handler for remove button + $scope.removeField = function () { + + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + $scope.fields.splice(index, 1); + + if ($scope.fields.length == 0) { + $scope.selectedField = undefined; + } + + $timeout(function () { + if ($scope.fields.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.fields[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveFieldUp = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.fields[index]; + $scope.fields.splice(index, 1); + $timeout(function () { + $scope.fields.splice(index + -1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveFieldDown = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + if (index != $scope.fields.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.fields[index]; + $scope.fields.splice(index, 1); + $timeout(function () { + $scope.fields.splice(index + 1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // 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.$hide(); + }; + + // Close button handler + $scope.close = function () { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + }]); diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-form-properties-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-form-properties-controller.js new file mode 100644 index 0000000..ca8f051 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-form-properties-controller.js @@ -0,0 +1,327 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Form Properties + */ + +angular.module('flowableModeler').controller('FlowableFormPropertiesCtrl', + ['$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 + _internalCreateModal(opts, $modal, $scope); + }]); + +angular.module('flowableModeler').controller('FlowableFormPropertiesPopupCtrl', + ['$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 = []; + } + + $scope.enumValues = []; + + $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: $scope.formProperties, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{field: 'id', displayName: $scope.labels.idLabel}, + {field: 'name', displayName: $scope.labels.nameLabel}, + {field: 'type', displayName: $scope.labels.typeLabel}] + }; + + $scope.enumGridOptions = { + data: $scope.enumValues, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{ field: 'id', displayName: $scope.labels.idLabel }, + { field: 'name', displayName: $scope.labels.nameLabel}] + } + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedProperty = row.entity; + $scope.selectedEnumValue = undefined; + if ($scope.selectedProperty && $scope.selectedProperty.enumValues) { + $scope.enumValues.length = 0; + for (var i = 0; i < $scope.selectedProperty.enumValues.length; i++) { + $scope.enumValues.push($scope.selectedProperty.enumValues[i]); + } + } + }); + }; + + $scope.enumGridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.enumGridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedEnumValue = row.entity; + }); + }; + }); + + // Handler for when the value of the type dropdown changes + $scope.propertyTypeChanged = function () { + + // Check date. If date, show date pattern + if ($scope.selectedProperty.type === 'date') { + $scope.selectedProperty.datePattern = 'MM-dd-yyyy hh:mm'; + } else { + delete $scope.selectedProperty.datePattern; + } + + // Check enum. If enum, show list of options + if ($scope.selectedProperty.type === 'enum') { + $scope.selectedProperty.enumValues = [ {id: 'value1', name: 'Value 1'}, {id: 'value2', name: 'Value 2'}]; + $scope.enumValues.length = 0; + for (var i = 0; i < $scope.selectedProperty.enumValues.length; i++) { + $scope.enumValues.push($scope.selectedProperty.enumValues[i]); + } + + } else { + delete $scope.selectedProperty.enumValues; + $scope.enumValues.length = 0; + } + }; + + // Click handler for add button + var propertyIndex = 1; + $scope.addNewProperty = function () { + var newProperty = { + id: 'new_property_' + propertyIndex++, + name: '', + type: 'string', + readable: true, + writable: true + }; + + $scope.formProperties.push(newProperty); + + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newProperty); + }); + }; + + // Click handler for remove button + $scope.removeProperty = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.formProperties.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + $scope.formProperties.splice(index, 1); + + if ($scope.formProperties.length == 0) { + $scope.selectedProperty = undefined; + } + + $timeout(function() { + if ($scope.formProperties.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.formProperties[0]); + } + }); + } + }; + + // Click handler for up button + $scope.movePropertyUp = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.formProperties.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.formProperties[index]; + $scope.formProperties.splice(index, 1); + $timeout(function(){ + $scope.formProperties.splice(index + -1, 0, temp); + $timeout(function() { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.movePropertyDown = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.formProperties.indexOf(selectedItems[0]); + if (index != $scope.formProperties.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.formProperties[index]; + $scope.formProperties.splice(index, 1); + $timeout(function(){ + $scope.formProperties.splice(index + 1, 0, temp); + $timeout(function() { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + $scope.addNewEnumValue = function() { + if ($scope.selectedProperty) { + var newEnumValue = { id : '', name : ''}; + $scope.selectedProperty.enumValues.push(newEnumValue); + $scope.enumValues.push(newEnumValue); + + $timeout(function () { + $scope.enumGridApi.selection.toggleRowSelection(newEnumValue); + }); + } + }; + + // Click handler for remove button + $scope.removeEnumValue = function() { + var selectedItems = $scope.enumGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.enumValues.indexOf(selectedItems[0]); + $scope.enumGridApi.selection.toggleRowSelection(selectedItems[0]); + + $scope.enumValues.splice(index, 1); + $scope.selectedProperty.enumValues.splice(index, 1); + + if ($scope.enumValues.length == 0) { + $scope.selectedEnumValue = undefined; + } + + $timeout(function () { + if ($scope.enumValues.length > 0) { + $scope.enumGridApi.selection.toggleRowSelection($scope.enumValues[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveEnumValueUp = function() { + var selectedItems = $scope.enumGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.enumValues.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.enumValues[index]; + $scope.enumValues.splice(index, 1); + $scope.selectedProperty.enumValues.splice(index, 1); + $timeout(function () { + $scope.enumValues.splice(index + -1, 0, temp); + $scope.selectedProperty.enumValues.splice(index + -1, 0, temp); + $timeout(function () { + $scope.enumGridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveEnumValueDown = function() { + var selectedItems = $scope.enumGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.enumValues.indexOf(selectedItems[0]); + if (index != $scope.enumValues.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.enumValues[index]; + $scope.enumValues.splice(index, 1); + $scope.selectedProperty.enumValues.splice(index, 1); + $timeout(function () { + $scope.enumValues.splice(index + 1, 0, temp); + $scope.selectedProperty.enumValues.splice(index + 1, 0, temp); + $timeout(function () { + $scope.enumGridApi.selection.toggleRowSelection(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'; + }; + + }]) +; \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-form-reference-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-form-reference-controller.js new file mode 100644 index 0000000..a710bce --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-form-reference-controller.js @@ -0,0 +1,261 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowableFormReferenceDisplayCtrl', + [ '$scope', '$modal', '$http', function($scope, $modal, $http) { + + if ($scope.property && $scope.property.value && $scope.property.value.id) { + $http.get(FLOWABLE.APP_URL.getModelUrl($scope.property.value.id)) + .success( + function(response) { + $scope.form = { + id: response.id, + name: response.name + }; + }); + } + +}]); + +angular.module('flowableModeler').controller('FlowableFormReferenceCtrl', + [ '$scope', '$modal', '$http', function($scope, $modal, $http) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/form-reference-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); +}]); + +angular.module('flowableModeler').controller('FlowableFormReferencePopupCtrl', + [ '$rootScope', '$scope', '$http', '$location', 'editorManager', function($rootScope, $scope, $http, $location, editorManager) { + + $scope.state = {'loadingForms' : true, 'formError' : false}; + + $scope.popup = {'state' : 'formReference'}; + + $scope.foldersBreadCrumbs = []; + + // Close button handler + $scope.close = function() { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + // Selecting/deselecting a subprocess + $scope.selectForm = function(form, $event) { + $event.stopPropagation(); + if ($scope.selectedForm && $scope.selectedForm.id && form.id == $scope.selectedForm.id) { + // un-select the current selection + $scope.selectedForm = null; + } else { + $scope.selectedForm = form; + } + }; + + // Saving the selected value + $scope.save = function() { + if ($scope.selectedForm) { + $scope.property.value = { + 'id' : $scope.selectedForm.id, + 'name' : $scope.selectedForm.name, + 'key' : $scope.selectedForm.key + }; + + } else { + $scope.property.value = null; + } + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + // Open the selected value + $scope.open = function() { + if ($scope.selectedForm) { + $scope.property.value = { + 'id' : $scope.selectedForm.id, + 'name' : $scope.selectedForm.name, + 'key' : $scope.selectedForm.key + }; + + $scope.updatePropertyInModel($scope.property); + + var modelMetaData = editorManager.getBaseModelData(); + var json = editorManager.getModel(); + json = JSON.stringify(json); + + var params = { + modeltype: modelMetaData.model.modelType, + json_xml: json, + name: modelMetaData.name, + key: modelMetaData.key, + description: modelMetaData.description, + newversion: false, + lastUpdated: modelMetaData.lastUpdated + }; + + // Update + $http({ method: 'POST', + data: params, + ignoreErrors: true, + headers: {'Accept': 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}, + transformRequest: function (obj) { + var str = []; + for (var p in obj) { + str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); + } + return str.join("&"); + }, + url: FLOWABLE.URL.putModel(modelMetaData.modelId)}) + + .success(function (data, status, headers, config) { + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_SAVED + }); + + var allSteps = EDITOR.UTIL.collectSortedElementsFromPrecedingElements($scope.selectedShape); + + $rootScope.addHistoryItem($scope.selectedShape.resourceId); + $location.path('form-editor/' + $scope.selectedForm.id); + + }) + .error(function (data, status, headers, config) { + + }); + + $scope.close(); + } + }; + + $scope.newForm = function() { + $scope.popup.state = 'newForm'; + + var modelMetaData = editorManager.getBaseModelData(); + + $scope.model = { + loading: false, + form: { + name: '', + key: '', + description: '', + modelType: 2 + } + }; + }; + + $scope.createForm = function() { + + if (!$scope.model.form.name || $scope.model.form.name.length == 0 || + !$scope.model.form.key || $scope.model.form.key.length == 0) { + + return; + } + + $scope.model.loading = true; + + $http({method: 'POST', url: FLOWABLE.APP_URL.getModelsUrl(), data: $scope.model.form}). + success(function(data, status, headers, config) { + + var newFormId = data.id; + $scope.property.value = { + 'id' : newFormId, + 'name' : data.name, + 'key' : data.key + }; + $scope.updatePropertyInModel($scope.property); + + var modelMetaData = editorManager.getBaseModelData(); + var json = editorManager.getModel(); + json = JSON.stringify(json); + + var params = { + modeltype: modelMetaData.model.modelType, + json_xml: json, + name: modelMetaData.name, + key: modelMetaData.key, + description: modelMetaData.description, + newversion: false, + lastUpdated: modelMetaData.lastUpdated + }; + + // Update + $http({ method: 'POST', + data: params, + ignoreErrors: true, + headers: {'Accept': 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}, + transformRequest: function (obj) { + var str = []; + for (var p in obj) { + str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); + } + return str.join("&"); + }, + url: FLOWABLE.URL.putModel(modelMetaData.modelId)}) + + .success(function (data, status, headers, config) { + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_SAVED + }); + + $scope.model.loading = false; + $scope.$hide(); + + var allSteps = EDITOR.UTIL.collectSortedElementsFromPrecedingElements($scope.selectedShape); + + $rootScope.addHistoryItem($scope.selectedShape.resourceId); + $location.path('form-editor/' + newFormId); + + }) + .error(function (data, status, headers, config) { + $scope.model.loading = false; + $scope.$hide(); + }); + + }). + error(function(data, status, headers, config) { + $scope.model.loading = false; + $scope.model.errorMessage = data.message; + }); + }; + + $scope.cancel = function() { + $scope.close(); + }; + + $scope.loadForms = function() { + var modelMetaData = editorManager.getBaseModelData(); + $http.get(FLOWABLE.APP_URL.getFormModelsUrl()) + .success( + function(response) { + $scope.state.loadingForms = false; + $scope.state.formError = false; + $scope.forms = response.data; + }) + .error( + function(data, status, headers, config) { + $scope.state.loadingForms = false; + $scope.state.formError = true; + }); + }; + + if ($scope.property && $scope.property.value && $scope.property.value.id) { + $scope.selectedForm = $scope.property.value; + } + + $scope.loadForms(); +}]); diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-httprequest-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-httprequest-controller.js new file mode 100644 index 0000000..c384e62 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-httprequest-controller.js @@ -0,0 +1,24 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowableHttpRequestMethodCtrl', [ '$scope', function($scope) { + + if ($scope.property.value == undefined && $scope.property.value == null) + { + $scope.property.value = 'GET'; + } + + $scope.httpRequestMethodChanged = function() { + $scope.updatePropertyInModel($scope.property); + }; +}]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-in-parameters-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-in-parameters-controller.js new file mode 100644 index 0000000..801a307 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-in-parameters-controller.js @@ -0,0 +1,179 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Input parameters for call activity + */ + +angular.module('flowableModeler').controller('FlowableInParametersCtrl', + ['$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 + _internalCreateModal(opts, $modal, $scope); + }]); + +angular.module('flowableModeler').controller('FlowableInParametersPopupCtrl', + ['$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.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 = []; + } + + $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: $scope.parameters, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{field: 'source', displayName: $scope.labels.sourceLabel}, + {field: 'sourceExpression', displayName: $scope.labels.sourceExpressionLabel}, + {field: 'target', displayName: $scope.labels.targetLabel}] + }; + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedParameter = row.entity; + }); + }; + }); + + // Click handler for add button + $scope.addNewParameter = function () { + var newParameter = { + source: '', + sourceExpression: '', + target: '' + }; + + $scope.parameters.push(newParameter); + + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newParameter); + }); + }; + + // Click handler for remove button + $scope.removeParameter = function () { + + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.parameters.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + $scope.parameters.splice(index, 1); + + if ($scope.parameters.length == 0) { + $scope.selectedParameter = undefined; + } + + $timeout(function () { + if ($scope.parameters.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.parameters[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveParameterUp = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.parameters.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.parameters[index]; + $scope.parameters.splice(index, 1); + $timeout(function () { + $scope.parameters.splice(index + -1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveParameterDown = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.parameters.indexOf(selectedItems[0]); + if (index != $scope.parameters.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.parameters[index]; + $scope.parameters.splice(index, 1); + $timeout(function () { + $scope.parameters.splice(index + 1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // 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(); + }; + + }]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-message-definitions-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-message-definitions-controller.js new file mode 100644 index 0000000..7a80338 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-message-definitions-controller.js @@ -0,0 +1,145 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Execution listeners + */ + +angular.module('flowableModeler').controller('FlowableMessageDefinitionsCtrl', ['$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 + _internalCreateModal(opts, $modal, $scope); +}]); + +//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('flowableModeler').controller('FlowableMessageDefinitionsPopupCtrl', + ['$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.selectedMessageDefinition = undefined; + $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: $scope.messageDefinitions, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [ + {field: 'id', displayName: $scope.labels.idLabel}, + {field: 'name', displayName: $scope.labels.nameLabel}] + }; + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedMessageDefinition = row.entity; + }); + }; + }); + + // Click handler for add button + $scope.addNewMessageDefinition = function () { + var newMessageDefinition = {id: '', name: ''}; + + $scope.messageDefinitions.push(newMessageDefinition); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newMessageDefinition); + }); + }; + + // Click handler for remove button + $scope.removeMessageDefinition = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.messageDefinitions.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + $scope.messageDefinitions.splice(index, 1); + + if ($scope.messageDefinitions.length == 0) { + $scope.selectedMesageDefinition = undefined; + } + + $timeout(function () { + if ($scope.messageDefinitions.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.messageDefinitions[0]); + } + }); + } + }; + + // 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(); + }; + + }]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-message-scope-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-message-scope-controller.js new file mode 100644 index 0000000..91f690b --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-message-scope-controller.js @@ -0,0 +1,41 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +angular.module('flowableModeler').controller('FlowableMessageRefCtrl', [ '$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.get('oryx-messagedefinitions')) { + messageDefinitionsProperty = parent.properties.get('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); + }; +}]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-multiinstance-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-multiinstance-controller.js new file mode 100644 index 0000000..6d90a4e --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-multiinstance-controller.js @@ -0,0 +1,24 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowableMultiInstanceCtrl', [ '$scope', function($scope) { + + if ($scope.property.value == undefined && $scope.property.value == null) + { + $scope.property.value = 'None'; + } + + $scope.multiInstanceChanged = function() { + $scope.updatePropertyInModel($scope.property); + }; +}]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-ordering-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-ordering-controller.js new file mode 100644 index 0000000..241dfc7 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-ordering-controller.js @@ -0,0 +1,28 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Adhoc sub process ordering property + */ + +angular.module('flowableModeler').controller('FlowableOrderingCtrl', [ '$scope', function($scope) { + + if ($scope.property.value == undefined && $scope.property.value == null) + { + $scope.property.value = 'Parallel'; + } + + $scope.orderingChanged = function() { + $scope.updatePropertyInModel($scope.property); + }; +}]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-out-parameters-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-out-parameters-controller.js new file mode 100644 index 0000000..1417a74 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-out-parameters-controller.js @@ -0,0 +1,176 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Input parameters for call activity + */ + +angular.module('flowableModeler').controller('FlowableOutParametersCtrl', + ['$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 + _internalCreateModal(opts, $modal, $scope); + }]); + +angular.module('flowableModeler').controller('FlowableOutParametersPopupCtrl', + ['$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.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 = []; + } + + $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: $scope.parameters, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{field: 'source', displayName: $scope.labels.sourceLabel}, + {field: 'sourceExpression', displayName: $scope.labels.sourceExpressionLabel}, + {field: 'target', displayName: $scope.labels.targetLabel}] + }; + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedParameter = row.entity; + }); + }; + }); + + // Click handler for add button + $scope.addNewParameter = function () { + var newParameter = { + source: '', + sourceExpression: '', + target: ''}; + + $scope.parameters.push(newParameter); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newParameter); + }); + }; + + // Click handler for remove button + $scope.removeParameter = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.parameters.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + $scope.parameters.splice(index, 1); + + if ($scope.parameters.length == 0) { + $scope.selectedParameter = undefined; + } + + $timeout(function () { + if ($scope.parameters.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.parameters[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveParameterUp = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.parameters.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.parameters[index]; + $scope.parameters.splice(index, 1); + $timeout(function () { + $scope.parameters.splice(index + -1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveParameterDown = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.parameters.indexOf(selectedItems[0]); + if (index != $scope.parameters.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.parameters[index]; + $scope.parameters.splice(index, 1); + $timeout(function () { + $scope.parameters.splice(index + 1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // 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(); + }; + + }]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-plan-item-lifecycle-listeners-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-plan-item-lifecycle-listeners-controller.js new file mode 100644 index 0000000..0ae0e0a --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-plan-item-lifecycle-listeners-controller.js @@ -0,0 +1,357 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +angular.module('flowableModeler').controller('FlowablePlanItemLifecycleListenersCtrl', + ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/plan-item-lifecycle-listeners-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); + }]); + +angular.module('flowableModeler').controller('FlowablePlanItemLifecycleListenersPopupCtrl', + ['$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.planItemLifecycleListeners !== undefined + && $scope.property.value.planItemLifecycleListeners !== null) { + + if ($scope.property.value.planItemLifecycleListeners.constructor == String) { + $scope.planItemLifecycleListeners = JSON.parse($scope.property.value.planItemLifecycleListeners); + } + 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.planItemLifecycleListeners = angular.copy($scope.property.value.planItemLifecycleListeners); + } + + for (var i = 0; i < $scope.planItemLifecycleListeners.length; i++) { + var planItemLifeCycleListener = $scope.planItemLifecycleListeners[i]; + if (planItemLifeCycleListener.className !== undefined && planItemLifeCycleListener.className !== '') { + planItemLifeCycleListener.implementation = planItemLifeCycleListener.className; + } + else if (planItemLifeCycleListener.expression !== undefined && planItemLifeCycleListener.expression !== '') { + planItemLifeCycleListener.implementation = planItemLifeCycleListener.expression; + } + else if (planItemLifeCycleListener.delegateExpression !== undefined && planItemLifeCycleListener.delegateExpression !== '') { + planItemLifeCycleListener.implementation = planItemLifeCycleListener.delegateExpression; + } + } + } else { + $scope.planItemLifecycleListeners = []; + } + + $scope.selectedListener = undefined; + $scope.selectedField = undefined; + $scope.fields = []; + $scope.translationsRetrieved = false; + + $scope.labels = {}; + + var sourceStatePromise = $translate('PROPERTY.PLANITEMLIFECYCLELISTENERS.SOURCE_STATE'); + var targetStatePromise = $translate('PROPERTY.PLANITEMLIFECYCLELISTENERS.TARGET_STATE'); + var implementationPromise = $translate('PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.IMPLEMENTATION'); + var namePromise = $translate('PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME'); + + $q.all([sourceStatePromise, targetStatePromise, implementationPromise, namePromise]).then(function (results) { + $scope.labels.sourceStateLabel = results[1]; + $scope.labels.targetStateLabel = results[2]; + $scope.labels.implementationLabel = results[3]; + $scope.labels.nameLabel = results[4]; + $scope.translationsRetrieved = true; + + // Config for grid + $scope.gridOptions = { + data: $scope.planItemLifecycleListeners, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [ + {field: 'sourceState', displayName: $scope.labels.sourceStateLabel}, + {field: 'targetState', displayName: $scope.labels.targetStateLabel}, + {field: 'implementation', displayName: $scope.labels.implementationLabel} + ] + }; + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedListener = row.entity; + $scope.selectedField = undefined; + if ($scope.selectedListener) { + var fields = $scope.selectedListener.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; + } + } + } else { + $scope.selectedListener.fields = []; + } + + $scope.fields.length = 0; + for (var i = 0; i < $scope.selectedListener.fields.length; i++) { + $scope.fields.push($scope.selectedListener.fields[i]); + } + } + }); + }; + + // Config for field grid + $scope.gridFieldOptions = { + data: $scope.fields, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + columnDefs: [{field: 'name', displayName: $scope.labels.name}, + {field: 'implementation', displayName: $scope.labels.implementationLabel}] + }; + + $scope.gridFieldOptions.onRegisterApi = function (gridApi) { + // set gridApi on scope + $scope.fieldGridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedField = row.entity; + }); + }; + }); + + $scope.listenerDetailsChanged = function () { + if ($scope.selectedListener.className !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.className; + } else if ($scope.selectedListener.expression !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.expression; + } else if ($scope.selectedListener.delegateExpression !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.delegateExpression; + } else { + $scope.selectedListener.implementation = ''; + } + }; + + // Click handler for add button + $scope.addNewListener = function () { + var newListener = { + sourceState: 'available', + targetState: 'active', + implementation: '', + className: '', + expression: '', + delegateExpression: '' + }; + $scope.planItemLifecycleListeners.push(newListener); + + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newListener); + }); + }; + + // Click handler for remove button + $scope.removeListener = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.planItemLifecycleListeners.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + + $scope.planItemLifecycleListeners.splice(index, 1); + + if ($scope.planItemLifecycleListeners.length == 0) { + $scope.selectedListener = undefined; + } + + $timeout(function () { + if ($scope.planItemLifecycleListeners.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.planItemLifecycleListeners[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveListenerUp = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.planItemLifecycleListeners.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.planItemLifecycleListeners[index]; + $scope.planItemLifecycleListeners.splice(index, 1); + $timeout(function () { + $scope.planItemLifecycleListeners.splice(index + -1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveListenerDown = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.planItemLifecycleListeners.indexOf(selectedItems[0]); + if (index != $scope.planItemLifecycleListeners.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.planItemLifecycleListeners[index]; + $scope.planItemLifecycleListeners.splice(index, 1); + $timeout(function () { + $scope.planItemLifecycleListeners.splice(index + 1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + + } + } + }; + + $scope.fieldDetailsChanged = function () { + if ($scope.selectedField.stringValue != '') { + $scope.selectedField.implementation = $scope.selectedField.stringValue; + } else if ($scope.selectedField.expression != '') { + $scope.selectedField.implementation = $scope.selectedField.expression; + } else if ($scope.selectedField.string != '') { + $scope.selectedField.implementation = $scope.selectedField.string; + } else { + $scope.selectedField.implementation = ''; + } + }; + + // Click handler for add button + $scope.addNewField = function () { + if ($scope.selectedListener) { + if ($scope.selectedListener.fields == undefined) { + $scope.selectedListener.fields = []; + } + + var newField = { + name: 'fieldName', + implementation: '', + stringValue: '', + expression: '', + string: '' + }; + $scope.fields.push(newField); + $scope.selectedListener.fields.push(newField); + + $timeout(function () { + $scope.fieldGridApi.selection.toggleRowSelection(newField); + }); + } + }; + + // Click handler for remove button + $scope.removeField = function () { + var selectedItems = $scope.fieldGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + $scope.fieldGridApi.selection.toggleRowSelection(selectedItems[0]); + + $scope.fields.splice(index, 1); + $scope.selectedListener.fields.splice(index, 1); + + if ($scope.fields.length == 0) { + $scope.selectedField = undefined; + } + + $timeout(function () { + if ($scope.fields.length > 0) { + $scope.fieldGridApi.selection.toggleRowSelection($scope.fields[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveFieldUp = function () { + var selectedItems = $scope.fieldGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.fields[index]; + $scope.fields.splice(index, 1); + $scope.selectedListener.fields.splice(index, 1); + $timeout(function () { + $scope.fields.splice(index + -1, 0, temp); + $scope.selectedListener.fields.splice(index + -1, 0, temp); + $timeout(function () { + $scope.fieldGridApi.selection.toggleRowSelection(temp); + }); + }); + + } + } + }; + + // Click handler for down button + $scope.moveFieldDown = function () { + var selectedItems = $scope.fieldGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + if (index != $scope.fields.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.fields[index]; + $scope.fields.splice(index, 1); + $scope.selectedListeners.fields.splice(index, 1); + $timeout(function () { + $scope.fields.splice(index + 1, 0, temp); + $scope.selectedListener.fields.splice(index + 1, 0, temp); + $timeout(function () { + $scope.fieldGridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for save button + $scope.save = function () { + + if ($scope.planItemLifecycleListeners.length > 0) { + $scope.property.value = {}; + $scope.property.value.planItemLifecycleListeners = $scope.planItemLifecycleListeners; + } 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(); + }; + + }]); diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-planitem-dropdown-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-planitem-dropdown-controller.js new file mode 100644 index 0000000..ad2bdb5 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-planitem-dropdown-controller.js @@ -0,0 +1,82 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowablePlanItemDropdownCtrl', [ '$scope', function($scope) { + + // Find all planitems + var selectedShape = $scope.selectedShape; + if (selectedShape) { + + // Go up in parent chain until plan model is found + var planModel; + var parent = selectedShape.parent; + if (parent) { + while (planModel === undefined && parent !== null && parent !== undefined) { + if (parent.resourceId !== null && parent.resourceId !== undefined && 'casePlanModel' === parent.resourceId) { + planModel = parent; + } else { + parent = parent.parent; + } + } + } + + var planItems = []; + if (planModel !== null && planModel !== undefined) { + + var toVisit = []; + for (var i=0; i 0) { + var child = toVisit.pop(); + if (typeof child.getStencil === 'function' + && (child.getStencil()._jsonStencil.groups.indexOf('Activities') >= 0 || (child.getStencil()._jsonStencil.title === 'Stage') )) { + planItems.push(child); + } + if (child.children !== null && child.children !== undefined) { + for (var i=0; i 0) { + simplifiedPlanItems.sort(function(a,b) { + if(a.name < b.name) { + return -1; + } else if (a.name > b.name) { + return 1; + } else { + return 0; + } + }); + } + $scope.planItems = simplifiedPlanItems; + + } + + if ($scope.property.value == undefined && $scope.property.value == null) { + $scope.property.value = ''; + } + + $scope.planItemChanged = function() { + $scope.updatePropertyInModel($scope.property); + }; +}]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-process-historylevel-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-process-historylevel-controller.js new file mode 100644 index 0000000..cc5bda7 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-process-historylevel-controller.js @@ -0,0 +1,24 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowableProcessHistoryLevelCtrl', [ '$scope', function($scope) { + + if ($scope.property.value == undefined && $scope.property.value == null) + { + $scope.property.value = 'None'; + } + + $scope.historyLevelChanged = function() { + $scope.updatePropertyInModel($scope.property); + }; +}]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-process-reference-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-process-reference-controller.js new file mode 100644 index 0000000..dd56e22 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-process-reference-controller.js @@ -0,0 +1,80 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowableProcessReferenceCtrl', + [ '$scope', '$modal', '$http', function($scope, $modal, $http) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/process-reference-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); +}]); + +angular.module('flowableModeler').controller('FlowableProcessReferencePopupCtrl', [ '$scope', '$http', function($scope, $http) { + + $scope.state = {'loadingProcesses' : true, 'error' : false}; + + // Close button handler + $scope.close = function() { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + // Selecting/deselecting a process + $scope.selectProcess = function(processModel, $event) { + $event.stopPropagation(); + if ($scope.selectedProcess && $scope.selectedProcess.id && processModel.id == $scope.selectedProcess.id) { + // un-select the current selection + $scope.selectedProcess = null; + } else { + $scope.selectedProcess = processModel; + } + }; + + // Saving the selected value + $scope.save = function() { + if ($scope.selectedProcess) { + $scope.property.value = {'id' : $scope.selectedProcess.id, 'name' : $scope.selectedProcess.name}; + } else { + $scope.property.value = null; + } + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + $scope.loadProcesses = function() { + + $http.get(FLOWABLE.APP_URL.getModelsUrl("?modelType=0")) + .success( + function(response) { + $scope.state.loadingProcesses = false; + $scope.state.processError = false; + $scope.processModels = response.data; + }) + .error( + function(data, status, headers, config) { + $scope.state.loadingProcesses = false; + $scope.state.processError = true; + }); + }; + + if ($scope.property && $scope.property.value && $scope.property.value.id) { + $scope.selectedProcess = $scope.property.value; + } + + $scope.loadProcesses(); +}]); diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-sequenceflow-order-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-sequenceflow-order-controller.js new file mode 100644 index 0000000..a37c8c4 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-sequenceflow-order-controller.js @@ -0,0 +1,126 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Sequence flow order controller + */ + +angular.module('flowableModeler').controller('FlowableSequenceFlowOrderCtrl', + [ '$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 + }; + + _internalCreateModal(opts, $modal, $scope); +}]); + +angular.module('flowableModeler').controller('FlowableSequenceFlowOrderPopupCtrl', + ['$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 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(); + }; + +}]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-signal-definitions-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-signal-definitions-controller.js new file mode 100644 index 0000000..63320ff --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-signal-definitions-controller.js @@ -0,0 +1,151 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Execution listeners + */ + +angular.module('flowableModeler').controller('FlowableSignalDefinitionsCtrl', ['$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 + _internalCreateModal(opts, $modal, $scope); +}]); + +//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('flowableModeler').controller('FlowableSignalDefinitionsPopupCtrl', + ['$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.selectedSignalDefinition = undefined; + $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: $scope.signalDefinitions, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [ + {field: 'id', displayName: $scope.labels.idLabel}, + {field: 'name', displayName: $scope.labels.nameLabel}, + {field: 'scope', displayName: $scope.labels.scopeLabel}] + }; + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedSignalDefinition = row.entity; + }); + }; + }); + + // Click handler for add button + $scope.addNewSignalDefinition = function () { + var newSignalDefinition = {id: '', name: '', scope: 'global'}; + + $scope.signalDefinitions.push(newSignalDefinition); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newSignalDefinition); + }); + }; + + // Click handler for remove button + $scope.removeSignalDefinition = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.signalDefinitions.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + $scope.signalDefinitions.splice(index, 1); + + if ($scope.signalDefinitions.length == 0) { + $scope.selectedSignalDefinition = undefined; + } + + $timeout(function () { + if ($scope.signalDefinitions.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.signalDefinitions[0]); + } + }); + } + }; + + $scope.scopeOptions = [{'value': 'global', 'translationId': 'PROPERTY.SIGNALDEFINITIONS.SCOPE-GLOBAL'}, + {'value': 'processInstance', 'translationId': 'PROPERTY.SIGNALDEFINITIONS.SCOPE-PROCESSINSTANCE'}]; + + // 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(); + }; + + }]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-signal-scope-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-signal-scope-controller.js new file mode 100644 index 0000000..c161991 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-signal-scope-controller.js @@ -0,0 +1,42 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowableSignalRefCtrl', [ '$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.get('oryx-signaldefinitions')) { + signalDefinitionsProperty = parent.properties.get('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); + }; +}]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-task-listeners-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-task-listeners-controller.js new file mode 100644 index 0000000..1c5717d --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-task-listeners-controller.js @@ -0,0 +1,356 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Task listeners + */ + +angular.module('flowableModeler').controller('FlowableTaskListenersCtrl', + ['$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 + _internalCreateModal(opts, $modal, $scope); + }]); + +angular.module('flowableModeler').controller('FlowableTaskListenersPopupCtrl', + ['$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.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 = []; + } + + $scope.selectedListener = undefined; + $scope.selectedField = undefined; + $scope.fields = []; + $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: $scope.taskListeners, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{field: 'event', displayName: $scope.labels.eventLabel}, + {field: 'implementation', displayName: $scope.labels.implementationLabel}] + }; + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedListener = row.entity; + $scope.selectedField = undefined; + if ($scope.selectedListener) { + var fields = $scope.selectedListener.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; + } + } + } else { + $scope.selectedListener.fields = []; + } + + $scope.fields.length = 0; + for (var i = 0; i < $scope.selectedListener.fields.length; i++) { + $scope.fields.push($scope.selectedListener.fields[i]); + } + } + }); + }; + + // Config for field grid + $scope.gridFieldOptions = { + data: $scope.fields, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + columnDefs: [{field: 'name', displayName: $scope.labels.name}, + {field: 'implementation', displayName: $scope.labels.implementationLabel}] + }; + + $scope.gridFieldOptions.onRegisterApi = function (gridApi) { + // set gridApi on scope + $scope.fieldGridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedField = row.entity; + }); + }; + }); + + $scope.listenerDetailsChanged = function () { + if ($scope.selectedListener.className !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.className; + } else if ($scope.selectedListener.expression !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.expression; + } else if ($scope.selectedListener.delegateExpression !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.delegateExpression; + } else { + $scope.selectedListener.implementation = ''; + } + }; + + // Click handler for add button + $scope.addNewListener = function () { + var newListener = { + event: 'create', + implementation: '', + className: '', + expression: '', + delegateExpression: '' + }; + $scope.taskListeners.push(newListener); + + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newListener); + }); + }; + + // Click handler for remove button + $scope.removeListener = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.taskListeners.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + + $scope.taskListeners.splice(index, 1); + + if ($scope.taskListeners.length == 0) { + $scope.selectedListener = undefined; + } + + $timeout(function () { + if ($scope.taskListeners.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.taskListeners[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveListenerUp = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.taskListeners.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.taskListeners[index]; + $scope.taskListeners.splice(index, 1); + $timeout(function () { + $scope.taskListeners.splice(index + -1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveListenerDown = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.taskListeners.indexOf(selectedItems[0]); + if (index != $scope.taskListeners.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.taskListeners[index]; + $scope.taskListeners.splice(index, 1); + $timeout(function () { + $scope.taskListeners.splice(index + 1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + + } + } + }; + + $scope.fieldDetailsChanged = function () { + if ($scope.selectedField.stringValue != '') { + $scope.selectedField.implementation = $scope.selectedField.stringValue; + } else if ($scope.selectedField.expression != '') { + $scope.selectedField.implementation = $scope.selectedField.expression; + } else if ($scope.selectedField.string != '') { + $scope.selectedField.implementation = $scope.selectedField.string; + } else { + $scope.selectedField.implementation = ''; + } + }; + + // Click handler for add button + $scope.addNewField = function () { + if ($scope.selectedListener) { + if ($scope.selectedListener.fields == undefined) { + $scope.selectedListener.fields = []; + } + + var newField = { + name: 'fieldName', + implementation: '', + stringValue: '', + expression: '', + string: '' + }; + $scope.fields.push(newField); + $scope.selectedListener.fields.push(newField); + + $timeout(function () { + $scope.fieldGridApi.selection.toggleRowSelection(newField); + }); + } + }; + + // Click handler for remove button + $scope.removeField = function () { + var selectedItems = $scope.fieldGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + $scope.fieldGridApi.selection.toggleRowSelection(selectedItems[0]); + + $scope.fields.splice(index, 1); + $scope.selectedListener.fields.splice(index, 1); + + if ($scope.fields.length == 0) { + $scope.selectedField = undefined; + } + + $timeout(function () { + if ($scope.fields.length > 0) { + $scope.fieldGridApi.selection.toggleRowSelection($scope.fields[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveFieldUp = function () { + var selectedItems = $scope.fieldGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.fields[index]; + $scope.fields.splice(index, 1); + $scope.selectedListener.fields.splice(index, 1); + $timeout(function () { + $scope.fields.splice(index + -1, 0, temp); + $scope.selectedListener.fields.splice(index + -1, 0, temp); + $timeout(function () { + $scope.fieldGridApi.selection.toggleRowSelection(temp); + }); + }); + + } + } + }; + + // Click handler for down button + $scope.moveFieldDown = function () { + var selectedItems = $scope.fieldGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + if (index != $scope.fields.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.fields[index]; + $scope.fields.splice(index, 1); + $scope.selectedListeners.fields.splice(index, 1); + $timeout(function () { + $scope.fields.splice(index + 1, 0, temp); + $scope.selectedListener.fields.splice(index + 1, 0, temp); + $timeout(function () { + $scope.fieldGridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // 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(); + }; + + }]); diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-transition-event-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-transition-event-controller.js new file mode 100644 index 0000000..59a33ab --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-transition-event-controller.js @@ -0,0 +1,27 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Execution listeners + */ + +angular.module('flowableModeler').controller('FlowableTransitionEventCtrl', [ '$scope', function($scope) { + + if ($scope.property.value == undefined && $scope.property.value == null) { + $scope.property.value = 'complete'; + } + + $scope.transitionEventChanged = function() { + $scope.updatePropertyInModel($scope.property); + }; +}]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties-trigger-mode-controller.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-trigger-mode-controller.js new file mode 100644 index 0000000..a16041c --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties-trigger-mode-controller.js @@ -0,0 +1,23 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowableTriggerModeCtrl', [ '$scope', function($scope) { + + if ($scope.property.value === undefined || $scope.property.value == null) { + $scope.property.value = 'default'; + } + + $scope.triggerModeChanged = function() { + $scope.updatePropertyInModel($scope.property); + }; +}]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties.js b/snow-flowable/src/main/resources/static/editor-app/configuration/properties.js new file mode 100644 index 0000000..8b7c264 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties.js @@ -0,0 +1,157 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +var FLOWABLE = FLOWABLE || {}; +FLOWABLE.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" + }, + "flowable-calledelementtype" : { + "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/calledelementtype-property-write-template.html" + }, + "flowable-multiinstance" : { + "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/multiinstance-property-write-template.html" + }, + "flowable-processhistorylevel" : { + "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/process-historylevel-property-write-template.html" + }, + "flowable-ordering" : { + "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/ordering-property-write-template.html" + }, + "oryx-dataproperties-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/data-properties-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/data-properties-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-subprocess-link": { + "readModeTemplateUrl": "editor-app/configuration/properties/subprocess-reference-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/subprocess-reference-write-template.html" + }, + "oryx-formreference-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/form-reference-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/form-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" + }, + "oryx-duedatedefinition-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/duedate-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/duedate-write-template.html" + }, + "oryx-decisiontaskdecisiontablereference-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/decisiontable-reference-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/decisiontable-reference-write-template.html" + }, + "oryx-casetaskcasereference-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/case-reference-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/case-reference-write-template.html" + }, + "oryx-processtaskprocessreference-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/process-reference-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/process-reference-write-template.html" + }, + "oryx-processtaskinparameters-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/in-parameters-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/in-parameters-write-template.html" + }, + "oryx-processtaskoutparameters-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/out-parameters-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/out-parameters-write-template.html" + }, + "oryx-planitemlifecyclelisteners-multiplecomplex": { + "readModeTemplateUrl": "editor-app/configuration/properties/plan-item-lifecycle-listeners-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/plan-item-lifecycle-listeners-write-template.html" + }, + "flowable-transitionevent" : { + "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/transition-event-write-template.html" + }, + "flowable-planitem-dropdown" : { + "readModeTemplateUrl": "editor-app/configuration/properties/planitem-dropdown-read-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/planitem-dropdown-write-template.html" + }, + "flowable-http-request-method" : { + "readModeTemplateUrl": "editor-app/configuration/properties/http-request-method-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/http-request-method-property-write-template.html" + }, + "flowable-triggermode" : { + "readModeTemplateUrl": "editor-app/configuration/properties/trigger-mode-read-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/trigger-mode-write-template.html" + }, +}; diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/assignment-display-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/assignment-display-template.html new file mode 100644 index 0000000..bbe6989 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/assignment-display-template.html @@ -0,0 +1,15 @@ + +{{'PROPERTY.ASSIGNMENT.ASSIGNEE_DISPLAY' | translate:property.value.assignment }} +{{'PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY' | translate:property.value.assignment.candidateUsers}} +{{'PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY' | translate:property.value.assignment.candidateGroups}} +{{'PROPERTY.ASSIGNMENT.USER_IDM_DISPLAY' | translate:property.value.assignment.idm.assignee }} +{{'PROPERTY.ASSIGNMENT.USER_IDM_EMAIL_DISPLAY' | translate:property.value.assignment.idm.assignee }} +{{'PROPERTY.ASSIGNMENT.USER_IDM_FIELD_DISPLAY' | translate:property.value.assignment.idm.assigneeField }} +{{'PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY' | translate:property.value.assignment.idm.candidateUsers}} +{{'PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY' | translate:property.value.assignment.idm.candidateGroups}} +{{'PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY' | translate:property.value.assignment.idm.candidateUserFields}} +{{'PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY' | translate:property.value.assignment.idm.candidateGroupFields}} +{{'PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY' | translate:property.value.assignment.idm.candidateUserFields.concat(property.value.assignment.idm.candidateUsers)}} +{{'PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY' | translate:property.value.assignment.idm.candidateGroupFields.concat(property.value.assignment.idm.candidateGroups)}} +PROPERTY.ASSIGNMENT.EMPTY +PROPERTY.ASSIGNMENT.IDM_EMPTY \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/assignment-popup.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/assignment-popup.html new file mode 100644 index 0000000..8089e45 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/assignment-popup.html @@ -0,0 +1,268 @@ +
diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/fields-write-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/fields-write-template.html new file mode 100644 index 0000000..fdc03b7 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/fields-write-template.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/form-properties-display-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/form-properties-display-template.html new file mode 100644 index 0000000..1274342 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/form-properties-display-template.html @@ -0,0 +1,3 @@ + +{{'PROPERTY.FORMPROPERTIES.VALUE' | translate:property.value.formProperties}} +PROPERTY.FORMPROPERTIES.EMPTY \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/form-properties-popup.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/form-properties-popup.html new file mode 100644 index 0000000..c16ed86 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/form-properties-popup.html @@ -0,0 +1,121 @@ + + diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/form-properties-write-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/form-properties-write-template.html new file mode 100644 index 0000000..0449718 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/form-properties-write-template.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/form-reference-display-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/form-reference-display-template.html new file mode 100644 index 0000000..15444f6 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/form-reference-display-template.html @@ -0,0 +1,4 @@ +
+ {{form.name}} + PROPERTY.FORMREFERENCE.EMPTY +
diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/form-reference-popup.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/form-reference-popup.html new file mode 100644 index 0000000..6c0a2db --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/form-reference-popup.html @@ -0,0 +1,74 @@ + + diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/form-reference-write-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/form-reference-write-template.html new file mode 100644 index 0000000..abb945f --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/form-reference-write-template.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/http-request-method-display-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/http-request-method-display-template.html new file mode 100644 index 0000000..2306527 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/http-request-method-display-template.html @@ -0,0 +1,3 @@ + +{{property.value}} +GET \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/http-request-method-property-write-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/http-request-method-property-write-template.html new file mode 100644 index 0000000..3a6e2b0 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/http-request-method-property-write-template.html @@ -0,0 +1,8 @@ +
+ +
\ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/in-parameters-display-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/in-parameters-display-template.html new file mode 100644 index 0000000..961e637 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/in-parameters-display-template.html @@ -0,0 +1,3 @@ + +{{'PROPERTY.INPARAMETERS.VALUE' | translate:property.value.inParameters}} +PROPERTY.INPARAMETERS.EMPTY \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/in-parameters-popup.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/in-parameters-popup.html new file mode 100644 index 0000000..51958fc --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/in-parameters-popup.html @@ -0,0 +1,53 @@ + + diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/in-parameters-write-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/in-parameters-write-template.html new file mode 100644 index 0000000..d6e1872 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/in-parameters-write-template.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/message-definitions-display-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/message-definitions-display-template.html new file mode 100644 index 0000000..2a0f3e7 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/message-definitions-display-template.html @@ -0,0 +1,3 @@ + +{{'PROPERTY.MESSAGEDEFINITIONS.DISPLAY' | translate:property.value}} +PROPERTY.MESSAGEDEFINITIONS.EMPTY \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/message-definitions-popup.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/message-definitions-popup.html new file mode 100644 index 0000000..c93cce9 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/message-definitions-popup.html @@ -0,0 +1,49 @@ + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/message-definitions-write-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/message-definitions-write-template.html new file mode 100644 index 0000000..76e7b88 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/message-definitions-write-template.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/message-property-write-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/message-property-write-template.html new file mode 100644 index 0000000..8e38ea3 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/message-property-write-template.html @@ -0,0 +1,4 @@ +
+ +
\ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/multiinstance-property-write-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/multiinstance-property-write-template.html new file mode 100644 index 0000000..16c36e9 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/multiinstance-property-write-template.html @@ -0,0 +1,8 @@ + +
+ +
\ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/ordering-property-write-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/ordering-property-write-template.html new file mode 100644 index 0000000..150be20 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/ordering-property-write-template.html @@ -0,0 +1,7 @@ + +
+ +
\ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/out-parameters-display-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/out-parameters-display-template.html new file mode 100644 index 0000000..859b2e4 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/out-parameters-display-template.html @@ -0,0 +1,3 @@ + +{{'PROPERTY.OUTPARAMETERS.VALUE' | translate:property.value.outParameters}} +PROPERTY.OUTPARAMETERS.EMPTY \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/out-parameters-popup.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/out-parameters-popup.html new file mode 100644 index 0000000..7f4df02 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/out-parameters-popup.html @@ -0,0 +1,53 @@ + + diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/out-parameters-write-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/out-parameters-write-template.html new file mode 100644 index 0000000..ea6986a --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/out-parameters-write-template.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/plan-item-lifecycle-listeners-display-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/plan-item-lifecycle-listeners-display-template.html new file mode 100644 index 0000000..88ffb8b --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/plan-item-lifecycle-listeners-display-template.html @@ -0,0 +1,3 @@ + +{{'PROPERTY.PLANITEMLIFECYCLELISTENERS.VALUE' | translate:property.value.planItemLifecycleListeners}} +PROPERTY.PLANITEMLIFECYCLELISTENERS.EMPTY \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/plan-item-lifecycle-listeners-popup.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/plan-item-lifecycle-listeners-popup.html new file mode 100644 index 0000000..9679c41 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/plan-item-lifecycle-listeners-popup.html @@ -0,0 +1,125 @@ + + diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/plan-item-lifecycle-listeners-write-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/plan-item-lifecycle-listeners-write-template.html new file mode 100644 index 0000000..f073c11 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/plan-item-lifecycle-listeners-write-template.html @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/planitem-dropdown-read-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/planitem-dropdown-read-template.html new file mode 100644 index 0000000..6edb2a2 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/planitem-dropdown-read-template.html @@ -0,0 +1,4 @@ + +{{property.value.name|limitTo:20}} +... +PROPERTY.EMPTY \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/planitem-dropdown-write-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/planitem-dropdown-write-template.html new file mode 100644 index 0000000..2ca6944 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/planitem-dropdown-write-template.html @@ -0,0 +1,5 @@ + +
+ +
\ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/process-historylevel-property-write-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/process-historylevel-property-write-template.html new file mode 100644 index 0000000..bd4efa1 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/process-historylevel-property-write-template.html @@ -0,0 +1,10 @@ + +
+ +
\ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/process-reference-display-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/process-reference-display-template.html new file mode 100644 index 0000000..9447d08 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/process-reference-display-template.html @@ -0,0 +1,3 @@ + +{{property.value.name}} +PROPERTY.PROCESSREFERENCE.EMPTY diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/process-reference-popup.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/process-reference-popup.html new file mode 100644 index 0000000..a8b3067 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/process-reference-popup.html @@ -0,0 +1,45 @@ + + diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/process-reference-write-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/process-reference-write-template.html new file mode 100644 index 0000000..56461a1 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/process-reference-write-template.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/sequenceflow-order-display-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/sequenceflow-order-display-template.html new file mode 100644 index 0000000..90f50e9 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/sequenceflow-order-display-template.html @@ -0,0 +1,3 @@ + +PROPERTY.SEQUENCEFLOW.ORDER.NOT.EMPTY +PROPERTY.SEQUENCEFLOW.ORDER.EMPTY \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/sequenceflow-order-popup.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/sequenceflow-order-popup.html new file mode 100644 index 0000000..2bc6542 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/sequenceflow-order-popup.html @@ -0,0 +1,47 @@ + + diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/sequenceflow-order-write-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/sequenceflow-order-write-template.html new file mode 100644 index 0000000..dd56210 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/sequenceflow-order-write-template.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/signal-definitions-display-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/signal-definitions-display-template.html new file mode 100644 index 0000000..7fa105b --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/signal-definitions-display-template.html @@ -0,0 +1,3 @@ + +{{'PROPERTY.SIGNALDEFINITIONS.DISPLAY' | translate:property.value}} +PROPERTY.SIGNALDEFINITIONS.EMPTY \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/signal-definitions-popup.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/signal-definitions-popup.html new file mode 100644 index 0000000..5f21ed7 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/signal-definitions-popup.html @@ -0,0 +1,56 @@ + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/signal-definitions-write-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/signal-definitions-write-template.html new file mode 100644 index 0000000..0ee1953 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/signal-definitions-write-template.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/signal-property-write-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/signal-property-write-template.html new file mode 100644 index 0000000..b8da432 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/signal-property-write-template.html @@ -0,0 +1,4 @@ +
+ +
\ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/string-property-write-mode-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/string-property-write-mode-template.html new file mode 100644 index 0000000..62c3323 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/string-property-write-mode-template.html @@ -0,0 +1,9 @@ + +
+ +
\ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/task-listeners-display-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/task-listeners-display-template.html new file mode 100644 index 0000000..4d07171 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/task-listeners-display-template.html @@ -0,0 +1,3 @@ + +{{'PROPERTY.TASKLISTENERS.VALUE' | translate:property.value.taskListeners}} +PROPERTY.TASKLISTENERS.EMPTY \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/task-listeners-popup.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/task-listeners-popup.html new file mode 100644 index 0000000..1c50b5a --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/task-listeners-popup.html @@ -0,0 +1,102 @@ + + diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/task-listeners-write-template.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/task-listeners-write-template.html new file mode 100644 index 0000000..dda53a1 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/task-listeners-write-template.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/configuration/properties/text-popup.html b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/text-popup.html new file mode 100644 index 0000000..98bab62 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/configuration/properties/text-popup.html @@ -0,0 +1,17 @@ + + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/popups/select-shape.html b/snow-flowable/src/main/resources/static/editor-app/popups/select-shape.html new file mode 100644 index 0000000..ad4ba81 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/popups/select-shape.html @@ -0,0 +1,18 @@ + + diff --git a/snow-flowable/src/main/resources/static/editor-app/popups/unsaved-changes.html b/snow-flowable/src/main/resources/static/editor-app/popups/unsaved-changes.html new file mode 100644 index 0000000..45325c0 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/popups/unsaved-changes.html @@ -0,0 +1,23 @@ + + diff --git a/snow-flowable/src/main/resources/static/editor-app/popups/validate-model.html b/snow-flowable/src/main/resources/static/editor-app/popups/validate-model.html new file mode 100644 index 0000000..824e5e7 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/popups/validate-model.html @@ -0,0 +1,18 @@ + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/process-navigator-controller.js b/snow-flowable/src/main/resources/static/editor-app/process-navigator-controller.js new file mode 100644 index 0000000..fe9ff29 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/process-navigator-controller.js @@ -0,0 +1,81 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('ProcessNavigatorController',['editorManager', '$scope',function(editorManager, $scope){ + //problem here the ORYX editor is bound to the rootscope. In theory this communication should be moved to a service. + + $scope.showSubProcess = function(child){ + var flowableShapes = editorManager.getChildShapeByResourceId(child.resourceId); + editorManager.setSelection([flowableShapes],[],true); + } + + $scope.treeview = {}; + $scope.isEditorReady = false; + + $scope.edit = function(resourceId){ + editorManager.edit(resourceId); + }; + + FLOWABLE.eventBus.addListener(FLOWABLE.eventBus.EVENT_TYPE_EDITOR_READY, function(event){ + $scope.isEditorReady = true; + renderProcessHierarchy(); + + editorManager.registerOnEvent(ORYX.CONFIG.ACTION_DELETE_COMPLETED, filterEvent); + + //always a single event. + editorManager.registerOnEvent(ORYX.CONFIG.EVENT_UNDO_ROLLBACK, renderProcessHierarchy); + }) + + //if an element is added te properties will catch this event. + FLOWABLE.eventBus.addListener(FLOWABLE.eventBus.EVENT_TYPE_PROPERTY_VALUE_CHANGED,filterEvent); + FLOWABLE.eventBus.addListener(FLOWABLE.eventBus.EVENT_TYPE_ITEM_DROPPED,filterEvent); + FLOWABLE.eventBus.addListener("EDITORMANAGER-EDIT-ACTION",function(){ + renderProcessHierarchy(); + }); + + function filterEvent(event){ + //this event is fired when the user changes a property by the property editor. + if(event.type === "event-type-property-value-changed"){ + if(event.property.key === "oryx-overrideid" || event.property.key === "oryx-name"){ + renderProcessHierarchy() + } + //this event is fired when the stencil / shape's text is changed / updated. + }else if(event.type === "propertyChanged"){ + if(event.name === "oryx-overrideid" || event.name === "oryx-name"){ + renderProcessHierarchy(); + } + }else if(event.type === ORYX.CONFIG.ACTION_DELETE_COMPLETED){ + renderProcessHierarchy(); + //for some reason the new tree does not trigger an ui update. + //$scope.$apply(); + }else if(event.type === "event-type-item-dropped"){ + renderProcessHierarchy(); + } + } + + function renderProcessHierarchy(){ + //only start calculating when the editor has done all his constructor work. + if(!$scope.isEditorReady){ + return false; + } + + if (!editorManager.isLoading()){ + //the current implementation of has a lot of eventlisteners. when calling getTree() it could manipulate + //the canvastracker while the canvas is stille loading stuff. + //TODO: check if its possible to trigger the re-rendering by a single event instead of registering on 10 events... + $scope.treeview = editorManager.getTree(); + } + + } + +}]); diff --git a/snow-flowable/src/main/resources/static/editor-app/select-shape-controller.js b/snow-flowable/src/main/resources/static/editor-app/select-shape-controller.js new file mode 100644 index 0000000..d752e07 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/select-shape-controller.js @@ -0,0 +1,318 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Controller for morph shape selection + */ + +angular.module('flowableModeler').controller('FlowableBpmShapeSelectionCtrl', + [ '$rootScope', '$scope', '$timeout', '$translate', 'editorManager', function($rootScope, $scope, $timeout, $translate, editorManager) { + + $scope.currentSelectedMorph = undefined; + + $scope.availableMorphShapes = []; + + for (var i = 0; i < $scope.morphShapes.length; i++) { + if ($scope.morphShapes[i].id != $scope.currentSelectedShape.getStencil().idWithoutNs()) { + $scope.availableMorphShapes.push($scope.morphShapes[i]); + } + } + + // Config for grid + $scope.gridOptions = { + data: $scope.availableMorphShapes, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{ field: 'objectId', displayName: 'Icon', width: 50, cellTemplate: 'editor-app/popups/icon-template.html?version=' + Date.now() }, + { field: 'name', displayName: 'Name', cellTemplate: '
{{"" + row.entity[col.field] | translate}}
'}] + }; + + $scope.gridOptions.onRegisterApi = function(gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function(row) { + if (row.isSelected) { + $scope.currentSelectedMorph = row.entity; + } else { + $scope.currentSelectedMorph = undefined; + } + }); + }; + + // Click handler for save button + $scope.select = function() { + + if ($scope.currentSelectedMorph) { + var MorphTo = ORYX.Core.Command.extend({ + construct: function(shape, stencil, facade){ + this.shape = shape; + this.stencil = stencil; + this.facade = facade; + }, + execute: function(){ + + var shape = this.shape; + var stencil = this.stencil; + var resourceId = shape.resourceId; + + // Serialize all attributes + var serialized = shape.serialize(); + stencil.properties().each((function(prop) { + if(prop.readonly()) { + serialized = serialized.reject(function(serProp) { + return serProp.name==prop.id(); + }); + } + }).bind(this)); + + // Get shape if already created, otherwise create a new shape + if (this.newShape){ + newShape = this.newShape; + this.facade.getCanvas().add(newShape); + } else { + newShape = this.facade.createShape({ + type: stencil.id(), + namespace: stencil.namespace(), + resourceId: resourceId + }); + } + + // calculate new bounds using old shape's upperLeft and new shape's width/height + var boundsObj = serialized.find(function(serProp){ + return (serProp.prefix === "oryx" && serProp.name === "bounds"); + }); + + var changedBounds = null; + + if (!this.facade.getRules().preserveBounds(shape.getStencil())) { + + var bounds = boundsObj.value.split(","); + if (parseInt(bounds[0], 10) > parseInt(bounds[2], 10)) { // if lowerRight comes first, swap array items + var tmp = bounds[0]; + bounds[0] = bounds[2]; + bounds[2] = tmp; + tmp = bounds[1]; + bounds[1] = bounds[3]; + bounds[3] = tmp; + } + bounds[2] = parseInt(bounds[0], 10) + newShape.bounds.width(); + bounds[3] = parseInt(bounds[1], 10) + newShape.bounds.height(); + boundsObj.value = bounds.join(","); + + } else { + + var height = shape.bounds.height(); + var width = shape.bounds.width(); + + // consider the minimum and maximum size of + // the new shape + + if (newShape.minimumSize) { + if (shape.bounds.height() < newShape.minimumSize.height) { + height = newShape.minimumSize.height; + } + + + if (shape.bounds.width() < newShape.minimumSize.width) { + width = newShape.minimumSize.width; + } + } + + if (newShape.maximumSize) { + if (shape.bounds.height() > newShape.maximumSize.height) { + height = newShape.maximumSize.height; + } + + if (shape.bounds.width() > newShape.maximumSize.width) { + width = newShape.maximumSize.width; + } + } + + changedBounds = { + a : { + x: shape.bounds.a.x, + y: shape.bounds.a.y + }, + b : { + x: shape.bounds.a.x + width, + y: shape.bounds.a.y + height + } + }; + + } + + var oPos = shape.bounds.center(); + if (changedBounds !== null) { + newShape.bounds.set(changedBounds); + } + + // Set all related dockers + this.setRelatedDockers(shape, newShape); + + // store DOM position of old shape + var parentNode = shape.node.parentNode; + var nextSibling = shape.node.nextSibling; + + // Delete the old shape + this.facade.deleteShape(shape); + + // Deserialize the new shape - Set all attributes + newShape.deserialize(serialized); + /* + * Change color to default if unchanged + * 23.04.2010 + */ + if (shape.getStencil().property("oryx-bgcolor") + && shape.properties["oryx-bgcolor"] + && shape.getStencil().property("oryx-bgcolor").value().toUpperCase()== shape.properties["oryx-bgcolor"].toUpperCase()){ + if (newShape.getStencil().property("oryx-bgcolor")){ + newShape.setProperty("oryx-bgcolor", newShape.getStencil().property("oryx-bgcolor").value()); + } + } + + if (changedBounds !== null) { + newShape.bounds.set(changedBounds); + } + + if (newShape.getStencil().type()==="edge" || (newShape.dockers.length==0 || !newShape.dockers[0].getDockedShape())) { + newShape.bounds.centerMoveTo(oPos); + } + + if (newShape.getStencil().type()==="node" && (newShape.dockers.length==0 || !newShape.dockers[0].getDockedShape())) { + this.setRelatedDockers(newShape, newShape); + + } + + // place at the DOM position of the old shape + if(nextSibling) parentNode.insertBefore(newShape.node, nextSibling); + else parentNode.appendChild(newShape.node); + + // Set selection + this.facade.setSelection([newShape]); + this.facade.getCanvas().update(); + this.facade.updateSelection(); + this.newShape = newShape; + + }, + rollback: function(){ + + if (!this.shape || !this.newShape || !this.newShape.parent) {return;} + + // Append shape to the parent + this.newShape.parent.add(this.shape); + // Set dockers + this.setRelatedDockers(this.newShape, this.shape); + // Delete new shape + this.facade.deleteShape(this.newShape); + // Set selection + this.facade.setSelection([this.shape]); + // Update + this.facade.getCanvas().update(); + this.facade.updateSelection(); + }, + + /** + * Set all incoming and outgoing edges from the shape to the new shape + * @param {Shape} shape + * @param {Shape} newShape + */ + setRelatedDockers: function(shape, newShape){ + + if(shape.getStencil().type()==="node") { + + (shape.incoming||[]).concat(shape.outgoing||[]) + .each(function(i) { + i.dockers.each(function(docker) { + if (docker.getDockedShape() == shape) { + var rPoint = Object.clone(docker.referencePoint); + // Move reference point per percent + + var rPointNew = { + x: rPoint.x*newShape.bounds.width()/shape.bounds.width(), + y: rPoint.y*newShape.bounds.height()/shape.bounds.height() + }; + + docker.setDockedShape(newShape); + // Set reference point and center to new position + docker.setReferencePoint(rPointNew); + if(i instanceof ORYX.Core.Edge) { + docker.bounds.centerMoveTo(rPointNew); + } else { + var absXY = shape.absoluteXY(); + docker.bounds.centerMoveTo({x:rPointNew.x+absXY.x, y:rPointNew.y+absXY.y}); + //docker.bounds.moveBy({x:rPointNew.x-rPoint.x, y:rPointNew.y-rPoint.y}); + } + } + }); + }); + + // for attached events + if(shape.dockers.length>0&&shape.dockers.first().getDockedShape()) { + newShape.dockers.first().setDockedShape(shape.dockers.first().getDockedShape()); + newShape.dockers.first().setReferencePoint(Object.clone(shape.dockers.first().referencePoint)); + } + + } else { // is edge + newShape.dockers.first().setDockedShape(shape.dockers.first().getDockedShape()); + newShape.dockers.first().setReferencePoint(shape.dockers.first().referencePoint); + newShape.dockers.last().setDockedShape(shape.dockers.last().getDockedShape()); + newShape.dockers.last().setReferencePoint(shape.dockers.last().referencePoint); + } + } + }); + + var stencil = undefined; + var stencilSets = editorManager.getStencilSets().values(); + + var stencilId = $scope.currentSelectedMorph.id; + if ($scope.currentSelectedMorph.genericTaskId) { + stencilId = $scope.currentSelectedMorph.genericTaskId; + } + + for (var i = 0; i < stencilSets.length; i++) { + var stencilSet = stencilSets[i]; + var nodes = stencilSet.nodes(); + for (var j = 0; j < nodes.length; j++) { + if (nodes[j].idWithoutNs() === stencilId) { + stencil = nodes[j]; + break; + } + } + } + + if (!stencil) return; + + // Create and execute command (for undo/redo) + var command = new MorphTo($scope.currentSelectedShape, stencil, editorManager.getEditor()); + editorManager.executeCommands([command]); + } + + $scope.close(); + }; + + $scope.cancel = function() { + $scope.$hide(); + }; + + // Close button handler + $scope.close = function() { + $scope.$hide(); + }; + +}]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/stencil-controller.js b/snow-flowable/src/main/resources/static/editor-app/stencil-controller.js new file mode 100644 index 0000000..cf20a33 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/stencil-controller.js @@ -0,0 +1,1488 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +angular.module('flowableModeler') + .controller('StencilController', ['$rootScope', '$scope', '$http', '$modal', '$timeout', '$window', 'editorManager', + function ($rootScope, $scope, $http, $modal, $timeout, $window, editorManager) { + + // Property window toggle state + $scope.propertyWindowState = {'collapsed': false}; + + // Add reference to global header-config + $scope.headerConfig = FLOWABLE.HEADER_CONFIG; + + $scope.propertyWindowState.toggle = function () { + $scope.propertyWindowState.collapsed = !$scope.propertyWindowState.collapsed; + $timeout(function () { + $window.dispatchEvent(new Event("resize")); + }, 100); + }; + + // Code that is dependent on an initialised Editor is wrapped in a promise for the editor + $scope.editorFactory.promise.then(function () { + + /* Build stencil item list */ + + // Build simple json representation of stencil set + var stencilItemGroups = []; + + // Helper method: find a group in an array + var findGroup = function (name, groupArray) { + for (var index = 0; index < groupArray.length; index++) { + if (groupArray[index].name === name) { + return groupArray[index]; + } + } + return null; + }; + + // Helper method: add a new group to an array of groups + var addGroup = function (groupName, groupArray) { + var group = { name: groupName, items: [], paletteItems: [], groups: [], visible: true }; + groupArray.push(group); + return group; + }; + + /* + StencilSet items + */ + var data = editorManager.getStencilData(); + + var quickMenuDefinition = undefined; + var ignoreForPaletteDefinition = undefined; + + if (data.namespace == 'http://b3mn.org/stencilset/cmmn1.1#') { + quickMenuDefinition = ['HumanTask', 'Association']; + ignoreForPaletteDefinition = ['CasePlanModel']; + + } else { + quickMenuDefinition = ['UserTask', 'EndNoneEvent', 'ExclusiveGateway', + 'CatchTimerEvent', 'ThrowNoneEvent', 'TextAnnotation', + 'SequenceFlow', 'Association']; + + ignoreForPaletteDefinition = ['SequenceFlow', 'MessageFlow', 'Association', 'DataAssociation', 'DataStore', 'SendTask']; + } + + var quickMenuItems = []; + + var morphRoles = []; + for (var i = 0; i < data.rules.morphingRules.length; i++) + { + var role = data.rules.morphingRules[i].role; + var roleItem = {'role': role, 'morphOptions': []}; + morphRoles.push(roleItem); + } + + // Check all received items + for (var stencilIndex = 0; stencilIndex < data.stencils.length; stencilIndex++) { + + // Check if the root group is the 'diagram' group. If so, this item should not be shown. + var currentGroupName = data.stencils[stencilIndex].groups[0]; + if (currentGroupName === 'Diagram' || currentGroupName === 'Form') { + continue; // go to next item + } + + var removed = false; + if (data.stencils[stencilIndex].removed) { + removed = true; + } + + var currentGroup = undefined; + if (!removed) { + // Check if this group already exists. If not, we create a new one + + if (currentGroupName !== null && currentGroupName !== undefined && currentGroupName.length > 0) { + + currentGroup = findGroup(currentGroupName, stencilItemGroups); // Find group in root groups array + if (currentGroup === null) { + currentGroup = addGroup(currentGroupName, stencilItemGroups); + } + + // Add all child groups (if any) + for (var groupIndex = 1; groupIndex < data.stencils[stencilIndex].groups.length; groupIndex++) { + var childGroupName = data.stencils[stencilIndex].groups[groupIndex]; + var childGroup = findGroup(childGroupName, currentGroup.groups); + if (childGroup === null) { + childGroup = addGroup(childGroupName, currentGroup.groups); + } + + // The current group variable holds the parent of the next group (if any), + // and is basically the last element in the array of groups defined in the stencil item + currentGroup = childGroup; + + } + + } + } + + // Construct the stencil item + var stencilItem = {'id': data.stencils[stencilIndex].id, + 'name': data.stencils[stencilIndex].title, + 'description': data.stencils[stencilIndex].description, + 'icon': data.stencils[stencilIndex].icon, + 'type': data.stencils[stencilIndex].type, + 'roles': data.stencils[stencilIndex].roles, + 'removed': removed, + 'customIcon': false, + 'canConnect': false, + 'canConnectTo': false, + 'canConnectAssociation': false}; + + if (data.stencils[stencilIndex].customIconId && data.stencils[stencilIndex].customIconId > 0) { + stencilItem.customIcon = true; + stencilItem.icon = data.stencils[stencilIndex].customIconId; + } + + if (!removed) { + if (quickMenuDefinition.indexOf(stencilItem.id) >= 0) { + quickMenuItems[quickMenuDefinition.indexOf(stencilItem.id)] = stencilItem; + } + } + + if (stencilItem.id === 'TextAnnotation' || stencilItem.id === 'BoundaryCompensationEvent') { + stencilItem.canConnectAssociation = true; + } + + for (var i = 0; i < data.stencils[stencilIndex].roles.length; i++) { + var stencilRole = data.stencils[stencilIndex].roles[i]; + if (data.namespace == 'http://b3mn.org/stencilset/cmmn1.1#') { + if (stencilRole === 'association_start') { + stencilItem.canConnect = true; + } else if (stencilRole === 'association_end') { + stencilItem.canConnectTo = true; + } + + } else { + if (stencilRole === 'sequence_start') { + stencilItem.canConnect = true; + } else if (stencilRole === 'sequence_end') { + stencilItem.canConnectTo = true; + } + } + + for (var j = 0; j < morphRoles.length; j++) { + if (stencilRole === morphRoles[j].role) { + if (!removed) { + morphRoles[j].morphOptions.push(stencilItem); + } + stencilItem.morphRole = morphRoles[j].role; + break; + } + } + } + + if (currentGroup) { + // Add the stencil item to the correct group + currentGroup.items.push(stencilItem); + if (ignoreForPaletteDefinition.indexOf(stencilItem.id) < 0) { + currentGroup.paletteItems.push(stencilItem); + } + + } else { + // It's a root stencil element + if (!removed) { + stencilItemGroups.push(stencilItem); + } + } + } + + for (var i = 0; i < stencilItemGroups.length; i++) { + if (stencilItemGroups[i].paletteItems && stencilItemGroups[i].paletteItems.length == 0) { + stencilItemGroups[i].visible = false; + } + } + + $scope.stencilItemGroups = stencilItemGroups; + + var containmentRules = []; + for (var i = 0; i < data.rules.containmentRules.length; i++) { + var rule = data.rules.containmentRules[i]; + containmentRules.push(rule); + } + $scope.containmentRules = containmentRules; + + // remove quick menu items which are not available anymore due to custom pallette + var availableQuickMenuItems = []; + for (var i = 0; i < quickMenuItems.length; i++) { + if (quickMenuItems[i]) { + availableQuickMenuItems[availableQuickMenuItems.length] = quickMenuItems[i]; + } + } + + $scope.quickMenuItems = availableQuickMenuItems; + $scope.morphRoles = morphRoles; + + /* + * Listen to selection change events: show properties + */ + editorManager.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, function (event) { + var shapes = event.elements; + var canvasSelected = false; + if (shapes && shapes.length == 0) { + shapes = [editorManager.getCanvas()]; + canvasSelected = true; + } + if (shapes && shapes.length > 0) { + + var selectedShape = shapes.first(); + var stencil = selectedShape.getStencil(); + + if ($rootScope.selectedElementBeforeScrolling && stencil.id().indexOf('BPMNDiagram') !== -1 && stencil.id().indexOf('CMMNDiagram') !== -1) { + // ignore canvas event because of empty selection when scrolling stops + return; + } + + if ($rootScope.selectedElementBeforeScrolling && $rootScope.selectedElementBeforeScrolling.getId() === selectedShape.getId()) { + $rootScope.selectedElementBeforeScrolling = null; + return; + } + + // Store previous selection + $scope.previousSelectedShape = $scope.selectedShape; + + // Only do something if another element is selected (Oryx fires this event multiple times) + if ($scope.selectedShape !== undefined && $scope.selectedShape.getId() === selectedShape.getId()) { + if ($rootScope.forceSelectionRefresh) { + // Switch the flag again, this run will force refresh + $rootScope.forceSelectionRefresh = false; + } else { + // Selected the same element again, no need to update anything + return; + } + } + + var selectedItem = {'title': '', 'properties': []}; + + if (canvasSelected) { + selectedItem.auditData = { + 'author': $scope.modelData.createdByUser, + 'createDate': $scope.modelData.createDate + }; + } + + // Gather properties of selected item + var properties = stencil.properties(); + for (var i = 0; i < properties.length; i++) { + var property = properties[i]; + if (property.popular() == false) continue; + var key = property.prefix() + "-" + property.id(); + + if (key === 'oryx-name') { + selectedItem.title = selectedShape.properties.get(key); + } + + // First we check if there is a config for 'key-type' and then for 'type' alone + var propertyConfig = FLOWABLE.PROPERTY_CONFIG[key + '-' + property.type()]; + if (propertyConfig === undefined || propertyConfig === null) { + propertyConfig = FLOWABLE.PROPERTY_CONFIG[property.type()]; + } + + if (propertyConfig === undefined || propertyConfig === null) { + console.log('WARNING: no property configuration defined for ' + key + ' of type ' + property.type()); + } else { + + if (selectedShape.properties.get(key) === 'true') { + selectedShape.properties.set(key, true); + } + + if (FLOWABLE.UI_CONFIG.showRemovedProperties == false && property.isHidden()) + { + continue; + } + + var currentProperty = { + 'key': key, + 'title': property.title(), + 'description': property.description(), + 'type': property.type(), + 'mode': 'read', + 'hidden': property.isHidden(), + 'value': selectedShape.properties.get(key) + }; + + if ((currentProperty.type === 'complex' || currentProperty.type === 'multiplecomplex') && currentProperty.value && currentProperty.value.length > 0) { + try { + currentProperty.value = JSON.parse(currentProperty.value); + } catch (err) { + // ignore + } + } + + if (propertyConfig.readModeTemplateUrl !== undefined && propertyConfig.readModeTemplateUrl !== null) { + currentProperty.readModeTemplateUrl = propertyConfig.readModeTemplateUrl + '?version=' + $rootScope.staticIncludeVersion; + } + if (propertyConfig.writeModeTemplateUrl !== null && propertyConfig.writeModeTemplateUrl !== null) { + currentProperty.writeModeTemplateUrl = propertyConfig.writeModeTemplateUrl + '?version=' + $rootScope.staticIncludeVersion; + } + + if (propertyConfig.templateUrl !== undefined && propertyConfig.templateUrl !== null) { + currentProperty.templateUrl = propertyConfig.templateUrl + '?version=' + $rootScope.staticIncludeVersion; + currentProperty.hasReadWriteMode = false; + } + else { + currentProperty.hasReadWriteMode = true; + } + + if (currentProperty.value === undefined + || currentProperty.value === null + || currentProperty.value.length == 0) { + currentProperty.noValue = true; + } + + selectedItem.properties.push(currentProperty); + } + } + + // Need to wrap this in an $apply block, see http://jimhoskins.com/2012/12/17/angularjs-and-apply.html + $scope.safeApply(function () { + $scope.selectedItem = selectedItem; + $scope.selectedShape = selectedShape; + }); + + } else { + $scope.safeApply(function () { + $scope.selectedItem = {}; + $scope.selectedShape = null; + }); + } + }); + + editorManager.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, function (event) { + + FLOWABLE.eventBus.dispatch(FLOWABLE.eventBus.EVENT_TYPE_HIDE_SHAPE_BUTTONS); + var shapes = event.elements; + + if (shapes && shapes.length == 1) { + + var selectedShape = shapes.first(); + + var a = editorManager.getCanvas().node.getScreenCTM(); + + var absoluteXY = selectedShape.absoluteXY(); + + absoluteXY.x *= a.a; + absoluteXY.y *= a.d; + + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + var ua = navigator.userAgent; + if (ua.indexOf('MSIE') >= 0) { + //IE 10 and below + var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); + if (zoom !== 100) { + additionalIEZoom = zoom / 100 + } + } + } + + if (additionalIEZoom === 1) { + absoluteXY.y = absoluteXY.y - jQuery("#canvasSection").offset().top + 5; + absoluteXY.x = absoluteXY.x - jQuery("#canvasSection").offset().left; + + } else { + var canvasOffsetLeft = jQuery("#canvasSection").offset().left; + var canvasScrollLeft = jQuery("#canvasSection").scrollLeft(); + var canvasScrollTop = jQuery("#canvasSection").scrollTop(); + + var offset = a.e - (canvasOffsetLeft * additionalIEZoom); + var additionaloffset = 0; + if (offset > 10) { + additionaloffset = (offset / additionalIEZoom) - offset; + } + absoluteXY.y = absoluteXY.y - (jQuery("#canvasSection").offset().top * additionalIEZoom) + 5 + ((canvasScrollTop * additionalIEZoom) - canvasScrollTop); + absoluteXY.x = absoluteXY.x - (canvasOffsetLeft * additionalIEZoom) + additionaloffset + ((canvasScrollLeft * additionalIEZoom) - canvasScrollLeft); + } + + var bounds = new ORYX.Core.Bounds(a.e + absoluteXY.x, a.f + absoluteXY.y, a.e + absoluteXY.x + a.a*selectedShape.bounds.width(), a.f + absoluteXY.y + a.d*selectedShape.bounds.height()); + var shapeXY = bounds.upperLeft(); + + var stencilItem = $scope.getStencilItemById(selectedShape.getStencil().idWithoutNs()); + var morphShapes = []; + if (stencilItem && stencilItem.morphRole) { + for (var i = 0; i < $scope.morphRoles.length; i++) { + if ($scope.morphRoles[i].role === stencilItem.morphRole) { + morphShapes = $scope.morphRoles[i].morphOptions; + } + } + } + + var x = shapeXY.x; + if (bounds.width() < 48) { + x -= 24; + } + + if (morphShapes && morphShapes.length > 0) { + // In case the element is not wide enough, start the 2 bottom-buttons more to the left + // to prevent overflow in the right-menu + + var morphButton = document.getElementById('morph-button'); + morphButton.style.display = "block"; + morphButton.style.left = x + 24 +'px'; + morphButton.style.top = (shapeXY.y+bounds.height() + 2) + 'px'; + } + + var deleteButton = document.getElementById('delete-button'); + deleteButton.style.display = "block"; + deleteButton.style.left = x + 'px'; + deleteButton.style.top = (shapeXY.y+bounds.height() + 2) + 'px'; + + var editable = selectedShape._stencil._jsonStencil.id.endsWith('CollapsedSubProcess') ; + var editButton = document.getElementById('edit-button'); + if (editable) { + editButton.style.display = "block"; + if (morphShapes && morphShapes.length > 0) { + editButton.style.left = x + 24 + 24 + 'px'; + } else { + editButton.style.left = x + 24 +'px'; + } + editButton.style.top = (shapeXY.y+bounds.height() + 2) + 'px'; + + } else { + editButton.style.display = "none"; + } + + if (stencilItem && (stencilItem.canConnect || stencilItem.canConnectAssociation)) { + var quickButtonCounter = 0; + var quickButtonX = shapeXY.x+bounds.width() + 5; + var quickButtonY = shapeXY.y; + jQuery('.Oryx_button').each(function(i, obj) { + if (obj.id !== 'morph-button' && obj.id != 'delete-button' && obj.id !== 'edit-button') { + quickButtonCounter++; + if (quickButtonCounter > 3) { + quickButtonX = shapeXY.x+bounds.width() + 5; + quickButtonY += 24; + quickButtonCounter = 1; + + } else if (quickButtonCounter > 1) { + quickButtonX += 24; + } + + obj.style.display = "block"; + obj.style.left = quickButtonX + 'px'; + obj.style.top = quickButtonY + 'px'; + } + }); + } + } + }); + + if (!$rootScope.stencilInitialized) { + FLOWABLE.eventBus.addListener(FLOWABLE.eventBus.EVENT_TYPE_HIDE_SHAPE_BUTTONS, function (event) { + jQuery('.Oryx_button').each(function(i, obj) { + obj.style.display = "none"; + }); + }); + + /* + * Listen to property updates and act upon them + */ + FLOWABLE.eventBus.addListener(FLOWABLE.eventBus.EVENT_TYPE_PROPERTY_VALUE_CHANGED, function (event) { + if (event.property && event.property.key) { + // If the name property is been updated, we also need to change the title of the currently selected item + if (event.property.key === 'oryx-name' && $scope.selectedItem !== undefined && $scope.selectedItem !== null) { + $scope.selectedItem.title = event.newValue; + } + + // Update "no value" flag + event.property.noValue = (event.property.value === undefined + || event.property.value === null + || event.property.value.length == 0); + } + }); + + FLOWABLE.eventBus.addListener(FLOWABLE.eventBus.EVENT_TYPE_SHOW_VALIDATION_POPUP, function (event) { + // Method to open validation dialog + var showValidationDialog = function() { + $rootScope.currentValidationId = event.validationId; + $rootScope.isOnProcessLevel = event.onProcessLevel; + + _internalCreateModal({template: 'editor-app/popups/validation-errors.html?version=' + Date.now()}, $modal, $rootScope); + }; + + showValidationDialog(); + }); + + FLOWABLE.eventBus.addListener(FLOWABLE.eventBus.EVENT_TYPE_NAVIGATE_TO_PROCESS, function (event) { + var modelMetaData = editorManager.getBaseModelData(); + $rootScope.editorHistory.push({ + id: modelMetaData.modelId, + name: modelMetaData.name, + type: 'bpmnmodel' + }); + + $window.location.href = "../editor/#/editor/" + event.processId; + }); + + $rootScope.stencilInitialized = true; + } + + $scope.morphShape = function() { + $scope.safeApply(function () { + + var shapes = editorManager.getSelection(); + if (shapes && shapes.length == 1) { + $rootScope.currentSelectedShape = shapes.first(); + var stencilItem = $scope.getStencilItemById($rootScope.currentSelectedShape.getStencil().idWithoutNs()); + var morphShapes = []; + for (var i = 0; i < $scope.morphRoles.length; i++) { + if ($scope.morphRoles[i].role === stencilItem.morphRole) { + morphShapes = $scope.morphRoles[i].morphOptions.slice(); + } + } + + // Method to open shape select dialog (used later on) + var showSelectShapeDialog = function() + { + $rootScope.morphShapes = morphShapes; + _internalCreateModal({ + backdrop: false, + keyboard: true, + template: 'editor-app/popups/select-shape.html?version=' + Date.now() + }, $modal, $rootScope); + }; + + showSelectShapeDialog(); + } + }); + }; + + $scope.deleteShape = function() { + FLOWABLE.TOOLBAR.ACTIONS.deleteItem({'$scope': $scope, 'editorManager': editorManager}); + }; + + $scope.quickAddItem = function(newItemId) { + $scope.safeApply(function () { + + var shapes = editorManager.getSelection(); + if (shapes && shapes.length == 1) { + $rootScope.currentSelectedShape = shapes.first(); + + var containedStencil = undefined; + var stencilSets = editorManager.getStencilSets().values(); + for (var i = 0; i < stencilSets.length; i++) { + var stencilSet = stencilSets[i]; + var nodes = stencilSet.nodes(); + for (var j = 0; j < nodes.length; j++) { + if (nodes[j].idWithoutNs() === newItemId) { + containedStencil = nodes[j]; + break; + } + } + } + + if (!containedStencil) return; + + var option = {type: $scope.currentSelectedShape.getStencil().namespace() + newItemId, namespace: $scope.currentSelectedShape.getStencil().namespace()}; + option['connectedShape'] = $rootScope.currentSelectedShape; + option['parent'] = $rootScope.currentSelectedShape.parent; + option['containedStencil'] = containedStencil; + + var args = { sourceShape: $rootScope.currentSelectedShape, targetStencil: containedStencil }; + var targetStencil = editorManager.getRules().connectMorph(args); + + // Check if there can be a target shape + if (!targetStencil) { + return; + } + + option['connectingType'] = targetStencil.id(); + + var command = new FLOWABLE.CreateCommand(option, undefined, undefined, editorManager.getEditor()); + + editorManager.executeCommands([command]); + } + }); + }; + + $scope.editShape = function(){ + editorManager.edit($scope.selectedShape.resourceId); + }; + + }); // end of $scope.editorFactory.promise block + + /* Click handler for clicking a property */ + $scope.propertyClicked = function (index) { + if (!$scope.selectedItem.properties[index].hidden) { + $scope.selectedItem.properties[index].mode = "write"; + } + }; + + /* Helper method to retrieve the template url for a property */ + $scope.getPropertyTemplateUrl = function (index) { + return $scope.selectedItem.properties[index].templateUrl; + }; + $scope.getPropertyReadModeTemplateUrl = function (index) { + return $scope.selectedItem.properties[index].readModeTemplateUrl; + }; + $scope.getPropertyWriteModeTemplateUrl = function (index) { + return $scope.selectedItem.properties[index].writeModeTemplateUrl; + }; + + /* Method available to all sub controllers (for property controllers) to update the internal Oryx model */ + $scope.updatePropertyInModel = function (property, shapeId) { + + var shape = $scope.selectedShape; + // Some updates may happen when selected shape is already changed, so when an additional + // shapeId is supplied, we need to make sure the correct shape is updated (current or previous) + if (shapeId) { + if (shape.id != shapeId && $scope.previousSelectedShape && $scope.previousSelectedShape.id == shapeId) { + shape = $scope.previousSelectedShape; + } else { + shape = null; + } + } + + if (!shape) { + // When no shape is selected, or no shape is found for the alternative + // shape ID, do nothing + return; + } + var key = property.key; + var newValue = property.value; + var oldValue = shape.properties.get(key); + + if (newValue != oldValue) { + var commandClass = ORYX.Core.Command.extend({ + construct: function () { + this.key = key; + this.oldValue = oldValue; + this.newValue = newValue; + this.shape = shape; + this.facade = editorManager.getEditor(); + }, + execute: function () { + this.shape.setProperty(this.key, this.newValue); + this.facade.getCanvas().update(); + this.facade.updateSelection(); + }, + rollback: function () { + this.shape.setProperty(this.key, this.oldValue); + this.facade.getCanvas().update(); + this.facade.updateSelection(); + } + }); + // Instantiate the class + var command = new commandClass(); + + // Execute the command + editorManager.executeCommands([command]); + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_PROPWINDOW_PROP_CHANGED, + elements: [shape], + key: key + }); + + // Switch the property back to read mode, now the update is done + property.mode = 'read'; + + // Fire event to all who is interested + // Fire event to all who want to know about this + var event = { + type: FLOWABLE.eventBus.EVENT_TYPE_PROPERTY_VALUE_CHANGED, + property: property, + oldValue: oldValue, + newValue: newValue + }; + FLOWABLE.eventBus.dispatch(event.type, event); + } else { + // Switch the property back to read mode, no update was needed + property.mode = 'read'; + } + + }; + + /** + * Helper method that searches a group for an item with the given id. + * If not found, will return undefined. + */ + $scope.findStencilItemInGroup = function (stencilItemId, group) { + + var item; + + // Check all items directly in this group + for (var j = 0; j < group.items.length; j++) { + item = group.items[j]; + if (item.id === stencilItemId) { + return item; + } + } + + // Check the child groups + if (group.groups && group.groups.length > 0) { + for (var k = 0; k < group.groups.length; k++) { + item = $scope.findStencilItemInGroup(stencilItemId, group.groups[k]); + if (item) { + return item; + } + } + } + + return undefined; + }; + + /** + * Helper method to find a stencil item. + */ + $scope.getStencilItemById = function (stencilItemId) { + for (var i = 0; i < $scope.stencilItemGroups.length; i++) { + var element = $scope.stencilItemGroups[i]; + + // Real group + if (element.items !== null && element.items !== undefined) { + var item = $scope.findStencilItemInGroup(stencilItemId, element); + if (item) { + return item; + } + } else { // Root stencil item + if (element.id === stencilItemId) { + return element; + } + } + } + return undefined; + }; + + /* + * DRAG AND DROP FUNCTIONALITY + */ + + $scope.dropCallback = function (event, ui) { + + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, + highlightId: "shapeRepo.attached" + }); + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, + highlightId: "shapeRepo.added" + }); + + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, + highlightId: "shapeMenu" + }); + + FLOWABLE.eventBus.dispatch(FLOWABLE.eventBus.EVENT_TYPE_HIDE_SHAPE_BUTTONS); + + if ($scope.dragCanContain) { + + var item = $scope.getStencilItemById(ui.draggable[0].id); + + var pos = {x: event.pageX, y: event.pageY}; + + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + var ua = navigator.userAgent; + if (ua.indexOf('MSIE') >= 0) { + //IE 10 and below + var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); + if (zoom !== 100) { + additionalIEZoom = zoom / 100; + } + } + } + + var screenCTM = editorManager.getCanvas().node.getScreenCTM(); + + // Correcting the UpperLeft-Offset + pos.x -= (screenCTM.e / additionalIEZoom); + pos.y -= (screenCTM.f / additionalIEZoom); + // Correcting the Zoom-Factor + pos.x /= screenCTM.a; + pos.y /= screenCTM.d; + + // Correcting the ScrollOffset + pos.x -= document.documentElement.scrollLeft; + pos.y -= document.documentElement.scrollTop; + + var parentAbs = $scope.dragCurrentParent.absoluteXY(); + pos.x -= parentAbs.x; + pos.y -= parentAbs.y; + + var containedStencil = undefined; + var stencilSets = editorManager.getStencilSets().values(); + for (var i = 0; i < stencilSets.length; i++) { + var stencilSet = stencilSets[i]; + var nodes = stencilSet.nodes(); + for (var j = 0; j < nodes.length; j++) { + if (nodes[j].idWithoutNs() === ui.draggable[0].id) { + containedStencil = nodes[j]; + break; + } + } + + if (!containedStencil) { + var edges = stencilSet.edges(); + for (var j = 0; j < edges.length; j++) { + if (edges[j].idWithoutNs() === ui.draggable[0].id) { + containedStencil = edges[j]; + break; + } + } + } + } + + if (!containedStencil) return; + + if ($scope.quickMenu) { + var shapes = editorManager.getSelection(); + if (shapes && shapes.length == 1) { + var currentSelectedShape = shapes.first(); + + var option = {}; + option.type = currentSelectedShape.getStencil().namespace() + ui.draggable[0].id; + option.namespace = currentSelectedShape.getStencil().namespace(); + option.connectedShape = currentSelectedShape; + option.parent = $scope.dragCurrentParent; + option.containedStencil = containedStencil; + + // If the ctrl key is not pressed, + // snapp the new shape to the center + // if it is near to the center of the other shape + if (!event.ctrlKey) { + // Get the center of the shape + var cShape = currentSelectedShape.bounds.center(); + // Snapp +-20 Pixel horizontal to the center + if (20 > Math.abs(cShape.x - pos.x)) { + pos.x = cShape.x; + } + // Snapp +-20 Pixel vertical to the center + if (20 > Math.abs(cShape.y - pos.y)) { + pos.y = cShape.y; + } + } + + option.position = pos; + + if (containedStencil.idWithoutNs() !== 'SequenceFlow' && containedStencil.idWithoutNs() !== 'Association' && + containedStencil.idWithoutNs() !== 'MessageFlow' && containedStencil.idWithoutNs() !== 'DataAssociation') { + + var args = { sourceShape: currentSelectedShape, targetStencil: containedStencil }; + var targetStencil = editorManager.getRules().connectMorph(args); + if (!targetStencil) { // Check if there can be a target shape + return; + } + option.connectingType = targetStencil.id(); + } + + var command = new FLOWABLE.CreateCommand(option, $scope.dropTargetElement, pos, editorManager.getEditor()); + + editorManager.executeCommands([command]); + } + + } else { + var canAttach = false; + if (containedStencil.idWithoutNs() === 'BoundaryErrorEvent' || containedStencil.idWithoutNs() === 'BoundaryTimerEvent' || + containedStencil.idWithoutNs() === 'BoundarySignalEvent' || containedStencil.idWithoutNs() === 'BoundaryMessageEvent' || + containedStencil.idWithoutNs() === 'BoundaryCancelEvent' || containedStencil.idWithoutNs() === 'BoundaryCompensationEvent') { + + // Modify position, otherwise boundary event will get position related to left corner of the canvas instead of the container + pos = editorManager.eventCoordinates( event ); + canAttach = true; + } + + var option = {}; + option['type'] = $scope.modelData.model.stencilset.namespace + item.id; + option['namespace'] = $scope.modelData.model.stencilset.namespace; + option['position'] = pos; + option['parent'] = $scope.dragCurrentParent; + + var commandClass = ORYX.Core.Command.extend({ + construct: function(option, dockedShape, canAttach, position, facade){ + this.option = option; + this.docker = null; + this.dockedShape = dockedShape; + this.dockedShapeParent = dockedShape.parent || facade.getCanvas(); + this.position = position; + this.facade = facade; + this.selection = this.facade.getSelection(); + this.shape = null; + this.parent = null; + this.canAttach = canAttach; + }, + execute: function(){ + if (!this.shape) { + this.shape = this.facade.createShape(option); + this.parent = this.shape.parent; + } else if (this.parent) { + this.parent.add(this.shape); + } + + if (this.canAttach && this.shape.dockers && this.shape.dockers.length) { + this.docker = this.shape.dockers[0]; + + this.dockedShapeParent.add(this.docker.parent); + + // Set the Docker to the new Shape + this.docker.setDockedShape(undefined); + this.docker.bounds.centerMoveTo(this.position); + if (this.dockedShape !== this.facade.getCanvas()) { + this.docker.setDockedShape(this.dockedShape); + } + this.facade.setSelection( [this.docker.parent] ); + } + + this.facade.getCanvas().update(); + this.facade.updateSelection(); + + }, + rollback: function(){ + if (this.shape) { + this.facade.setSelection(this.selection.without(this.shape)); + this.facade.deleteShape(this.shape); + } + if (this.canAttach && this.docker) { + this.docker.setDockedShape(undefined); + } + this.facade.getCanvas().update(); + this.facade.updateSelection(); + + } + }); + + // Update canvas + var command = new commandClass(option, $scope.dragCurrentParent, canAttach, pos, editorManager.getEditor()); + editorManager.executeCommands([command]); + + // Fire event to all who want to know about this + var dropEvent = { + type: FLOWABLE.eventBus.EVENT_TYPE_ITEM_DROPPED, + droppedItem: item, + position: pos + }; + FLOWABLE.eventBus.dispatch(dropEvent.type, dropEvent); + } + } + + $scope.dragCurrentParent = undefined; + $scope.dragCurrentParentId = undefined; + $scope.dragCurrentParentStencil = undefined; + $scope.dragCanContain = undefined; + $scope.quickMenu = undefined; + $scope.dropTargetElement = undefined; + }; + + + $scope.overCallback = function (event, ui) { + $scope.dragModeOver = true; + }; + + $scope.outCallback = function (event, ui) { + $scope.dragModeOver = false; + }; + + $scope.startDragCallback = function (event, ui) { + $scope.dragModeOver = false; + $scope.quickMenu = false; + if (!ui.helper.hasClass('stencil-item-dragged')) { + ui.helper.addClass('stencil-item-dragged'); + } + }; + + $scope.startDragCallbackQuickMenu = function (event, ui) { + $scope.dragModeOver = false; + $scope.quickMenu = true; + }; + + $scope.dragCallback = function (event, ui) { + + if ($scope.dragModeOver != false) { + + var coord = editorManager.eventCoordinatesXY(event.pageX, event.pageY); + + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + var ua = navigator.userAgent; + if (ua.indexOf('MSIE') >= 0) { + //IE 10 and below + var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); + if (zoom !== 100) { + additionalIEZoom = zoom / 100 + } + } + } + + if (additionalIEZoom !== 1) { + coord.x = coord.x / additionalIEZoom; + coord.y = coord.y / additionalIEZoom; + } + + var aShapes = editorManager.getCanvas().getAbstractShapesAtPosition(coord); + + if (aShapes.length <= 0) { + if (event.helper) { + $scope.dragCanContain = false; + return false; + } + } + + if (aShapes[0] instanceof ORYX.Core.Canvas) { + editorManager.getCanvas().setHightlightStateBasedOnX(coord.x); + } + + if (aShapes.length == 1 && aShapes[0] instanceof ORYX.Core.Canvas) { + var item = $scope.getStencilItemById(event.target.id); + var parentCandidate = aShapes[0]; + + if (item.id === 'Lane' || item.id === 'BoundaryErrorEvent' || item.id === 'BoundaryMessageEvent' || + item.id === 'BoundarySignalEvent' || item.id === 'BoundaryTimerEvent' || + item.id === 'BoundaryCancelEvent' || item.id === 'BoundaryCompensationEvent' || + item.id === 'EntryCriterion') { + + $scope.dragCanContain = false; + + // Show Highlight + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, + highlightId: 'shapeRepo.added', + elements: [parentCandidate], + style: ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE, + color: ORYX.CONFIG.SELECTION_INVALID_COLOR + }); + + } else { + $scope.dragCanContain = true; + $scope.dragCurrentParent = parentCandidate; + $scope.dragCurrentParentId = parentCandidate.id; + + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, + highlightId: "shapeRepo.added" + }); + } + + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, + highlightId: "shapeRepo.attached" + }); + + return false; + + } else { + var item = $scope.getStencilItemById(event.target.id); + + var parentCandidate = aShapes.reverse().find(function (candidate) { + return (candidate instanceof ORYX.Core.Canvas + || candidate instanceof ORYX.Core.Node + || candidate instanceof ORYX.Core.Edge); + }); + + if (!parentCandidate) { + $scope.dragCanContain = false; + return false; + } + + if (item.type === "node") { + + // check if the draggable is a boundary event and the parent an Activity + var _canContain = false; + var parentStencilId = parentCandidate.getStencil().id(); + + if ($scope.dragCurrentParentId && $scope.dragCurrentParentId === parentCandidate.id) { + return false; + } + + var parentItem = $scope.getStencilItemById(parentCandidate.getStencil().idWithoutNs()); + if (parentItem.roles.indexOf('Activity') > -1) { + if (item.roles.indexOf('IntermediateEventOnActivityBoundary') > -1 + || item.roles.indexOf('EntryCriterionOnItemBoundary') > -1 + || item.roles.indexOf('ExitCriterionOnItemBoundary') > -1) { + _canContain = true; + } + + } else if(parentItem.roles.indexOf('StageActivity') > -1) { + if (item.roles.indexOf('EntryCriterionOnItemBoundary') > -1 + || item.roles.indexOf('ExitCriterionOnItemBoundary') > -1) { + _canContain = true; + } + + } else if(parentItem.roles.indexOf('StageModelActivity') > -1) { + if (item.roles.indexOf('ExitCriterionOnItemBoundary') > -1) { + _canContain = true; + } + + } else if (parentCandidate.getStencil().idWithoutNs() === 'Pool') { + if (item.id === 'Lane') { + _canContain = true; + } + } + + if (_canContain) { + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, + highlightId: "shapeRepo.attached", + elements: [parentCandidate], + style: ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE, + color: ORYX.CONFIG.SELECTION_VALID_COLOR + }); + + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, + highlightId: "shapeRepo.added" + }); + + } else { + for (var i = 0; i < $scope.containmentRules.length; i++) { + var rule = $scope.containmentRules[i]; + if (rule.role === parentItem.id) { + for (var j = 0; j < rule.contains.length; j++) { + if (item.roles.indexOf(rule.contains[j]) > -1) { + _canContain = true; + break; + } + } + + if (_canContain) { + break; + } + } + } + + // Show Highlight + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, + highlightId: 'shapeRepo.added', + elements: [parentCandidate], + color: _canContain ? ORYX.CONFIG.SELECTION_VALID_COLOR : ORYX.CONFIG.SELECTION_INVALID_COLOR + }); + + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, + highlightId: "shapeRepo.attached" + }); + } + + $scope.dragCurrentParent = parentCandidate; + $scope.dragCurrentParentId = parentCandidate.id; + $scope.dragCurrentParentStencil = parentStencilId; + $scope.dragCanContain = _canContain; + + } else { + var canvasCandidate = editorManager.getCanvas(); + var canConnect = false; + + var targetStencil = $scope.getStencilItemById(parentCandidate.getStencil().idWithoutNs()); + if (targetStencil) { + var associationConnect = false; + if (stencil.idWithoutNs() === 'Association' && (curCan.getStencil().idWithoutNs() === 'TextAnnotation' || curCan.getStencil().idWithoutNs() === 'BoundaryCompensationEvent')) { + associationConnect = true; + } else if (stencil.idWithoutNs() === 'DataAssociation' && curCan.getStencil().idWithoutNs() === 'DataStore') { + associationConnect = true; + } + + if (targetStencil.canConnectTo || associationConnect) { + canConnect = true; + } + } + + //Edge + $scope.dragCurrentParent = canvasCandidate; + $scope.dragCurrentParentId = canvasCandidate.id; + $scope.dragCurrentParentStencil = canvasCandidate.getStencil().id(); + $scope.dragCanContain = canConnect; + + // Show Highlight + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, + highlightId: 'shapeRepo.added', + elements: [canvasCandidate], + color: ORYX.CONFIG.SELECTION_VALID_COLOR + }); + + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, + highlightId: "shapeRepo.attached" + }); + } + } + } + }; + + $scope.dragCallbackQuickMenu = function (event, ui) { + + if ($scope.dragModeOver != false) { + var coord = editorManager.eventCoordinatesXY(event.pageX, event.pageY); + + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + var ua = navigator.userAgent; + if (ua.indexOf('MSIE') >= 0) { + //IE 10 and below + var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); + if (zoom !== 100) { + additionalIEZoom = zoom / 100 + } + } + } + + if (additionalIEZoom !== 1) { + coord.x = coord.x / additionalIEZoom; + coord.y = coord.y / additionalIEZoom; + } + + var aShapes = editorManager.getCanvas().getAbstractShapesAtPosition(coord); + + if (aShapes.length <= 0) { + if (event.helper) { + $scope.dragCanContain = false; + return false; + } + } + + if (aShapes[0] instanceof ORYX.Core.Canvas) { + editorManager.getCanvas().setHightlightStateBasedOnX(coord.x); + } + + var stencil = undefined; + var stencilSets = editorManager.getStencilSets().values(); + for (var i = 0; i < stencilSets.length; i++) { + var stencilSet = stencilSets[i]; + var nodes = stencilSet.nodes(); + for (var j = 0; j < nodes.length; j++) { + if (nodes[j].idWithoutNs() === event.target.id) { + stencil = nodes[j]; + break; + } + } + + if (!stencil) { + var edges = stencilSet.edges(); + for (var j = 0; j < edges.length; j++) { + if (edges[j].idWithoutNs() === event.target.id) { + stencil = edges[j]; + break; + } + } + } + } + + var candidate = aShapes.last(); + + var isValid = false; + if (stencil.type() === "node") { + //check containment rules + var canContain = editorManager.getRules().canContain({containingShape:candidate, containedStencil:stencil}); + + var parentCandidate = aShapes.reverse().find(function (candidate) { + return (candidate instanceof ORYX.Core.Canvas + || candidate instanceof ORYX.Core.Node + || candidate instanceof ORYX.Core.Edge); + }); + + if (!parentCandidate) { + $scope.dragCanContain = false; + return false; + } + + $scope.dragCurrentParent = parentCandidate; + $scope.dragCurrentParentId = parentCandidate.id; + $scope.dragCurrentParentStencil = parentCandidate.getStencil().id(); + $scope.dragCanContain = canContain; + $scope.dropTargetElement = parentCandidate; + isValid = canContain; + + } else { //Edge + + var shapes = editorManager.getSelection(); + if (shapes && shapes.length == 1) { + var currentSelectedShape = shapes.first(); + var curCan = candidate; + var canConnect = false; + + var targetStencil = $scope.getStencilItemById(curCan.getStencil().idWithoutNs()); + if (targetStencil) { + var associationConnect = false; + if (stencil.idWithoutNs() === 'Association' && (curCan.getStencil().idWithoutNs() === 'TextAnnotation' || curCan.getStencil().idWithoutNs() === 'BoundaryCompensationEvent')) { + associationConnect = true; + } else if (stencil.idWithoutNs() === 'DataAssociation' && curCan.getStencil().idWithoutNs() === 'DataStore') { + associationConnect = true; + } + + if (targetStencil.canConnectTo || associationConnect) { + while (!canConnect && curCan && !(curCan instanceof ORYX.Core.Canvas)) { + candidate = curCan; + //check connection rules + canConnect = editorManager.getRules().canConnect({ + sourceShape: currentSelectedShape, + edgeStencil: stencil, + targetShape: curCan + }); + curCan = curCan.parent; + } + } + } + var parentCandidate = editorManager.getCanvas(); + + isValid = canConnect; + $scope.dragCurrentParent = parentCandidate; + $scope.dragCurrentParentId = parentCandidate.id; + $scope.dragCurrentParentStencil = parentCandidate.getStencil().id(); + $scope.dragCanContain = canConnect; + $scope.dropTargetElement = candidate; + } + + } + + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, + highlightId:'shapeMenu', + elements: [candidate], + color: isValid ? ORYX.CONFIG.SELECTION_VALID_COLOR : ORYX.CONFIG.SELECTION_INVALID_COLOR + }); + } + }; + + }]); + +var FLOWABLE = FLOWABLE || {}; +//create command for undo/redo +FLOWABLE.CreateCommand = ORYX.Core.Command.extend({ + construct: function(option, currentReference, position, facade){ + this.option = option; + this.currentReference = currentReference; + this.position = position; + this.facade = facade; + this.shape; + this.edge; + this.targetRefPos; + this.sourceRefPos; + /* + * clone options parameters + */ + this.connectedShape = option.connectedShape; + this.connectingType = option.connectingType; + this.namespace = option.namespace; + this.type = option.type; + this.containedStencil = option.containedStencil; + this.parent = option.parent; + this.currentReference = currentReference; + this.shapeOptions = option.shapeOptions; + }, + execute: function(){ + + if (this.shape) { + if (this.shape instanceof ORYX.Core.Node) { + this.parent.add(this.shape); + if (this.edge) { + this.facade.getCanvas().add(this.edge); + this.edge.dockers.first().setDockedShape(this.connectedShape); + this.edge.dockers.first().setReferencePoint(this.sourceRefPos); + this.edge.dockers.last().setDockedShape(this.shape); + this.edge.dockers.last().setReferencePoint(this.targetRefPos); + } + + this.facade.setSelection([this.shape]); + + } else if (this.shape instanceof ORYX.Core.Edge) { + this.facade.getCanvas().add(this.shape); + this.shape.dockers.first().setDockedShape(this.connectedShape); + this.shape.dockers.first().setReferencePoint(this.sourceRefPos); + } + } + else { + this.shape = this.facade.createShape(this.option); + this.edge = (!(this.shape instanceof ORYX.Core.Edge)) ? this.shape.getIncomingShapes().first() : undefined; + } + + if (this.currentReference && this.position) { + + if (this.shape instanceof ORYX.Core.Edge) { + + if (!(this.currentReference instanceof ORYX.Core.Canvas)) { + this.shape.dockers.last().setDockedShape(this.currentReference); + + if (this.currentReference.getStencil().idWithoutNs() === 'TextAnnotation') + { + var midpoint = {}; + midpoint.x = 0; + midpoint.y = this.currentReference.bounds.height() / 2; + this.shape.dockers.last().setReferencePoint(midpoint); + } + else + { + this.shape.dockers.last().setReferencePoint(this.currentReference.bounds.midPoint()); + } + } + else { + this.shape.dockers.last().bounds.centerMoveTo(this.position); + } + this.sourceRefPos = this.shape.dockers.first().referencePoint; + this.targetRefPos = this.shape.dockers.last().referencePoint; + + } else if (this.edge){ + this.sourceRefPos = this.edge.dockers.first().referencePoint; + this.targetRefPos = this.edge.dockers.last().referencePoint; + } + } else { + var containedStencil = this.containedStencil; + var connectedShape = this.connectedShape; + var bc = connectedShape.bounds; + var bs = this.shape.bounds; + + var pos = bc.center(); + if(containedStencil.defaultAlign()==="north") { + pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.height()/2); + } else if(containedStencil.defaultAlign()==="northeast") { + pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2); + pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2); + } else if(containedStencil.defaultAlign()==="southeast") { + pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2); + pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2); + } else if(containedStencil.defaultAlign()==="south") { + pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.height()/2); + } else if(containedStencil.defaultAlign()==="southwest") { + pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2); + pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2); + } else if(containedStencil.defaultAlign()==="west") { + pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.width()/2); + } else if(containedStencil.defaultAlign()==="northwest") { + pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2); + pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2); + } else { + pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.width()/2); + } + + // Move shape to the new position + this.shape.bounds.centerMoveTo(pos); + + // Move all dockers of a node to the position + if (this.shape instanceof ORYX.Core.Node){ + (this.shape.dockers||[]).each(function(docker){ + docker.bounds.centerMoveTo(pos); + }); + } + + //this.shape.update(); + this.position = pos; + + if (this.edge){ + this.sourceRefPos = this.edge.dockers.first().referencePoint; + this.targetRefPos = this.edge.dockers.last().referencePoint; + } + } + + this.facade.getCanvas().update(); + this.facade.updateSelection(); + + }, + rollback: function(){ + this.facade.deleteShape(this.shape); + if(this.edge) { + this.facade.deleteShape(this.edge); + } + //this.currentParent.update(); + this.facade.setSelection(this.facade.getSelection().without(this.shape, this.edge)); + } +}); diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/adhoc.subprocess.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/adhoc.subprocess.png new file mode 100644 index 0000000000000000000000000000000000000000..bf50968ac183c188e0c1a3e12ea4acc521f6b915 GIT binary patch literal 293 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xj(fT|hE&{2`t$$4J+o>6*o7fx*uS3FfG@Q-&ezHxT{gD%HivbW)ou<7neWm7ndZ=kn1|!VAa^c7a}4O z+c3pY;QsE<5B_DT6gn#Ww~b?N=yGbjqNVcBR^ck=5ry8T4mnOIxV;?SaBb-n^k{cH zn&!l7>wSUSp?9uF&V@EufbeJYD@<);T3K0RZiEZ2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4x@XHPV2-p&roj9JG%-*R-NJ%=$=-fa5=0?3XOLWx0{HU^me944$rjF6*2UngCcma%=zq literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/event.subprocess.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/event.subprocess.png new file mode 100644 index 0000000000000000000000000000000000000000..db72fee2e91e47f3dcd60727031d9aae6eaf8e36 GIT binary patch literal 274 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4oc9xz-oTla#E zVdl>be_0CRuTPzH?wbD2Npq&B-b|1d3{(}p{bJ)1A;GI=yZG!Zm1@Mc7(B`piF<4m zbHT)P(_!9vw*AQ)($ikn&YI~O#M);#aZbPCUaPhg2J4fO3>Bs4^6QSt{F>2lAR6d2 N22WQ%mvv4FO#l&tVW0p2 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/expanded.subprocess.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/expanded.subprocess.png new file mode 100644 index 0000000000000000000000000000000000000000..085343c84e98d902680df5575d5e4ed1ca3604ec GIT binary patch literal 273 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4I>W+Y*bM3I@G1- zZPLKP@UCw97Ums(MZGC2x9$^SDET2Mc%0|$yXf@12`zIrt2~_k)8Mr19Qg@u-p0~$ z?k)vd2`PV;eYXA)?NIzZSM1e2wl6}SVxGHa+Nv8%on&H&seNu9ay*L5=+A;ZK$kIi My85}Sb4q9e0D3oGY5)KL literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.business.rule.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.business.rule.png new file mode 100644 index 0000000000000000000000000000000000000000..7b3f3b671b0a8ff132b56b458550df699484efe4 GIT binary patch literal 209 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4w?GgtC@!$G<@3_2IlN7AIaJlz8 z_xpZ_dqh?7Ja67wdjWV7$MKK@EaRNJXRRFqcY$r^T%&mGbUL%1=bb5Zv)Mef2OuI3 zf$zDV0xW><`_oyLZCGpHIOoo{+wIHMYW1gc?&26AilQ}OyC{grdw?WKR)G^hSwz-U z^)_%ASn+*-dKb{^^-91(u0PajwQsFfYZY*XNmXk(4B%9fB!k_Cs)}>&2XGWffY-p{ zKC@F}%u*PJj|;#$(AXz5xxSQ2rL!jg_wNIS0VGM1>jpqoU;Srj2Pm3t0Y?l#rBWFH z&j6hWyvWZxBGRbW>!*R0yf!N$4@C8E#yPhLq`*z!oiXNCmSrDBWGRZGM*!V!cP35K zE#SDSE}PMIaU4HS)ATKH&RRPN!*B=K0A>nL5Cp$ebs0cJu8aWy%H{GLuo(owr+hw7 zfnyW4m%vwGeh(l`(@Vg5p+)4gs#Zrm#+Vu~1g6FSp68teu8GL~JS?i}1Jx0aRn;3J uvZ<<9QPqEL=UlJdZZC}1`u)Bs?tcI@I?dC0000Iakn literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.decision.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.decision.png new file mode 100644 index 0000000000000000000000000000000000000000..0351fee8a4a147e3e54c9ddbfcd9dddc25fe693d GIT binary patch literal 299 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt@+JY5_^ zEP9V#HuPdn6k&PbfAN@8N7zBPX%$T+Nr~xi8FP}?rR1v19k}GQp-WsqOgngGLSnKD z_xa=F`tQrtuRYq=E}ZkHFt1VCX8DJP_kGvbs8t+QzSrFUv1$2( z-#5-G<~(Mw?s5!Pic1Xop|ZtA*w}mS>Vpi27x6l0hh4wMHT#E-p!g4teWLoOyLOhX zJhVb($FVIRGBY{@!y>K=@72EIYvU??UVO*l)DOlo4{a)x_j#FSbRU#{)_UGKd#!@@ vo!@u+_3ST+^IcA8NWOdSQ0|gn>3V;J literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.http.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.http.png new file mode 100644 index 0000000000000000000000000000000000000000..ffba8de117c51945335082019349be32dacc78a4 GIT binary patch literal 1267 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0WW zg+Z8+Vb&Z81_tJ3nIRD+5xzcF$@#f@i7EL>sd^Q;1whpd3^o;3KxS@gNuokUZcbjY zRfVk*ScMgk4HDK@QUEI{$+lIB@C{IK&M!(;Fx4~BGf=YQQczH^DN0GR3UYCSY6tRc zl`=|73as??%gf94%8m8%i_-NCEiEne4UF`SjC6r2bc-wVN)jt{^NN)rhQQ2mNi9w; z$}A|!%+FH*nVXoDUs__Tqy(}E4xsMLEr45;R}A$P(0}?Bi3R$GdItK~G?iqgA)JSz z3nYV6TWUon4s9SAh&FIwK-_2p3{flJ{FKbJN|(fvR68RBLsMM?V_jpz5JL+q17j;g za~pj$H3%PqbvqZOCYIzEh2-bw*ac)(q~_#;xC+L4#t@yz@<>`izOeEy%1i|YFDMZ0 z3~lr=#L(3{=jRp_r4|>1)SE)pBa5M{4@xc0&nX2NADWk0VrK-^f+mcvD-t1ZXAaYY zEQqcl0-FY8K_m^JXs`l@Q-n)qZfYLbFNS6|`dB54=o-U3d7J^$R?dD?) z6mdQNSY1VG;tLTgUMa!OL-H$FT2~xle^KJ}I#|R@v|eH2i;g~lj}g{}CuP&rj0LSD zji1lke17h4iPOIVCkp%x++%sdiOtNQ*+J_;)Pc(hJ~AG%G3o)I1+J{v!59|9FJHRS z_rSeZjXxO6BMwgwO4)Kp>&rv7XPe$u_}Q`XsY>J?G^^ZuzT#8gx$g;53nEYF?=}_p z%!-eT5B{PY?6SNRln4WvVW_^4+wgGn%2?42r7v@UHx3vIVCg!0Kr9^jsO4v literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.manual.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.manual.png new file mode 100644 index 0000000000000000000000000000000000000000..8dc32983d825edfaf5ab40d3721db2f3ba3e3b02 GIT binary patch literal 405 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4~W4%O$Rt<}ImZm|i(={y#2- zlPaFu_DwEh)M0E`@^oMOjS7L|g+8Ao4(wu|<83v)BsFbqWNM_H<#W3z2NBoXX=TP& zf|g&3oR)fd8>{hY_DR~F<@*xS*2R8bhkf9F1oky=NAP!X7rn`mQ-Qd@D;qIvJB z8{0?{Oh(&qVn`o!Bn0aqz*B@F|Ye8u7ft%R@SO?b4>`j`c-#hVY3rJEN#|1Nc4s>&R>`Qujbab>-tyVpN zYm>t;{9tA;fgG@R3V9F6nOV^}_fC?I1>!g^NE!t;Bn_F_%t^MH%}5%`Fr#rCKL$`3 zhP{%$0xjp<^-`&{m5F`^ZfE>2Ns`43Ft=D}*UdLZd-*2!WRh9hAZj!1fu<=)TD&9%&I zFuSh>{r&ydvTa|e)oLrvW^)x70xnCMk~9T$0jt1+TCMi0*=)WBdVsPsvof#`4AkrO zLXsrg-uq!-v%?0P-uvMsNw(|tdI1;!_RTDjnK3>-{wQ;y2a0C4EU6CYuaB%x(tY3w z5J;LWm&;2svtuh~ZiGL!J2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4toV*9CakC_wr6HrFYDv7tik$#`TEASoEr+)seO61`C-gsmL1=`x44DB m<@FJJ^T^C1{^k4n$Lveu+-&7fWxfHrn8DN4&t;ucLK6TfN^xBP literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.script.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.script.png new file mode 100644 index 0000000000000000000000000000000000000000..674e4b89f0a97f1dff8637ffceec66f19ef68624 GIT binary patch literal 300 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4a{Eo zn0Wfbr!@=JnKtO0{=~L}g+tG7(JHmrEvr_U?~zU{`O9d}kixL)7mHZuJoo!-Upp3F p=WqC4$8N&;OzOt*rrE#F>6e=rtPQ{1&j@rhgQu&X%Q~loCIAlOZjJx| literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.send.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.send.png new file mode 100644 index 0000000000000000000000000000000000000000..8ebe452eef430ca1a28af78cf7d8616e7a7a4451 GIT binary patch literal 440 zcmV;p0Z0CcP)>LL}bzk%xotj;|nA;JT|jkBLL7dvz_;T_=lua)xvu} ztl(Z-004dG+@6^SCnTk+7R)?w&g}v8>xZ-7*pf5@J5}A*`7@<7jWK?R$P&Oy4T?w) zz=Nu;z4ue++*{p6E%+j$EXMfG%+CPk0PbhASqA(J8Ni5{?_!LPB9fWeYZHNpvJk>C z&+}~s1HdSybVw;30F0`;d7kIn5Wb8E^u;0q!SBvR4$v$*P3!q4)vNS=qE%%l!=8WeG)5T!qOI6X0WbCbj%| z;Qo;i4C?@+Fm2+Tdp#bHe*kp5-4~5U;{tdbHq)$07*qoM6N<$f}+0Zod5s; literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.shell.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.shell.png new file mode 100644 index 0000000000000000000000000000000000000000..53226b1e91833e777b6dd811db8da22efae83b6e GIT binary patch literal 325 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4-TS=8=P}GLLbv{SD$X3a>m0w5SU$IxRUPxelF{r5}E+Iym)v3 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.user.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.user.png new file mode 100644 index 0000000000000000000000000000000000000000..60562a0ae228c519d3f4571f48a892d42b546165 GIT binary patch literal 405 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4T86MDA{A z7f5m3=B<1q>csyXp~y1zzD?_EKL5YJr_tO===X^qXBKJng?x>3S;pY-$+BzF>{YAm zwxuu5b#`$H6=z6OIj(Y?A#K$z0YOftHCx3Q)aE5jwmGlg%rHrPUwWw(FH^|Zgp6nx zzGeo7*NO}$w<{cw*lfIoF@lw`P-Z<_(3;6AmAp)+HvM5S_|EX`?#=fM&+n|zzp%_D z<<%VNw?As9Zq_l*oE0~54|BmAPX>nfN=3J~y-mJs5^v9t{noO9eNsAe_wCF$hM4Q6 we^VG5o_x~p-n*-N8pDz6&Gnw&{+_%4+dsu>tF_WLU=T8Ry85}Sb4q9e0E_6JHvj+t literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/subprocess.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/activity/subprocess.png new file mode 100644 index 0000000000000000000000000000000000000000..329b24ca9a8b24864dc214684eeda04b490a5741 GIT binary patch literal 282 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR42?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4YHW%tNf9 zW5?}#4X;(Mt8P70qtCF-+_V2o&Djfr8~d8gbAr7#=GM*BFaG)ZW31mn%^TcRE^9Vl uxbfEDl*-DR_p;WW_jI3rg`s52Ir)%tAp*012^Ij|!QkoY=d#Wzp$PzP>0M<2 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/artifact/text.annotation.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/artifact/text.annotation.png new file mode 100644 index 0000000000000000000000000000000000000000..ab870a29537b0b696880f5f3c0129c50c1aabfa9 GIT binary patch literal 367 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 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/catching/message.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/catching/message.png new file mode 100644 index 0000000000000000000000000000000000000000..ba997f7d1eb651bae04598bc520494c611dff43b GIT binary patch literal 549 zcmV+=0^0qFP)_1Svv7N(G^VD2mefyp}*Ia8G3;6#N1yc!G2^6yT4->*yq6Ap|3>cJ|--XJ%(+ z4X7?5gbmxJq-I)@G?O#~su<%%-9B3?wq2IxuI&l11{_OjNooPdz?$tzvhfuUkZtFA zKDK=$%d*~JF!-u#q}%PT&*$?~;M-_4+5#}3vMhIjSJ#nNiS5T#RUJCd^9|b*NjK9) z1m3P7Jpe*FUILp9+a+*fyD#Yo=-K{URn=jgoU*(l=}6N3#3?c@Dm_gR&VU`@pe)ON zjob$gfF0Xs37$%7Ws;h<&zHtA#m^jX%`tS=xWD zGH7TqAnj#qLkL^8-${CI`=cZQw}1~Jgu7Xm{YY5b_N<}Blywq#+jb9l5@UQ>3-l?3 z@ZI)%;51kvb{iCQpff^ n+b@R0;cF7{%E40p_B;OqTC)QV^had)00000NkvXXu0mjfF=Fmq literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/catching/signal.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/catching/signal.png new file mode 100644 index 0000000000000000000000000000000000000000..19ea91858e1f1c91156e76a78b0a7755d1396875 GIT binary patch literal 627 zcmV-(0*w8MP)dix-joVSMp1M~av^C)(iMOPfQF0cSpzr(pBp1e*7bOe;Q54N2{j}d_J}CW3l58Z6NQTCCdRgskQ55e0oXzL+yZL;62jI-w zsL(;G zJkN8gjKTeaJO=>Bae5?g(=@%_Di>**UX#3a9H$2WmRT9xZ&|b3?LGl8Bze3ISIRyH zFto8v06!kaNb-%OuK@V31Xe`ym84IST9kw+iVh{cc3rnU7z~QX=;3f^*6Z~*lAqHw zegEhxZ_D3SndLQ-WEh5hNvD!V0G8!=ZNr)*-;z8ZkH;TmLH_SK{{ew55NEsU{ABb@?P)^WOJnc<+0Z zgfhC_?jgw-KqEf@um-S}Gs**+k4gefT8cC{>T;)0Z%aa6> zjH2ir$(k|dNt&ix>_M;ByXU>1Ncy!{EKVfJ0D!f2K(ZEwVe2X~0HkTU4a2ZSvSzIv z005&XIwZL=#vENo27ow@9|QPKa^tpNA7ew)gTDY0JJ1^oO9c5w>u_j zD|x3!dtQ40;FY9XK@i*l@Oih}HI~ce&phQEz_SW~2FViuEEkY;2H<|~e$BG%Q8`ZX z4S;V3SL1iduD09l+xwCXE(LP>Z-C?r03S)N0eq>~>mU04{@v0KPXVkexKvpaz}s?x z`F#E!z)|5_Yah;Lvmevxw76;l`1D_6ERYN8LejBu&TU8zz4wzONv`V&03b;c00000 LNkvXXu0mjfshaW4 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/connector/association.undirected.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/connector/association.undirected.png new file mode 100644 index 0000000000000000000000000000000000000000..f7954dce42305c445aef3fc5a0b2c7c3de6b004f GIT binary patch literal 413 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4U&3S%?H-dpd)1FqB%kj+BQ95nF&5jo<&x=~!1ki}6doW47)0d-u(KjaRQ)^>^*^=?*S=Gk$*4FTTEIsm|$VnX~M8 zD+8igyjFI0+!4I!EFT*#9ep7x-r(~gOY_awb}2GuGcCQcuR~|%&(sx_z7tY!h6=E> z=iZ(dm2KZXi!mYS`qwEl=QG+!CEq(XgE8T8_Pa&;CPi;W*YZwN0R|<5r>mdKI;Vst E0Dya?kN^Mx literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/connector/association.unidirectional.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/connector/association.unidirectional.png new file mode 100644 index 0000000000000000000000000000000000000000..7a9be868d08efc8876b7039161b6db935f62d259 GIT binary patch literal 3032 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 LNkvXXu0mjfl>OB5 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/connector/sequenceflow.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/connector/sequenceflow.png new file mode 100644 index 0000000000000000000000000000000000000000..d757a24405b663ff6c7432b8fd66455169f2b293 GIT binary patch literal 346 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4rjid%bTNf8i5*AgAEn&J$TRpDB{(zh2?QZC=V- zSy(uh++%hWh#VMgLwe{*RkDi&eRM_~o{@3{Q z0>fjR&H literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/dataobject/data.store.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/dataobject/data.store.png new file mode 100644 index 0000000000000000000000000000000000000000..922f66f708b86ba3e38a90de2040ece9d05f5228 GIT binary patch literal 3184 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 WT7M%~IriZI00002?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4$h?Za;hN`RR?# u+P?*i;stC5&o)0k9JS%d4Udx2I>yQg)|@LcyOscrW$<+Mb6Mw<&;$Ubh(s0u literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/endevent/cancel.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/endevent/cancel.png new file mode 100644 index 0000000000000000000000000000000000000000..a4302bf88bfe9f8471042ef3e37694970de9872e GIT binary patch literal 910 zcmV;919AL`P)VGd000McNliru-vtX5MFU`FXJ^&L#l`Oy78V`@Kwn=U$z(DV07#OAMllT2z`Cvn`}_M} zc6D|60DJ&70CiCm{X`;hWLehu^(-L-06<+6EX#HhLN;r)ni`EpHw8iXd3bo3Jvut_ zwzjs~s@3YFgM)(*&+{+J4;%QItPy+a4bs9p!MRW@cvIOD2;m zO-)Uw9LMDx#~}bfFE204=jZ3Y$+Fy<$z(px=kw9s-Q7ILaq87BrD@v3jg5^TRaO0^ zy}kXpq9|WjmX!qnWHOmg0r(RW6W>lxPu~xPLOuXr6vfx7s>Wqm{)}bWe+eOeEEfB9 zZEY=S7)C*oq}TKF^Exz5dm%}Z>-&BH0NvW!`iy1SO8~wg2>UF{9$(=%ilRIKfbQ<@ zC$cR6-Ou@;iIF7S$adFX3Q51NdFGeDfM|*pF1puIF z`X9qEBF)Xs-L&hv7k34#R4TW6-}m7-&P|H)JP*}s^%8AuZMmxxLICKNmX>FPkjpC_ z_BoC_2HB2LKR{$DfL#SPF;3NhY062X=OLJ}H$-^w7}IX|Y&*RW6qqMN#sK zqKpC9t=H=xdY;#z>$*BOH@CmNz5QjSQh96J_A9KctjLC8{1pfUPN$}(-cP5~U&Z6` z9Z8ZJZ`5`Dp=p}GPfkvLplO<|s;Y0A<~NOlZW<|@&5n$R4Ual(#gpQ zdB@5u%Wk@^8|mrkDY~xv{m94&cX)W{<@5Qd=Xq15Qi%wH@WU-D-wabM77M0Qsh7RI zy|=<7%d$T(Fz|M8aPXZl(Vpi)6h#2Q>gwt-&-0H9g#xi{``*&h(o!y$`~2+ejA9t( kUN9K^={nA}S`7g3AKq>r_Y}*bn*aa+07*qoM6N<$g6qAjX8-^I literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/endevent/error.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/endevent/error.png new file mode 100644 index 0000000000000000000000000000000000000000..3e310a73b4a7d23e61f2a80e29e57bad1e8718f9 GIT binary patch literal 757 zcmV?woGV0Z5rl$*E+Zrqq;wZT-9&IvNN(W9g`i~9U0SMOB1FX`L~xY`x-g^!JGFrXKh_TJBT zNF0Fo{t9p=lHND7&w-E3%;x9kFXeeYY-S$=o02wqdV0pa_um3&baZquw%rSCrfGV% zEX#F3z#mmreOMI5Zq%p0R;x9us;Wzxs;cU!bIzTQ$tLN`s;WMX$pG~&Bjg9RGevq^z>2(x;#Qj@~H}!h`grvP@HlFACPr!qSohr-nXP`fXuw-UE z9dZXeiEM`@odJFw8XEc$AW4#OAjIHdfDpnjz|rVicam1(=XXg>=iE1wlam2pc6Rm| zkau;t=A1hK9E(LCy0R>9OKO|hV>7$gZnw9(MXai7g7?dXnJr100aD;?S(ekTD2gp$ zB80FisnOThx8l9;v`A4DuYj3YaSiw++EYbQY^4C(+uOGW1_sUn7b5s1%d$1#k(srf zb1P={MiTM(?lu~Y8vyFQM(_RCl5X*SvAW+Da1%HJ?CkFD-dtQX)4931o$mN|Yj^t$$N)2W00000NkvXXu0mjfju>Dl literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/endevent/none.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/endevent/none.png new file mode 100644 index 0000000000000000000000000000000000000000..c46d16020b9370076ebb6adaa69af35e0480aa00 GIT binary patch literal 467 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 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/gateway/eventbased.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/gateway/eventbased.png new file mode 100644 index 0000000000000000000000000000000000000000..7aa78b7186eefed78043a9c42d5b0a761888b372 GIT binary patch literal 492 zcmVSmS1&4N|+Fbu;X08cXT z-anH(m?e=cVg`%IHOV6p+3)xJ_vu~>z$M8G5!nMU%)$!EU)ao!opV<~5G?n4y|=>Y z76H77$S%qAOyaWIs=7KD48{Py%q%I+I+;v90BEDp7^~_k(%YG8z@K>@%xt|VsMTsM z08gDx$EG5tvy8m=k5LrWN!|k3E(!qbnAuGfMRo7}BY;sH$K6sy=UmIoUP<0f)fU-E zl4L0i!~0UiT&V0OIwTiF#E}#cac1@|A}4vcB*;tBsGk6kJNB^nE=q!;1OTewN2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4#|^;P`aR=xhX+SiCZv|Va8I0 z^ac-`@^i9tirEEcE>}=f&6{PovT=lXdwBs_}>-Op$foxPo* zZ0^Qo`s-G`@^A@ekTkx2CWiS$M@CfW)s6Ex*M_ZTasV3r{0<|-C!6iZW`u|CWoJ;T z%D?^Xpr!i5nw+(NSvJVmu)hE65vqPSDpdX6?~4~=g|lt~&8?i*-`O#vviZJT1-EhX zGhV^Kj(w~f^iOY+Fu5pEynNO6Rlg*>Dijy3-C+hD`Kbm|I2o24@pRzfJni_=)q!Q_kGb^>5&5^y#UI>s9~kxwp00i_>zopr08P=d AmH+?% literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/gateway/inclusive.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/gateway/inclusive.png new file mode 100644 index 0000000000000000000000000000000000000000..13e84f633bc517f7dc483cf37ed8c3980c7b086a GIT binary patch literal 432 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4jnIb+#=PAB~fjPKs>`2mo2J`bQ|J03MJbT z#jQ`yDXz~+kNn2Dz+Q&${KBiNR_$YWa&D)%;*rb}r{r77=NY(^e$8n48m-;rZaQc-C6@pjD*J%xrlf6v() Y%)hjA!=>mCz|dvzboFyt=akR{0Be`5RR910 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/gateway/parallel.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/gateway/parallel.png new file mode 100644 index 0000000000000000000000000000000000000000..ef82f48737b83912c5a042e90549ec8773410e55 GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4|lnl(#2 z-^lJzHN0%1>!7am_}Vr#1`kci_kRyterK_JCH1~dbLk4@oV!b=oGIHLR?qle;&D=9 zeP;giJEyDvUsxrZxMEv@s%7(c!B-a2?#=$J?wk#5tDB-W$@xEAwqTOU{?GhBm39RL TohoPq`iQ~P)z4*}Q$iB}c07G} literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/startevent/error.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/startevent/error.png new file mode 100644 index 0000000000000000000000000000000000000000..27603c4c86986f6f5b1a4a5b813ed68ddb8eec67 GIT binary patch literal 698 zcmV;r0!96aP)x!jk~$GbD!tA z=iKuglSFl8S=Mf54WI>Bp29Q0jHF_Cc=&Y{9~KT~X7zggh?z|TUBFsk2hb(yrlh52 zHkmN?k0%K;v)vvwTm|+3*MaZAbKpJj2AD{k+P^l&7*_zD zz?!t508XWn27sTy;nd=Z1zwuS$`7v0vxP#Z3Os~G6L8FOyqgqW@i18 z+$2%2*Dp#sYG(aKQQWBr5M%5C?$fmPTQl1s>71E8D2n2804U4y8SqikzC6#{ssipl z2FwEYfF+X7OZw*SLy%?xn!^-h9FR09={7J`Y42X(Eb!aRj=TGi64CxM&UKmwtEKP^ g&<>2c`|&FNFLL7VV$&j+9{>OV07*qoM6N<$f>UQZpa1{> literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/startevent/message.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/startevent/message.png new file mode 100644 index 0000000000000000000000000000000000000000..ba997f7d1eb651bae04598bc520494c611dff43b GIT binary patch literal 549 zcmV+=0^0qFP)_1Svv7N(G^VD2mefyp}*Ia8G3;6#N1yc!G2^6yT4->*yq6Ap|3>cJ|--XJ%(+ z4X7?5gbmxJq-I)@G?O#~su<%%-9B3?wq2IxuI&l11{_OjNooPdz?$tzvhfuUkZtFA zKDK=$%d*~JF!-u#q}%PT&*$?~;M-_4+5#}3vMhIjSJ#nNiS5T#RUJCd^9|b*NjK9) z1m3P7Jpe*FUILp9+a+*fyD#Yo=-K{URn=jgoU*(l=}6N3#3?c@Dm_gR&VU`@pe)ON zjob$gfF0Xs37$%7Ws;h<&zHtA#m^jX%`tS=xWD zGH7TqAnj#qLkL^8-${CI`=cZQw}1~Jgu7Xm{YY5b_N<}Blywq#+jb9l5@UQ>3-l?3 z@ZI)%;51kvb{iCQpff^ n+b@R0;cF7{%E40p_B;OqTC)QV^had)00000NkvXXu0mjfF=Fmq literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/startevent/none.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/startevent/none.png new file mode 100644 index 0000000000000000000000000000000000000000..8b51f188c67b12bb1584925443c30540838dc16e GIT binary patch literal 450 zcmV;z0X_bSP)N82~Rw)gOdvn_zSu73c75W?54>z?(7QcA;8 z%F6c3X0!QX+d-0IjB{X6Rn`69U`gt_?zyU}dteY_oJ$gQUEc!R5W=T_!Ea3R)Ar{8 zG`5%5!ly}WFM$|zOnP@Me5ReGaga0ue!Z9OnNhgtyr7_CLGIoQ_RK!$*s{rgJU)^1 zJJ@~#W+|oNwPZ?Z2+VA+L(cgCEJ`V>wrwwF(zb0VrL2HO&iU}+Ds$RKfEeT4_BY#0 sNxRec_JK`+8L(Kd*WcZPd~}^(0hW8fflBbtcK`qY07*qoM6N<$g6RXvH~;_u literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/startevent/signal.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/startevent/signal.png new file mode 100644 index 0000000000000000000000000000000000000000..828a260b602fcc09fed6ada9c77d8f8c77421f28 GIT binary patch literal 3201 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 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/startevent/timer.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/startevent/timer.png new file mode 100644 index 0000000000000000000000000000000000000000..adb275f4e91a42d1202157b5da038036310928ca GIT binary patch literal 573 zcmV-D0>b@?P)^WOJnc<+0Z zgfhC_?jgw-KqEf@um-S}Gs**+k4gefT8cC{>T;)0Z%aa6> zjH2ir$(k|dNt&ix>_M;ByXU>1Ncy!{EKVfJ0D!f2K(ZEwVe2X~0HkTU4a2ZSvSzIv z005&XIwZL=#vENo27ow@9|QPKa^tpNA7ew)gTDY0JJ1^oO9c5w>u_j zD|x3!dtQ40;FY9XK@i*l@Oih}HI~ce&phQEz_SW~2FViuEEkY;2H<|~e$BG%Q8`ZX z4S;V3SL1iduD09l+xwCXE(LP>Z-C?r03S)N0eq>~>mU04{@v0KPXVkexKvpaz}s?x z`F#E!z)|5_Yah;Lvmevxw76;l`1D_6ERYN8LejBu&TU8zz4wzONv`V&03b;c00000 LNkvXXu0mjfshaW4 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/swimlane/lane.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/swimlane/lane.png new file mode 100644 index 0000000000000000000000000000000000000000..f0e7a823bfc279536b4fd273c5569293895ae4d6 GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4E*@+V;{%5!2apRTX;p{AYk*>z@ YZwjCKM~f}Xfo3pxy85}Sb4q9e04&ru8vp2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4FNiO__p2z1T2)njmh^izo4t`F0|3ss5y@s8#}_0U*4jeSnB+Oh zb4g=sZ9%dTFiq#&2mqKQ$tlUXG3F)7hWGxPr0YD-@1M-(lH`rG_O+xxRaO0v^vaOT zB#q0m+g= zqzTDk6h$p-?SSOXA(2{)gD8qxB!`lwl!PqHt|YyUpz|IU%CG- UaOb0x?*IS*07*qoM6N<$g3Gi16951J literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/throwing/signal.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/bpmn2.0/icons/throwing/signal.png new file mode 100644 index 0000000000000000000000000000000000000000..c5979fbfa5fa0bbe98f38dba4b6e038e39cbce4d GIT binary patch literal 747 zcmVcBAHq$VKDRVY4b)#t3?Ms zxLm$-?&Uk@qa-w9aB$EkSpd)-7XYjPSdml=!?4`gZ}kI777B$Ck_(brB#i^e0LVxh zm()UXA@1P;0g?=YU`|rMnPtN;9Bpc9`ckP>ewf)FfXy%rN6joNsXqvUxw;4?p-?D{ zNa|0g)4gkJYiTnJNv@jNR1`(uNR9zGD(PBBN5|)ljg5CCXN$$+GX_E6lUy*fY!pRD z0K6snvQnwsPo+}tC2j5O>FMcv zsZ=Ttpo`>{WHOlv!|*nMJ0!<^-`|upK{9Xgq!-uM*DnHSZ*Fc5hlYll0X*Cvl-W}N z@I0>wptD>qX8J#nRD)YR`F#HB)YQ~Z0P~W%NG=2D zwuV=#lC}p1295!^i$fs!B$vxI0jNl-)$bFXot?dszLQ)7ATtX{<_-%0IG#)XRgk8&oQl`bf??=a$UuF@QDzuj6Vnv&YW4C6cpsG7#@V dBmQ@te*@$jHU6@4@HhYf002ovPDHLkV1l7MKcWBt literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/casefileitem.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/casefileitem.png new file mode 100644 index 0000000000000000000000000000000000000000..5c42a8f8a9b38539a803aa8321942604855e5cc4 GIT binary patch literal 2937 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 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/casetask.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/casetask.png new file mode 100644 index 0000000000000000000000000000000000000000..68be8d60547c3e95647e35c4bd3f4a4948ad38c6 GIT binary patch literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ydu{YLn>}1CoEt!Ff;qt&nvuk zW{PEunb0AYT$NK>n-4SOvq@*2ywE%%@Qj&Bpo624VzOSbXlIV2}PR$0OO zG+-BBmVk_M=hbP`rpak(X<4zEE9mO#?%TAfNbE$Kiu$621=?H-@3B0-a^*_Rlp`)> dUNQv?405ZUf7p?`u@LBR22WQ%mvv4FO#tE1Qj-7x literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/collapsed.planfragment.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/collapsed.planfragment.png new file mode 100644 index 0000000000000000000000000000000000000000..68e6ec2f9df461c191c2b8bce57c2076dc5a65d1 GIT binary patch literal 629 zcmV-*0*d{KP)E))u%)9LgN02F1ZRB98^+j6=5$uNu?P1CLbSds4c06eQyDj$jHb~c+)5Cn8C zcDo&QyIpb|=T1?SHGn4vJuF30*6nuttng1U9*=3i-@hgzK-07<$8qldi*Sh5YPGg) z`zf;7?6BYOKZHTOUXKjJ_zEI=^B@8d1wlZPB>lXYPN#Z4p9cVhVTi?If&0R;EJ%_B zS(Xuop#%UiSqKrg^=~PJh&9Dx@r!h>5@QTP2yo8fx-K~95JG@4cCvRk9A2Mw5>>iy zO+?gaG_Ef)nM?rSQIhWaKIZc|mdhmo#Ix`FCr)a$TIHxaQ6<-P&)!A!J#rFt2b0O< z#dfUBnsvGMy P00000NkvXXu0mjfv(XGa literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/decisiontask.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/decisiontask.png new file mode 100644 index 0000000000000000000000000000000000000000..0351fee8a4a147e3e54c9ddbfcd9dddc25fe693d GIT binary patch literal 299 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt@+JY5_^ zEP9V#HuPdn6k&PbfAN@8N7zBPX%$T+Nr~xi8FP}?rR1v19k}GQp-WsqOgngGLSnKD z_xa=F`tQrtuRYq=E}ZkHFt1VCX8DJP_kGvbs8t+QzSrFUv1$2( z-#5-G<~(Mw?s5!Pic1Xop|ZtA*w}mS>Vpi27x6l0hh4wMHT#E-p!g4teWLoOyLOhX zJhVb($FVIRGBY{@!y>K=@72EIYvU??UVO*l)DOlo4{a)x_j#FSbRU#{)_UGKd#!@@ vo!@u+_3ST+^IcA8NWOdSQ0|gn>3V;J literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/expanded.planfragment.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/expanded.planfragment.png new file mode 100644 index 0000000000000000000000000000000000000000..c68cd0a80238b1d6ff9bcbc5c97254ad73527ee4 GIT binary patch literal 386 zcmV-|0e$|7P)3tRf{ z-@gw}pFaKn^XJe1*ueMi-~XRFb?SdXLBS7BPR@@&eI_si#6SWE4jlMT3b=Xm=Ko*6 zekFrV067h0@_#bGt5>f+>gnk@Gl+?aT{v^*3^``}KYjZ2e_$BhWdH_P<$p2(DC`&+ z8UHfezkk2uKLr39gAA0I@gEo_Hz+m)lzu2Sq@|^01p_-f`wxo4getLf{rdIb&!0b& zWysmHXF=)Y9s?H_*Bn@ieg6D8QJP`uE?&I&31~i^DVm02yACUwbomRsaA107*qoM6N<$g3Uapp8x;= literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/httptask.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/httptask.png new file mode 100644 index 0000000000000000000000000000000000000000..ffba8de117c51945335082019349be32dacc78a4 GIT binary patch literal 1267 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0WW zg+Z8+Vb&Z81_tJ3nIRD+5xzcF$@#f@i7EL>sd^Q;1whpd3^o;3KxS@gNuokUZcbjY zRfVk*ScMgk4HDK@QUEI{$+lIB@C{IK&M!(;Fx4~BGf=YQQczH^DN0GR3UYCSY6tRc zl`=|73as??%gf94%8m8%i_-NCEiEne4UF`SjC6r2bc-wVN)jt{^NN)rhQQ2mNi9w; z$}A|!%+FH*nVXoDUs__Tqy(}E4xsMLEr45;R}A$P(0}?Bi3R$GdItK~G?iqgA)JSz z3nYV6TWUon4s9SAh&FIwK-_2p3{flJ{FKbJN|(fvR68RBLsMM?V_jpz5JL+q17j;g za~pj$H3%PqbvqZOCYIzEh2-bw*ac)(q~_#;xC+L4#t@yz@<>`izOeEy%1i|YFDMZ0 z3~lr=#L(3{=jRp_r4|>1)SE)pBa5M{4@xc0&nX2NADWk0VrK-^f+mcvD-t1ZXAaYY zEQqcl0-FY8K_m^JXs`l@Q-n)qZfYLbFNS6|`dB54=o-U3d7J^$R?dD?) z6mdQNSY1VG;tLTgUMa!OL-H$FT2~xle^KJ}I#|R@v|eH2i;g~lj}g{}CuP&rj0LSD zji1lke17h4iPOIVCkp%x++%sdiOtNQ*+J_;)Pc(hJ~AG%G3o)I1+J{v!59|9FJHRS z_rSeZjXxO6BMwgwO4)Kp>&rv7XPe$u_}Q`XsY>J?G^^ZuzT#8gx$g;53nEYF?=}_p z%!-eT5B{PY?6SNRln4WvVW_^4+wgGn%2?42r7v@UHx3vIVCg!0Kr9^jsO4v literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/humantask.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/humantask.png new file mode 100644 index 0000000000000000000000000000000000000000..f19f6ef41f96a62c2ff63c471d710c0d34dfb1b0 GIT binary patch literal 3015 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 JPDHLkV1i?9m8bv! literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/milestone.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/milestone.png new file mode 100644 index 0000000000000000000000000000000000000000..6c2e106b7163bad5c42f09d1a5856f1d29a26484 GIT binary patch literal 285 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b zKpodXn9)gNb_Gz7y~NYkmHjTGJU^Gh+|4fGK%rHhE{-7KMl=YlGo4&VjR2*PS&ousTtbE%$)io`Q^GlZSm)jbG z-Z}=a64qIyKHKOkAeb#GJb7lB?bCezm;e7eZ9O2X Ye{HVqnRy=UKvy$(y85}Sb4q9e09LzdK>z>% literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/processtask.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/processtask.png new file mode 100644 index 0000000000000000000000000000000000000000..ff9130bf5d0311b52a470da7529f4613dbced090 GIT binary patch literal 102 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`x}GkMAr-fh6C_we82_I<5W(xI z%J|r{MZ!Va+2dl*!g)z&mplq7**~GHU6_I4pq9a-?wJ1tK#dHZu6{1-oD!M2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4a{Eo zn0Wfbr!@=JnKtO0{=~L}g+tG7(JHmrEvr_U?~zU{`O9d}kixL)7mHZuJoo!-Upp3F p=WqC4$8N&;OzOt*rrE#F>6e=rtPQ{1&j@rhgQu&X%Q~loCIAlOZjJx| literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/servicetask.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/servicetask.png new file mode 100644 index 0000000000000000000000000000000000000000..8035fb984d9755f8befddfba0ca29928d16161bd GIT binary patch literal 530 zcmV+t0`2{YP)b8E^u;0q!SBvR4$v$*P3!q4)vNS=qE%%l!=8WeG)5T!qOI6X0WbCbj%| z;Qo;i4C?@+Fm2+Tdp#bHe*kp5-4~5U;{tdbHq)$07*qoM6N<$f}+0Zod5s; literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/task.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/task.png new file mode 100644 index 0000000000000000000000000000000000000000..40c8f70211f226436f34b17ed42082808692ceb8 GIT binary patch literal 2990 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 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/timereventlistener.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/activity/timereventlistener.png new file mode 100644 index 0000000000000000000000000000000000000000..adb275f4e91a42d1202157b5da038036310928ca GIT binary patch literal 573 zcmV-D0>b@?P)^WOJnc<+0Z zgfhC_?jgw-KqEf@um-S}Gs**+k4gefT8cC{>T;)0Z%aa6> zjH2ir$(k|dNt&ix>_M;ByXU>1Ncy!{EKVfJ0D!f2K(ZEwVe2X~0HkTU4a2ZSvSzIv z005&XIwZL=#vENo27ow@9|QPKa^tpNA7ew)gTDY0JJ1^oO9c5w>u_j zD|x3!dtQ40;FY9XK@i*l@Oih}HI~ce&phQEz_SW~2FViuEEkY;2H<|~e$BG%Q8`ZX z4S;V3SL1iduD09l+xwCXE(LP>Z-C?r03S)N0eq>~>mU04{@v0KPXVkexKvpaz}s?x z`F#E!z)|5_Yah;Lvmevxw76;l`1D_6ERYN8LejBu&TU8zz4wzONv`V&03b;c00000 LNkvXXu0mjfshaW4 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/connection/connector.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/connection/connector.png new file mode 100644 index 0000000000000000000000000000000000000000..34462c3d7a733bfe6b2bd99e60f3ffe353c76775 GIT binary patch literal 2988 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 iA^zeg*0SV*{0#tG3@+FTp2Pb90000@86d#I z!g4P+H#a?PL=00000NkvXXu0mjf3G!!g literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/containers/collapsed.stage.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/containers/collapsed.stage.png new file mode 100644 index 0000000000000000000000000000000000000000..1c2c21c67007b808e4a97bb93858dc27979a88c9 GIT binary patch literal 625 zcmV-%0*?KOP)gyMY>-4%MKn*M^qu_H3})=#Jyg{%|O$^PjJ%Qx`;pQvml$sQ{3V z;+Vg`s5=AX9LISZ3$)oOK@PN%yf0+wYx6pO{(a=H8z;H2epDaB%OXIa(*N~vHnnfw>v zq{(C=N~s_Li2Ugb0E@+fFbuh+TrP)g+W;gI2{=MxmCNN1kM|V)en0jDlDxK3uh+vE z!)!LgbzNq&8O9ilF_cQBcmAu8Y&MJ5np7%9x7#I^N};tzYmH@D@BHc-BnSdL&tpEH z1H_}_I9Gd=R7&lq)9J0qv0P82LNo_Mr%zzp9dhH z&!e@Dw<97n8V!H5**u3~_@V%|+wIe6H2T(Vx4#2l*6TH%=i&Q4uIu9aKAz_R5JeIF ze*f2KH2SgKZl7YRoW0_^ySsnh6Wg|b^7kv2%l~A53vkSTJ+J!>_#Fw7YCcac00000 LNkvXXu0mjfM`08j literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/containers/expanded.stage.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/containers/expanded.stage.png new file mode 100644 index 0000000000000000000000000000000000000000..01535249653b47e152cc4006e170445d3cabbc28 GIT binary patch literal 252 zcmVkb00lkbVYGKwZ9k z`9C=Tqz@X<3@FYd);ll&jWveKLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0004?Nkl|4!&-bt zJ(}A~jCml2*3+~o@H#jzBBh4nAIVi5j)~jw7M&u-O<*$~;cSSO^(6P<3htwYofyYL zImZ3CjZvJ$iHz)3x*ftDG;ksK4SXvL)Uq6>vW2aTbvTPOp4ceX;bKgkE(=uh(;UO~ z$a)!Lmj`)!x;8SY88jKLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0007qNklPurUX%GN~MD0C1@-8xyeng#?Um4%NHnuc;JJN!})p7 zdEaB<-_{2l1HJ<9fi0lLe{3%>4wQf_Fbk}R#Fu~{umP5KLdTBe!@xX{1a1Q#gnt&e z18f5KfoYinz}!r|~Wpf2_k1r!MgicJp}3Wbtk81tD- zCLat2i;AN3&CSidayT5>?(Xh!(=<&WELb@L$P(ZI%D{e2)0(m@OT}U_-)J>FWy%3y%VUfJ;%7 z+Q`U=9Wcbw%YY;S8Q>7`R+eS8)oO*K(dfZ=JnkA87}%VdnehVB#>U2|uIoom30y&+df`n$G_hKr ztnk92+b&kRU=Yr&+-S7u!WJH56?oC*@#%lYD@Zixz>fpxec%84p65KLscHF34_&Yi z6d-H*k83U5gI`dB6cmAA6m|i(T$qtf4niAv;5r-w3!H|}a0+;k|GjgOEeybS_y|dM z{{d&&_!~G5YZ^oDLJ0aG2b*9wnAyn=!WbKGhcB=VRMO(run2bP?(_NDtX6BM-|w&4 z?e!pAL@J@Png+eiwNF*G|WK#5aJjC-n1uq6^{?j~F ztJSL<$7L|@0z_Z{wn_nR7=b%VrSj?A+}yc*J})AKiXV!UNoS~BE|VyVVU&4tBxe*H_pH@qnn-6d;^fpc zJ$y7kQ`7IMP$-bY;TXpWAFv_{tmyjsXSBksPN!?PSS;fjjfRe*h&OKDBCpp=TCJ9> zHrrdH(YOcm;t+*a*jNu(B{h&-E}!h`?(UC7qhg?^hg@zq_4M{qEEc0sD0Ckuc+A?n zh4len50HABZ*Fe(q0);6gMkh?opi+IqK=NkWHy_BqkvVlS{-AH4Xk@tG`6#xC2ocj z&=0TR1)PWdU}8H2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4xr7I$t=sh%>yFd%slu%$el^hqPKYBt5&V z#2)o}Z}GdR?5R2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4%A|cen|}T~^H-C~ VHCaiM%79K}@O1TaS?83{1OVlqVJ!dv literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/tables/planningtable.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/cmmn1.1/icons/tables/planningtable.png new file mode 100644 index 0000000000000000000000000000000000000000..80ed1f9b344faa2ac7380b4b9eb703f782de4fd0 GIT binary patch literal 476 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 P?E;kLHRS4KEkgeXtz233 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_checkbox.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_checkbox.png new file mode 100644 index 0000000000000000000000000000000000000000..463c9a2747683cb05695d2ae5ec6af703fe38f41 GIT binary patch literal 308 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4=z%BmB7a?00Gh0`Eg(OYaBdt>&MY`;1{L%dSj$Y^P36qwHygJs{Sd)0~ zIL{f5=Q7?&TRZ->9<&mPdL8-sN~!K7Hipnp#)P%LhmOsdc&<-jX-|>G_rTaIju`^S z9`5kJrfU77UD!47$C-nX%njSJCj?z8>-}GSCq6K?jHTgi-sAi4pQqQcUq79@q`2Uk xLd&uQ2Eltx*KTPpRby<}r1Mv)^S}Kv{SWta#3N#hT!D^f@O1TaS?83{1OU$acryS1 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_choices.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_choices.png new file mode 100644 index 0000000000000000000000000000000000000000..45b779bcd7b216eabc2a1408388042f610f7f6ec GIT binary patch literal 206 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{E zL4Lvi|1(@a#S1i$!N$|YF{I+woIXQ71_KVJ#{c%a+7^c1^eXuvB#^-=-yrncNn#RX wWb)OMoEaBNjOVF3L@1fubK4mEm&1TzbvGk3lhlSYKyw&8UHx3vIVCg!07Vf%@&Et; literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_combo.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_combo.png new file mode 100644 index 0000000000000000000000000000000000000000..aba156d817d23fb494c06449351fa72ad95fa9b7 GIT binary patch literal 278 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4Z` z6iPSHzL+IQ9<+8Fiou}Z4(txReK0>JHF@ZP19#@kocl9_suFX)nCZjgz0MaiJ>M_W zL{<6vo~!3gs8+8Sjc)P%DTl)k=g4d0@g0NyP$~ePH^Fs#?DzZRg6sA&26@f%CJg#R z3_1AzG{04b^2rB4+JZ5HF@lKDYPD&%9YiEy zx7&+igNVsi03ad&*!DF+utrsBHe0M#OC0AWNumm>X$vMbI5}@Nn@koF!)momlEf^m zAck$*1VIqZBsBw#SYlAG*9pT-G_=$-pCn@tAFwQo?RFcz$dSBWY7oP+tRxP@kVc~p zK(pCmy2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4lnOExHWRnv! zZ$8>P|HoXz=QWvYV^wWC4E0{AELBNh&2v8fM3?POKLW!!PC{xWt~$(69BGaT2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4!>igU;U~&f8LzN znacyu%*_>PU911-^>5)g6=wlKHTm^^SIWz+E}U}6NOcIw6Pd{4xOh9`@3{$$-!}E! zf5qSb{lgX`3!C>z7IlSHd+*+HR&nOAW-jM+VTzJGt?;4R;+34WcSlM_EJMS=7dJZ( z*8NU+<|HZ5Ig`8besorX-ZJhl+k0;BmR_?p>TI`Ht!&|+mY;J}3|IB?F3D`VmB#wF suIpErXymko8)Kd4J)d@P|Nmq1uh<@|n9U8m1Pnh0Pgg&ebxsLQ0IX4;!~g&Q literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_header.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_header.png new file mode 100644 index 0000000000000000000000000000000000000000..d15165f4be9dca17a7058422e6a334be90794ff9 GIT binary patch literal 277 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4B$alzq$2C4ctSyddrSrsH1xIC+k0-o2ajuDlS!nu;10u6eW_2npIi;PyY2PII z-^U$8KW-?#%ckVu<>{^2!J*W2RrhRGsOoc>MV7Mu?Y{c{&re@sJn;9|tt*X!dlcOo zj(`64)aXm{imhVK_Ii>fzxf(|+6HIqzM1n|`aj!h*Qn+Hy;m3NPpWR=Hzopr0E@h2`v3p{ literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_help.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_help.png new file mode 100644 index 0000000000000000000000000000000000000000..a481373874c78080dc79ff6d015c0ef75664db07 GIT binary patch literal 393 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{E(;F6(&$;aXDWW+34W*J?{ViUQ?HsjSSK6`6N5@XUBzKo-O>tNr^>5=&tp# z;|`{60X4NY4;35|u0CchB-Kiv$D9G}gkkCy&Si-OAwU>gTe~DWM4f8zq#L literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_hint.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_hint.png new file mode 100644 index 0000000000000000000000000000000000000000..457dbbf2276e70fa94dfed6d73f1a8456b7c8adf GIT binary patch literal 352 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{EG|Lu}>cd1Nox$KMQ&v(qzsm=t7%QfZ8-rH+ZlO=r@NM=gcWlLY*X;Pmfb7HkY zc8t{BJthsgGBaCL>vCl7?lGQna>6#Cq5YmNjv*DdV)`Tb4m)r-_s%>sYsv3>zvpi@ zSiB;%_enoHQ_rcbK6;;@9^rcDGKtAEp-%l9S7@W>o-mf0)CCG(^pZ-#XHIaR{Dsp{ zAm{2<(@k49EAR^3G<7a%h&B;2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4)OXc?Iy=9lHT7pn z`puag3atH0UdD5*NR6Ciq`{!k_2}A$@Bca`JpZY>c5B3S(QCK1%P}O(OTYO&wk>hO zvP_q3-Kgx3_uRumOII<^j0`CVxNgd@;C;1#;FKWs-RnyodJOuMJ2-N0*KKXrcs=Lv zwp@mW%vp9~7Izs18#^wP#+D@YI7Uu0I2NPbqI!?f*!$QS&-N*Q{~Oyfo@1ZuG(Bxy Q6wpHqp00i_>zopr0KuDjhX4Qo literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_item.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_item.png new file mode 100644 index 0000000000000000000000000000000000000000..26e1dba2c5c94b1a08d80eed4d558c3039468320 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{ENI}7YHJg!%hoSN!!*$-Y9e;t!7(8A5 KT-G@yGywo~zAWbe literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_itemset.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_itemset.png new file mode 100644 index 0000000000000000000000000000000000000000..3f5170700e666867cbccf60c8b9a229f1efba7a2 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{E2?DzAWz!U#WAGfR#JisGmnWN0~1Fl3kL^J&q4-9Hiq;Q3~RGhn!AC@7(8A5 KT-G@yGywppqb&~r literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_label.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_label.png new file mode 100644 index 0000000000000000000000000000000000000000..d20cd3c387f2bbe3687c1422b4d480105f0d6880 GIT binary patch literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUfZd~z?Faq)=OI#yL zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+5i<5db&7>nLvDke3bO;(d42?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4)$dsMxr`E7gT z9W?QXtWDm|dcgmdKI;Vst E0379X4gdfE literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_output.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_output.png new file mode 100644 index 0000000000000000000000000000000000000000..b50cd8f46846049549a47f874a454e541724fcfc GIT binary patch literal 250 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{E}_o1RyuIv$bl0FPn|i!6ngN~xl>0@oM;kwkeHOv ikoE9b8n;6OBZI(QuG&1dxk*5?7(8A5T-G@yGywpyvtZ-^ literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_paragraph.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_paragraph.png new file mode 100644 index 0000000000000000000000000000000000000000..2caf4c1249005fe6ae14c516304c3cdab0450728 GIT binary patch literal 314 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4vnVo*2R;z_1N$Mzy5=|r$axfSK zV+_mX5~I<`T(8$3`~5zX&*$go5->p!I`Me?O4Br3GQZ!CNF*W~hH*6>k2?T)n3nM}HTK3}xeY85Qq(ZKC?XH%(^3;?fh zIv$$$n0`(%{hZ>Vd5_mO9RLuE#bi+wvkrspcB_U$AppSR;~z(}7N;l*cDtSGFd!m_ z=o~obwzo$EQ51)>*$e=XPG38O7PnX|APB#!_viC|DTz;I;_v(^5rZV!Yi;Ii@{{4rI zjm^~5R8&+WbYH!}YQ&CZMbaXB(Dsggh{qf`Hs#Rz~ScR=AS=* z{r&r|tE;E5uvk$^NnKsz^OvtXcI?`|eLEi?-@`{wl9N+^{P>}%simf-cKPx(CPpTH ze*WpxXHS_j{mGMO+1WYD$|}`0bw$OczkmP!_3QWi1&cB>a~?l_mYA4$>oXP+SJrqU0rKxYR<~SA}lQY z>C+dWk8-zr0KLZGSrX(I4CGP;Fz|594+R=J#nZ(xq~cc6hY!H;OXT1@BA3z7$T*i@ z=)(0U$>pU2)6Ckn5)2cbObD8k^7Q$ah8YVFoyb1&BypwQa&FVZ*P5i4#QHn)X0>tm zOWbgf3|-MMd8TrQ{({B4q7%}ue46m}!-h@8ZMP1oJXBlsMltI|4%1fG6Z0kp9(0}% yct zA*FQNjX-GKl3o1#10nr|aflO~bso45t?WqhLlV~MLa7_uq|j#31D8AZ&YhVvcg_fs zcn+jztp<=ezdWUFIZ!nP|Kf#V>O6dZ1dWvyV z*SFAYHUR+DY84lavnk4xEV9{Id_De>zQX4E)@VYO<*`mb1tBD;nv&`O0CKt9SOJ+l z2x!uN3(dA1yjWXX{XDmrMLvIm$G%X=V}9usip2sJmgi6^6|uN7k8-(;rPm9nR4Pz4 d1>(Q|#-CP09NK4u0QCR>002ovPDHLkV1hg#2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4z{}1H%C~fLpyY}cZj?M`(o+oam zBqS!@NNl_7J44dY!o~N!qQb9z{ihTd6wZI1-*&z9uF{gsUqQztcn&ip`%I{}U}(tP zbzrV6gTq{rO>a1|byuxw+G_S9A#&PT$Ga94_J@88mOfT!X%H~~Tm3)gz`Sgo5Kc|i zB~vs)e(rU;UTSmRxP8IaXWMckvt^%jcHHNxVG=BKatUmo^5?&CEaRG;D}^uZ;Hd+8 OhQZU-&t;ucLK6TX?|xta literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_select.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_select.png new file mode 100644 index 0000000000000000000000000000000000000000..568c6cb858609af44685f0d98e3a488a56bc83a2 GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{E_CVE6e}@ literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_select1.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_select1.png new file mode 100644 index 0000000000000000000000000000000000000000..4bbb9385cd9b02d4b5e3e6b6f78575273346d9b4 GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{EgTe~ HDWM4f=Y=hk literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_separator.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_separator.png new file mode 100644 index 0000000000000000000000000000000000000000..c46362be5f86a81475f0f2534d0eec5e76720c9c GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4w3x@Dul^hhdFJc|xKuFgP?YGCXeJWZ64?w>Qur22WQ%mvv4FO#t+2XtMwS literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_switch.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_switch.png new file mode 100644 index 0000000000000000000000000000000000000000..3d818beb262983104d7c10b17feec1880541caf1 GIT binary patch literal 524 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{Eo?*O5}P*f{QB)jZf?<)Yq$UZ|IZo9Jrn2whms(_U?7(gz;LK~ zqYKciHcuDFkcwML8@8t>FeGwt9{HBhz^HcUh;oJ+TNsz&GSBt88YF6!H^Vs$x zy6~e{fx^v2DQgd%(CvE@BmdKI;Vst0PnL9CIA2c literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_textarea.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_textarea.png new file mode 100644 index 0000000000000000000000000000000000000000..125fd8bcf3384f540bf31fbe2907866519f63f51 GIT binary patch literal 419 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4gP=?fp7;KO;jr-@|s##v8x@W$<+M Kb6Mw<&;$VRUZ^Ml literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_trigger.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_trigger.png new file mode 100644 index 0000000000000000000000000000000000000000..df1e2c53b12d0e78587d4ab3114cff139c630210 GIT binary patch literal 174 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{EM@T1 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_upload.png b/snow-flowable/src/main/resources/static/editor-app/stencilsets/xforms/icons/new_upload.png new file mode 100644 index 0000000000000000000000000000000000000000..5cc01398441add3c03cb725600f4c7e234310c31 GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{EJ9J-as3Yje{TSJ2?+^TuU>U= zw%WaGo|2NRl9JM@l@n&pXc83U+r4{tM|*KvYM8OH_NrB@IyyQ81qI)|duMEHoR*g6 z;^K1m?%mK3kMgqAySI10dvof{skJj_&I}C=EiW$@6%{>m=FGNj+hk>Bj~zRgh99IF!uPCFX8G`6fzK<@WtjlNm@YSx=e znrElDI2Jdrv7D{3_2HUJynTxl`VM_D`D1bEUs+gYbN0CteHm81x7j(*`&fj%vRt>D z+2qx%9|8|;^y--XRK;R?kMb2v4HsD18dUN^)umOA{pzXoveZR-dn4Ca`ZSKCAf!TLh&!)NlE-O~EzTM;Wnor86NXB@v zibaAOXThRf$-9{(Y?Nf`JH@V>&J>Qho?>&Zs55c0<-t4DP$uRytTIjb;T_&Sv(VL3oBZU(TA6cA`D3nR*sbAc4_nS^uj{x8Q>YfK# z%Rl!2X5-VcT4NHvLr`2>X34E%Gv91HEGcSx=k(`bWwSSd(H4^zwO8-iS=PC`cE^6{ znb$Vi`7Qp@6s>oE+7~OMwW+h-{NgGuJG^yG|7DFc`Q|aFe_8Z8MQgNe&5=$Ic(d(Y iOj+yYd9~sR3|sOKA3UFUd>$|fF?hQAxvX= minLength && !item.enabled) { + $scope.safeApply(function () { + item.enabled = true; + }); + } else if (elements.length == 0 && item.enabled) { + $scope.safeApply(function () { + item.enabled = false; + }); + } + } + } + }); + + }); + + }]); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/editor-app/tour.js b/snow-flowable/src/main/resources/static/editor-app/tour.js new file mode 100644 index 0000000..0f29024 --- /dev/null +++ b/snow-flowable/src/main/resources/static/editor-app/tour.js @@ -0,0 +1,201 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var FLOWABLE_EDITOR_TOUR = { + + /* + * General 'getting started' tutorial for the Editor. + */ + gettingStarted: function($scope, $translate, $q, useLocalStorage) { + var userName; + if ($scope.account.firstName) { + userName = $scope.account.firstName; + } else { + userName = $scope.account.fullname; + } + + $q.all([ + $translate('TOUR.WELCOME-TITLE', {userName: userName}), $translate('TOUR.WELCOME-CONTENT'), + $translate('TOUR.PALETTE-TITLE'), $translate('TOUR.PALETTE-CONTENT'), + $translate('TOUR.CANVAS-TITLE'), $translate('TOUR.CANVAS-CONTENT'), + $translate('TOUR.DRAGDROP-TITLE'), $translate('TOUR.DRAGDROP-CONTENT'), + $translate('TOUR.PROPERTIES-TITLE'), $translate('TOUR.PROPERTIES-CONTENT'), + $translate('TOUR.TOOLBAR-TITLE'), $translate('TOUR.TOOLBAR-CONTENT'), + $translate('TOUR.END-TITLE'), $translate('TOUR.END-CONTENT') + ]).then(function(translations) { + + // We're using a hack here due to https://github.com/sorich87/bootstrap-tour/issues/85: + // when clicking next in the tour, it always sets the 'display' css property to 'none' + // The hack is simple: before the next step is shown, we reset the 'display' property to 'block' + + var tourStepDomElements = ['body', '#paletteHelpWrapper', '#canvasHelpWrapper', '#propertiesHelpWrapper', '#editor-header']; + + var tour = new Tour({ + name: 'activitiEditorTour', + storage: (useLocalStorage ? window.localStorage : false), + container: 'body', + backdrop: true, + keyboard: true, + steps: [ + { + orphan: true, + title: translations[0], + content: translations[1], + template: FLOWABLE_EDITOR_TOUR._buildStepTemplate(false, true, false, 300), + onNext: FLOWABLE_EDITOR_TOUR._buildOnNextFunction(tourStepDomElements[0]) + }, + { + element: tourStepDomElements[1], + title: translations[2], + content: translations[3], + template: FLOWABLE_EDITOR_TOUR._buildStepTemplate(false, true, false, 400, 'images/tour/open-group.gif'), + onNext: FLOWABLE_EDITOR_TOUR._buildOnNextFunction(tourStepDomElements[1]) + }, + { + element: tourStepDomElements[2], + title: translations[4], + content: translations[5], + placement: 'left', + template: FLOWABLE_EDITOR_TOUR._buildStepTemplate(false, true, false), + onNext: FLOWABLE_EDITOR_TOUR._buildOnNextFunction(tourStepDomElements[2]) + }, + { + orphan: true, + title: translations[6], + content: translations[7], + template: FLOWABLE_EDITOR_TOUR._buildStepTemplate(false, true, false, 720, 'images/tour/tour-dnd.gif'), + onNext: FLOWABLE_EDITOR_TOUR._buildOnNextFunction(tourStepDomElements[0]) + }, + { + element: tourStepDomElements[3], + title: translations[8], + content: translations[9], + placement: 'top', + template: FLOWABLE_EDITOR_TOUR._buildStepTemplate(false, true, false, 400), + onNext: FLOWABLE_EDITOR_TOUR._buildOnNextFunction(tourStepDomElements[3]) + }, + { + element: tourStepDomElements[4], + title: translations[10], + content: translations[11], + placement: 'bottom', + template: FLOWABLE_EDITOR_TOUR._buildStepTemplate(false, true, false, 400), + onNext: FLOWABLE_EDITOR_TOUR._buildOnNextFunction(tourStepDomElements[4]) + }, + { + orphan: true, + title: translations[12], + content: translations[13], + template: FLOWABLE_EDITOR_TOUR._buildStepTemplate(false, false, true, 400), + onNext: FLOWABLE_EDITOR_TOUR._buildOnNextFunction(tourStepDomElements[0]) + } + ], + + onEnd: FLOWABLE_EDITOR_TOUR._buildOnEndFunction(tourStepDomElements) + }); + + tour.init(); + tour.start(); + }) + }, + + /* + * Tutorial showing how to use the bendpoint functionality for sequenceflow + */ + sequenceFlowBendpoint: function($scope, $translate, $q, useLocalStorage) { + + $q.all([ + $translate('FEATURE-TOUR.BENDPOINT.TITLE'), $translate('FEATURE-TOUR.BENDPOINT.DESCRIPTION') + ]).then(function(translations) { + + // We're using a hack here due to https://github.com/sorich87/bootstrap-tour/issues/85: + // when clicking next in the tour, it always sets the 'display' css property to 'none' + // The hack is simple: before the next step is shown, we reset the 'display' property to 'block' + + var tourStepDomElements = ['body']; + + var tour = new Tour({ + name: 'bendpointTour', + storage: (useLocalStorage ? window.localStorage : false), + container: 'body', + backdrop: true, + keyboard: true, + steps: [ + { + orphan: true, + title: translations[0], + content: translations[1], + template: FLOWABLE_EDITOR_TOUR._buildStepTemplate(false, false, true, 500, 'images/tour/sequenceflow-bendpoint.gif'), + onNext: FLOWABLE_EDITOR_TOUR._buildOnNextFunction(tourStepDomElements[0]) + } + ], + + onEnd: FLOWABLE_EDITOR_TOUR._buildOnEndFunction(tourStepDomElements) + }); + + tour.init(); + tour.start(); + }) + }, + + + + _buildStepTemplate : function (addPrevButton, addNextButton, addEndTourButton, optionalForcedWidth, image) { + + var width = 200; + if (optionalForcedWidth) { + width = optionalForcedWidth; + } + + var template = + '
' + + '
' + + '

' + + '
' + + '
'; + if (image) { + template = template + '
'; + } + if (addPrevButton) { + template = template + ''; + } + if (addNextButton) { + template = template + ''; + } + if (addEndTourButton) { + template = template + ''; + } + + template = template + '
' + '' + '
'; + return template; + }, + + _buildOnNextFunction: function(selector) { + return function () { + jQuery(selector).each(function (i, obj) { + obj.style.display = 'block'; + }) + }; + }, + + _buildOnEndFunction: function(selectors) { + return function () { + for (var elementsToResetIndex = 0; elementsToResetIndex < selectors.length; elementsToResetIndex++) { + jQuery(selectors[elementsToResetIndex]).each(function (i, obj) { + obj.style.display = 'block'; + }); + } + } + } + +}; diff --git a/snow-flowable/src/main/resources/static/favicon.ico b/snow-flowable/src/main/resources/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..6f1babbf5f52e6750cb9035964a5ccaf0bf36e91 GIT binary patch literal 134386 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 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/fonts/TitilliumWeb-Regular.ttf b/snow-flowable/src/main/resources/static/fonts/TitilliumWeb-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6da821935dc29725c445ee8b469a2242c508c481 GIT binary patch literal 63752 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 D2bv~K literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/fonts/cherokee-webfont.eot b/snow-flowable/src/main/resources/static/fonts/cherokee-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..74c04811b424a38cd5c5abf43b7747d396158dd7 GIT binary patch literal 4160 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/fonts/cherokee-webfont.ttf b/snow-flowable/src/main/resources/static/fonts/cherokee-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..34f143ff7d6fed9f797a97a9b8f5985fbd04c155 GIT binary patch literal 6896 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 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/fonts/cherokee-webfont.woff b/snow-flowable/src/main/resources/static/fonts/cherokee-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..c210f615339b1bad4db8af25ce817f335e5565da GIT binary patch literal 4816 zcmY+IXEZSbVG>fqJ=@C_ud&Te4>XCCCH~FM3?BjL>ZmL zAbOAJb(FJx=lnVAx}IyT=U!#Md+oh`yvs`+g#sV|SZIa->g)RU&j0%B_Wv&^l#Utz zK!QQad@XzFq8=p$MHI*~K+gh-9nb{`)wTJBK-K_yB~W^1SQC_mgPAh`5DFDOwW2HQ+)5P}R1`swRUj#2AMzTWIU1a>{3;j0;8Laloc|K{ z|F;erZ5fPagrQ(msn8|CkW*fAINA`n-v)iP%j5iD4bf3_>C>_+vy(F?zxyVUQiScp z`4#0vcTr0)CxYOeuD3OicyVFE#6*8_815z$u}aj$iDLakQ0b@m+p7H%L0hW6WPk zgfA1@JaSElc7d?TU=-lEQpW6@f0ff=9Q4Zma#9>LNV~{fVF`&!w}CXIYHz|9uXVdY z?bSQ+Z8I>e=*4s8>Pq1F-_6aKw^gA;hW3^Ry&m{WGFbZXI|*B0`H9m5N=7vajA2#5 zE+Fu4YW~7Q>3prr@4~CL zePz`N!wsQG>eC)!8ErcU!Vi~Y9OL^gw5sua`Q@UisTG%ZZnlQ^xa(?H_n+WeUshDE zp+kAF7@}Y8dOqZ=6qNU9N50?b<%LrpnHO~sQztQ#K3<;gx%^k=RGFr$;i-zmVnj8p zE8%BLwy1jLm1Me_gA+^Ji2-w~S2Lrk_{on590Rqvg!zMD5(PPw?rFsB!A4%#k`{hY z=3VgeZd_0%an;{n3X<=uJtzeAhjjQ2G+Db4lX_Wu+M1GU{ET$>3&W}lw|#E5_5MC zN*%fFH;Z4nIQ_ki-={(mKcU_Jm7fq9AJVAEyxlV0sTEaUGveQTDs|PplCTAPL{{-E zaMg>7Bjk6xtRUC4+)VLgc)Q9!ahvkS?(=u_O%dh1daS`m^rUnu&tQswZBF}YLBU}1 zO;3}7w^>h&n{`;=?<~8umNvX*G2VUwO9X#bX*NPG!e(Y1u}N^IaCxx|%2hXCVP@*1 zMMp0NBA1;LhSRFL;ML;UhdSRQx?+uvzv7ME+z(VdT*`g(MoLghlX@iNEHv9KQgl^p zwbc2o!ir4p>Y-mEe1PNJepyBB(_+m(ZSp5n6PjXSbzTm5aaMh{v>yTG=Ov@!uP>Sp zV?5gQ?3@z$O;5<`*bUToj1OB&{Y~dXJd&(fC?^AV_);HDihndGIx-h*YQwr#BL1N5 z-y0H*=2CYB$uZ{GDm}YJU;Z5$-Qwrz%ie*{%G@ONqFzcbWbdE4ac_33vr{a|sibVt zi52tIvG@-=q}sjyt<+7s1p-`XJQ?cEa>pcdpT}ORWQo&_o{O`TfIbuMV;6`w-xCl9mlV(zPqhQfQ9Qg7Sbp2}8f?_V&{j(V`M%{&l*VY_4gJ5a+x5J6C8 zKh;v9$mJ`{DdfDHI}~-dKiYzTI!5+vMWXU<)}06xpzV+)uma_331#@l{A}Bfn!}NE6Ahxn@R=-Q z4m{4!`DvNlNe3rtEKd*dTaAbEGEluuE++7#p_ed>r9^1n_}P1s>EqvI ze#%Lm(LURTpQ@-9a~gN(d+i^%pG8%<@wzKW9G8gsT}L(5@MiGSEmZ2q6T^dSim@mi zT9k{zjE!%$Yyj*q&n8<|9ynJ1P$ybAkxfL7#2v9tI-B$;wQGJSI~UM%u7O(Zqvk~t ziN1!C8PFk%(htXVD_laDX3j@E-4Ja7O2n|@jb8!Q1 zBPJqsR0H&6i*P$t&Mk7!1~;BvB0NJDsaEj7@}4r?BsoCS4!@nE#-?H3-VfY^k^<42 z1WRGbaWDNWTwwP;`eNJh^&Y5b(k%d}tD`-%cpK91jU)>A6)W#qyyTJCF-*lNM9S2# z;n8=$3SMvAz(9W}wr1M)E2^2D zzu43ziNl^3kbcYhDsAw1lNwLa*K^fcIdNlicy#I&i*$`$b%VTd= z^>c&jr0EInrl&3PlpkpLqddeA@ElHw;6fU`-1@m8H-ld_4L-+0O}``LI=?_^^B*oE zCJ38Cq-QaJX`t^-_7;b@QzZsBeg)D-mIwdB>zZYc`|^pZ)*Z`&&3unSMJ1{)zXgTX z`nlB5*P|iMI}h)R^;VM^b=X+!mslKD#QW!341Pk4bZ)z-?9cq^QuEKQFsX!hj)52G>eUjNFL4ntg+==_%yLh zDOFXnh}-{MhCxhlE3`afm8?>6__LkG9kN&E$5W8@J~|JgmU?UC;0;rMI~`=tlJ`rY zyXjS5eYe34W(`cT|HG0>8hCy1>S5W!gaRgcjm$1UeE-64KUu}JZIJ{84KG+{GQdGsm~a|vMsVMIYIw8I)lqlv&@9`b3R(4@mBIO{B>0DSST`Au zNBySqx;wMZ7c0%WOMg9-s~(Pa8m&k*Jgs-ki97b-o6z2Am!M_Ywb&mMxW6%bwmz6V zyL@K#7HO6C^{y^5ow-IwYr zp0e2Sdvbp}tGNjv)p3ooLvwz7>O?tFiC{~0bbZBrDTzeXB9xwXN+hm{c z)ysc=-A&_eYHH0phFb(QY)}(#^V$V0F4oE_xuP$34Szh+N&AN|CN+b@a8MAtzLe?B z<2?U7ZIQWc!$#W0`l-S4R#-Zt7cj8&&k9%US60pC-g+x;_ZxiH#eMZbFXI4bqR!#VW} z$$t`k(Hdt!2TlVW?CTi@{Nj}*0DONh)ya^|q{?afSms!u-O+Iw;^B=c@^Da7hK zZ~t~3i1^la-b;%+zp3E|acibS{Omz_rFk|^w-R-p zZD!}e#qEba!!pCa+vA+Kx9L^K+m$R=U=}8!q%pH>$BHzg-7Cv_+M=_7(>HV(FA6+2 zj5D( zi;gN^ctrY|WQHo!yZWHjIGKH;qpm(G21%^Y=CY&Ir&{%prnyS#OO%#0{#kOFsaBDs zH=rKI7Hrw_S@9$_P6nyhD<+gTf#~Yi5|qk){I&G1NA`H(ml2{S4dO1&0Q(jVVqWOH zH1w9pk6PpVq?2gs#)v>t?j6{MlDnAN)kD>wk?fnWdifTEu-n39Ly{??S813L{7vP& znkPJce{7Tmuh#GPO(a{1+1U-wxRRF6O`5d2ZS4dve`_3arE64l;*M3N*!@mXFuLnK zz>%TG3a#rc^tC6DVfgvO*IJA-b_oXOw(zq}KT1{Thz zt+%`b(@V+sn913lF$vqeLfFf&P`I*-fB?oDSj-`c_}?6M4vi0jDhL4({7o>$)L|zC zRE-Jty>W}^V1R<%(hN3YPyE3KPK6W_5QvZ!)POJYvTG9N$h!9PxA-*acJ53hzpO38gJI#Nlrf2Zj-e{05Xi=9n6WVn3{Ka&2T|KUI=;d4e`xN&dt z`Tgn!VLr8e53~G>{?0d76(`o5+K=Cp)$)jNdsy9T)af1*^mxW%q;lBcYx1Nt>%|~< z5Vw#%6x{b3$W?e5BnD6|Bi7I_hd^Qt%26_pdkt+yM3f?|%^(0BwNn zKil^oY6VY{-1dR0Ma@N z|IbPR0e+! zN}8*7O64;}N}#)+k#j6FO>isk@k@Bh*}4HIZ8cU{OIG{HQ=j2X*xT%?IOBQpvTZW7IXToOwNzo|ejHaAwCN3nOc7m7e{ub?Y8i z9p3wwJ(%iCu~2*Rb;zUJG0b8esX)Om9*+v4m=T(1qO&}%tozG*k;kT*-plt){q_5c z=|<3=s%J;+5^v+e03X6T{0`e9cT7ovP0397X+n!3SBptlDu2Z(nI^J_Nr|Uj5|0C( zsH7C}(vTj#)-rQv+n%XGE}df=E4Dq-Cn{|U=>@EJ_c| zjH;t!H%Vd##NLSe`rbIC2J`CayTWN>e+qGMY?nW2xD$T@W0o1?#bj;oT(4;Ir)pP{ z^zn;2#~F`ftb9z2k;^GdMPH0idXNQqUSan~vmdnPn3s3%SN@Uig6OL<*X8N9PDVh8 zE=aXkd(#~a3H9B82wp6U3u8FGYoX^x7PGE#+vn}?O~tkn>Tv{iedtIfP8&bwnH1VV zHel!dgTT%?xmK)jRE{TF1YFcv8fD@y@1r@D1{la@9zHJ7`jjIgzd=oiWYa9mwK%B} zy|CkRB)J0JQ?mos6ANjD$3j}@!PdiZfx7c_qb7yN=?6t6lXA%0bSJe!ZLD>cF8{8S z%zc;TkETPxDAFe72-on^9wD-?{q;2aQ7EWrbl0Amd#3unxvqn|JC@Kd#!m zD3%q9>q$Qjsg=pC8dMY`_9rchB1o3(Wil)(sF~w)ACOx!9kcmc~KuZIkS}MR3@?*tjUUD*Kz; zVJRtiRB@p=gjxTAV`+L&^tE^C(CQRP!Bw(!Isen8`CL+pooh^+*%S@MaWSk4#@}gec|L# zB!X*xUXp`ho|VA`Ll)k5apBn|b=s1UHqG7d^9|e>hRSD4>#^tOx^prUc@J{d%&V)s zyY~ElJu0~3h&e4W4aJuFSTzpP%#yYGoDnZQlcGs!Sg3eGz`+OyUM_5xhx_aB}(am3~y@Fbd#1jSgAHpY4(fcua7%fTYkjZoq^$w>yI73S7BkQ1zBQ*iajFGoOY7aT zzym?U;sqi*@>@XjVK$R!N4;+s1}+_7hh#pIAi&zsu7a+Tcs_f1cA{riJ7EXtqe}OCX@Dh z_f|1w0};t&!oFbeqQ>Lt^HffBG51nvh{2eY!IdDfs2x$JmnI{NjEp}dg#0~^m;ss6 zXJ7;ie1$Tx&O2|BAx7HM*LELUTp^FccN>14vS?0SO~mDdR(Kz1v&ADl*5()&tDJ_b z+@dOWohxD|K?25Rk-p3BrYx?pHa=UHhLH+$a2v z0*lz_@ZQ?(jQym9Dh+*AdID&qXcvK!Hx+r&iMJW$!#=gjdu8F_MJD>^TM6jRMM>Vg z!S-620)nlVDK%S@o zVLA)2Bvp_i-Xtaw5s~w0SW+OyDF(zG^7#$KEMtJFy#5T55YJXt($Cz3p0hF(rC_Z- zHv@_nQCdp*B>WeEzvjk(hKOHl%Q?dl*%cafGod7Xvd*{bJX*;Htb>D0Pb^4L3-A{% zdR7bvem7@tj~qGhy!ae@4i|!mQ}SKuT!DaHKU6r^w@rn*iP4Qu1y(*QIP+V7lp zV1(b5MRgtRhHiv-Dx8Ugd!fVL!O%WuZS!1vM5(;b)(|e-=OX{Sh@G#mg9?zY>t9S3 z(gc7>upu=0BZdi5xMs} z!4nO=`(zd!`DFqv#03v{KtD<27UqYs3nh9o?!_dr&ryAGG&*Mex~-)7B`U4MFO0b* z#dL#X5Cs=Ve>Pz*#jYt?edt=m$NcWvP6u!Ds+`Caml?OwqR<}7R|c5s^5Xdcoz62Q zly*lMa2P(pt{L;1;Lwnbip6O*aE_!(R6%_fvb|cO+dhpZ+S#9;qxk?7K$7x6K+PB; zkUu8&@PQX8Id0~eP8GwNrDfWe+>XVCZ_%`TPoG%{uGsT*2@zW^@~XhbZj4OqFIC?A z-Q7P4limjRUNt|AkeZg{;<&Y<`$m*tc7W(N$2ydyHsC(=F}Z5qZel`_Y+wRqt>tID7ycuVB%5tJs&tWbL6 z*O&Xi?9gg5DWX9bLog%x3r9VJF_D9xdyRp`lWoa0&d#9ZJSUL8&d#|evcRL#rqZVO zJNC7MJen=e9iT?{{;z2g+?Px`EoOq!hRSxz;OXY0*APlAW@ma^B~3hN5%Dq8pTKCOm35VonBfC0 z7VRQox~ieh3BgEeC}Hoed+Bdi05zmVQ}_hwg&3i1@?^6ga0|CjtXY|I1ES$jrjV_9 z+akX_DI1EpwSls+{=AG3R;R9)`kwp2mD<*+F9l8cN9Y)C(b571U8D?SjNd$un*W$^ zQb3!O63^f(-w;Pb2aw7=70LYQre{1Y*nT9U>C1`lhorT&pev|h>j*t~AZh2TQkd6! z#nAOK$b56zMt=0)Jn9x+zaw7D75Tq6g{;UcRPQRvYviJAJ80kI;iPgq$ZpUk zv``I3NMn%$3RND;4o3({ne?g0v93`9qqBXV=f32tj+&*#eRvX$Z@Uth8DvQeA)7k6 zC=w`L9G8=)dfi3V^Sex-qDlv5@QSVUhOrL?(T+V>?S?|u^xRB z9AG`U7u_rYVxUM4WswQ^1X1pkETpecH5WfA2zpx%1%><#Eo?_bZ?-X0Qt%m|XPl;_ zu8I53WU?v;ubySw*KR9?Cefkz5=?E0K4| zTIX~w?XR31GOY4x$A}x~rZHFPu-8FYyAkGG@McWucr`cY;YArWU`C4xS%D)$`Y6ro z7i8HK3a*?2$uhrt4{XePufp{9W6WckA9@bh{Y3T?uM&VqbX`Zfj~6&}B@IC4`>4&N zqglD%fv{0`v`z@^T?zw}KP7tp zF7`Lc2c#!8x{#QI{rL$0(DQbaG*YH_VNq?ZQOAZZjj<$*-7xcdGwRAhh; zg>R4Cp<%f4%j;^ij_HAlt<2B4s3%j>N=NR8>aBystt*@e)DHTKcITN8ktnsR5}*@+ z@%3Bn;UiMu>6<3X$qn!?>#yYMIjVGtrU+)}ll`$fZRnpf9?5;1!W(|kNp66|d|ffe z?YG%#3In=mR&~v%>d%O~pK_F+z*+89qHt*GAaB>dut}dEj8Gmjv?hbcZArt!ex3x5 z^7!L@9-AUTQ>Be)0YV`|qwa==f3?+@!RyvsJt?3Ev0;LYSnc(QfDy zl`S2^SAJ_k8y5u!T0v ztGm&;m^5KC(joeT)DpKxBQIhf@J7h{OWN_noT|69zUbm6{*tC%p`JiU-dKr)YsATI zt~kSw`fhSe=!_Oc)TmUD;@J`4K`SLf3&o8I&d*gfnVw9&oqTVj7fmXe9`O9{LyWR1 zLL}Yyz>YdANeaRw-f_h+2W6?H8cBJysbm{=Tp;86oJ5uKVDHdnpKk(ZPrLyaGDw|f zj5gh3YE|3GCB1q9C7`L5S{;VLCDQI3&tsVS`2$2%#~KPCw48A1^d43{ii<)q{0hoD zRGXP-^qjFZiIqPEez5nzpT}(pkw%GvtamjSnQTfb zXb+xMT_RlXhT$vBv4_WTDCByW+MI%H@T5#8RIM7TX&}DaAp5l(jSnvJ-Db@DCgK*3 zKE$ippUB=Oi{XV)L7cZ37UpqLEs|1h6~U-jL{UZ3ZH$@?AFS*|h89Xr>EOon9ufvS zURA%4n1Vh+e_*wKQ=sLc#tKl5M)pJZw+?VcOGaqf^-JNz8sXWEmkvTY|H0AWc6IHF zv|Qd?RK3me>{nH6ve-QMqnjwW)B(;Lwz+AB&35THNM+Q!;dshRsyASi6pLd!AzOek zDSvVGq{wReUJ}JYK6rcJ^}OD69xJunQ_y~$jx zEerlVAfD9J=U|fVI^G&Hn?&shBnczCp92sx-n4LXL|r2mV4scT;9gu@*Ylcu*BnSC z;@J^7^5PfZ5yh1kTTE}ODx6Kzq2H(5M!;;XPIFlSJr2+hI$Bl z+!0xVR=6Z{OH7W3Z1?YcSriUR>ex@Z!#z=QVg>Y6vyyCa#Y`jt<+zdcbQ=D2&Ao;u zVds^;OJ+JKCc-0@NdR-go(ZsnV1DgO0{MwIah{EJmAZKttG0YO*W{7peKGx@ z8!RPp4TXkW#9g*d0&@&_UvUWRNe!9E(2jU&M7hl<*x^}DjEi5DEzuDMLMAa(t+T+9 ziE>FIvU*Auv|EZa7TjLoG`1p1=2tm6A|%3*#xEKe)^LrXXvlgTSbNnybU#eL&z8bV z>)W>fNRO88bpPlnN!k;c4;eF2)(ZVgq zI+NLU?PS@WVb94?&DQuLNeE`k6U6hoI#UEm;?7}3b>YnQR($BNMju{qh5D6;ge6IZ zBVH!tT@}BpCBowG@=nuyq4^zv3uD zaz9KxlaxGy^VuZh+N5lW1qb_w#1MIexr-L{sL_wQV)gSk&+mHd{pg0+x&}O|Nn_Xl zo^%uH4A%D(0y|MfQ-3utC%?TedJ5(uK;wRRSD1fQm(ga&=AuGH_cpk0rfnluYslzl zz5FOBDv35DzC=zE)LbA(tnO2l=wh(6_~9hZ2R4cdkuTk!jKSkd1;G8Jx)5;s$_qFd z*_G>Gp-wcLibH$rJUzfT!-2c%9P)t2VTWPtCr_t;?)ZiNICh#@g^k10el6)>91Xqa z44gu;fe+QCuBY_GKdHZRbwH!1JJ)wZfBqvB}U(%}4DReR)5pu;yMwumQYH6=88;#?HtFk4s zhI2L0AaB}Afm|Eq7I+7|5@s@kIuWduf0gcjr|l$3KhfIKVb<2U?_KhzB0wLQ$$zsn z_!km;#@NoPQyX^iO+e~CB?M0W$nG4KNwlEGcqa7Qk>Jp_V zR}Vzd!h87li`ony87U;pUiNkqVedNiRAK+Y;m2J_f4L}5izq|rk|@0SXNx|su)lKz zSr9;-Xb&9BVufgNQFGAV^?qymw$MP+V!oob0Pg)OT2vL*_!l}ZAh?zkJn9M4tQ6?>L?25H;KLXE z+ACml;kdyafmW-F5pa?s1Q9O^;t7R)Ur*iw9xEORh!$}h26~ug}p9e?vqjbb>8VVp4;iPIR80_?n%edz`dweV5*y%#U+-Y z>A!GP?b8@lDbbbk9Eh8Y31Z?-o6#wsJ!~B7g#v*k2fqHzbs(fE*%JB%#d)`GNakgD zK?-F?Q)6!-A?1xFIgPJxItTZFdTlM3!lzK))wk+YHGRz(NA|*NGi!~WRFvu%>JqP0 zL__rFuWBRix0HnGY51aXGAHs>(T4cen*mJyPmvLGq13Qy z<5f*X9N)YYL@7#gVZ3hb9<``3zwUwSahk%h0;?_*dF)}y9$xJpR1e2khb9M9cGNu* zuDx2q@)!(#*sP+V3{39s{g=Ve{#?8k%Ajg3qGw7*+s}MSwZXs^4eMDnM1Gq#Ah4wA zP~$M3fdNOS9OkDwt^8djKrJZ|{x^1d1U}-vrA)CR6^0hQ-^3;qDwi|gkNmq`jLK6I z)r%2htZg#gn*0mcWb=s2m1|}^iY07>eWUBR;7RHD=Aml-nIpK_xE9nlXZfcvP-!+) zH9DHiFTpUICV@nsqssBrR^#a+1n%1ZQZjA`qIfXbyX2FYi$D%o#!R1* zOxTBAW-^tak+g2GwZR{b7lmW+DJY`iLY zMgsRvidd<_Y|uI2t(q+web&~r;ez4>o~+msHXXIzdkq+VLXeLidVBMYo5;$GUF5tmbJ{~}@;eACae`pZP-`~1RQW$Ppp`-@sq6o`-hOO;0BFs;f zTn+NTB1+d17aPP&&5WkxRXn~USE?Ye7<}zaN}ug;zC_fmJ(DDq^{cr(;o^RH5sOwJ z=51d=R$lsmZHU~F)YI4cHfJ*y+ zdUnyrK5^G*l*2moA1Ve9cpV;udmds%_w{-Iuy??HoI|HUt4|l*nD+}SS!&9AxT8Tw zl4=hmJ2Ce8<62i-*qn0lim6+)+~j?n?MiEw9~@ovFxTw-DQD3dUoFc+iZE@w5CXeN zBJ2C?1y7{DBMsHZ!JFom6Un`#QGBb!ELH~Ka%TA_Hx{VN^Rf*bb1DV9+vv{OnZz+V zV6ppnYAJ|X^bFV}?tWyPb((zyNf+&$6Rwqg1W-XjwpZE*G^TA&B94m_n-eOeF_@TK zOLPqKO`}JB`=fR66b-OAtUo|5Am4U(;9=zsOe?JTs68#9u8ZG`_MM8gt6vA?d zJ)8FAEifNZN-E-|Ly)YZE)KC$Y5EIxLsoHq=@W_;Hnljx5_1T-l<|^mi->+92=EsC z>Gi-?(NRWV6KDf?Ax;{%O)|MAQa+52O8E%U*%F2jU9Hk(m+mAF-qJ6m0zekjiwm={ zR^tr;bZ9R|dDQ+tN8~&olv;EYdXI>elphqNoyKg(JO})3;UyRu@vi^SZwvh))^G zf2+fI7c&$PT$)6a*65(Yhx<@ScYC!!=OP_Ol0HDczg48Fv5u0A(};FNq$;0W0BJcRIl84i`V zP0z@;ZV8cAoc3JRP$#k%+x}fM%D4HYNVdF&15UDx?QvcOX8Lur@uEh&5Yiocmv z-NZ-MZ6Nfg+^#6B}o=UI^$eevG{DTsh#u zq_Y@`fROO$|4N) zBNay8QAIZ%jNlhQedrZmG4s!HYM(wqAvM;zV@3z*@JYT70#)`hlqD8sj4#z?=4exZ z`X6KQ%`dqvYq1JYUue=DvWq56Uvh;|^5C(l0zYs}Su@=>=Q;jY)pw4jYUXIJv9N~DtF1O&K24+jCm6-n|6OazGa#KTwKR;X>`V4oM#^F zPb5FJsNZ?*#Z0_+f~Yw6&HB{&E!evc=wRT!1A@iG0XrP4dWPE&12dbOk;2EL+Qddfp;@E9j3>u_vR{W1VUT!+k0N zud1?Y*(sg4$YrwL`;0X=`h`S5?A%+bkn;JN@wX1gB^f6<0hmT?i1QOWA%)SOwQDWs z3c1)4juq3@2D)!1$NAi=*rrVBc(RT*4fhECLHwfmKhMNaZ+7)10(#WsJp=&;KxXk~ z84-d{dIYbqPJJp2z3K^fypJ1nxtaw2+#`+f@w7`8dM^0VPKQ6Mut?EOdiwm&5~nDJ zaML}}&Req>Nzmn8(3E1Gf5c=`J%_Ym;e4TYB65h;5l3lLk-+Rvr~1|k&HJf{h(2%d zf#c=gm*63P&QEYVyhpYpls*XBAjx1Rl_faaZc#vJgnQ~ObkWZS*CY&d_1zV%anoUn zLpCtsC}tKx-p&^LBilUX#mf()Bj+rY=K3T_vzs=3XnRf#V9%gFmqUywxG!zm4}IO_ zXI3LHT+}`?8D23`haQYvVFG8W;!@kh97I}41q4M|1Zg}+t)+nU2rDrWy=KA>p|_Kj z^uhJvL7{k(Fu{1?!kU{mE)3q_jgG*a}A;J;E139H^FZkTc!@O4&7ri69#;fB?fVASr+;0aqPI1wkQXqLZcHTZSZ3k zT7~n;^!0YF!fK(?J}BrbxqnOIZ~jAt{-c5;6=AavGDvTnR+^#IG=HvmWdn+gsLX_% z8q0o#7^;7prL)u-zopW3g4$58c`3T+WcUdS8sAbzUqdG zWnC3Yg4wYvD*A9FDRt;SsI7Y|Df*~9LuM9Vx?va`!G`rRh)=OlzOoHL30=rX_%$h& zd-4X`UNHH~fKbAxXR(}!@rBj>tT2zhjBpW#yU{cIoTH_9Dg z5YIjAUWkxC)MUZOsmu~?f3-Nh+(lL~%XzEu?ax&%zWWqCEbj0B%A}x^n@6JYBMc9$ z!s@TLcOkT*bpd}MpA-qz@uySP5EWE+638yMt1O5yTVBX+n~7O7*TF^i+>Sx;Bzl#m zP$1U{&%8K@AYd4fQk`G>Qco(XZ>O&C1Se+eXz@;p4Od>_ev{jElzQ|=q5R?^bWn^J zbA;Cut&@n5xmI3}T!xr)BwbTtoZ}4(oPlIfon_dflfQ`cELaIAi|v+OAXU2qp5!el zmHgvJ*+z^bIMwop3I3?j-ioRVM9(*v{YAzT?cY!E+#FvE+TwN}Ij#nJ?xoH$eCoLF zQ)?HbBCsw&&ur}i&CJXXq|Y&7j=01Vi*-!zJF5EeSpW^{M^PTWeExEmcH<^jzuLHC z!bX8vYga0HYZe{HTN6R^ZA=j5Mh6U69o*>&|L-yL`)>Vg)s40j!f*rw27fwWJ(jfs zOhSZPK@x_Ij~_On+Rii@baZrKX)8xN1(;gqk+-&C+;T<+2N_f91t_tm@j$FXMue0t z2^_Q!DDZ>slQ%t($tG9`2^yvJng&%C8a2MMB<{_*OFnlQXJ4f8e$B2WkPAMUo4Teq zG$5j7GSaTxZO+3+@{0z-lBB}k&3=sZ-@wQQm`f%PQJG0g^Q^^{!s>Vo@_5C{FCLnH zuQfSGZ5_HK5;o`U0bX9yKS+(xR3%tjIfCNN-y|pDxWtH`NI-3kOT8SAXcs#TxX|Tb z-4gImTme3ZCVGsD{R!+ebgH;n%EkgGr&&d`NFg!c~sI~uyO4$zHb&OSNls_}o- z+C=Ll*8_*5mkNW=hi*>?VLq0R)#6`e z+4)w1YS*6EzhoeupC64W=qCM$na5+QY48**iVLk9;1fMrF&4qzF7qFY1C2?;a{(V$ z6W8yhFQcHP(L-K~}+u64~ z#eq_Er%r`NCT&?mIO4HznTrcoO}b$7@<3^0td0Tdt5JzOct3}hO$*^ssednwqH7-L zFiX4h4#56nh&ELlRXbm5px!DC+P;$hYMLbi?t58{75r%TAgrd-1tcOqINykZxLhA` zTV`Pag@$3F&A1A+2H_9(fdM+j-ZdVo=YZ#E%2c5{ZUbn>?X~&$xaf7tSCn*OrrKYF z&*IS+F+`T_W&w>yQ`FoQJtN(uTPkLH?m=b6&~zP@pJmL8KEr;h!P}JkH2BlPRwVcY zYz>GGen9nTRMfcu30WA^HbVj4^u(V%<$9=K5N$c1Q|D*+HTgBrh?Ql)IFsi_LrE<% zYC|!R!s?PIB0L7%P5Ah-?veGq%ciOF*3Fv(g;9~wl8}j%hI=ng!-B1?#=Zx zR3S$auy_38iR6Ad*rL9j)HZ=j(~cj-!hJvbI7sM?E@+T^JtOr@XE_!oXlUhT=JHLbW()ItXs^-KWvZ0-yLq z$)>gyz@17ERGLu%*`ct#t9lo}u1 z^tGoP4IK;Ha4qlRaT5F|D(Z0ir$m^n7Q_X*^Rj&O)j6B00%)q42>GLoBb0dLQbKsh-(ohcln$0wrN;M~snY%70A3W?5}3;2iuC+~$}ft7J24Wr3L{v4u#N_mI<45iMh7fG!nCehN>#LJiYm2bv8m8gzt zIrQg&UX6;HT&qi7?313!{WOwu<&Z!1`++{St)j4V&t6~rlX27%jU~%)l3ZR4W*QEu zLjM!U2xX}Xbc7uEh|T$#iseSnWe0(q{MQKyYwUHr^H{&EXkaK*FdcdCeS2c0_d^9P z&w8iCV66w!kK<$p+7E-;-np_X=3LIQ%&MBA9k|>q?&*PNCeL|S#!$h}oBBP;v}{d| z1mNHd7Ej6eu`uKm-dtoEZ97BOBuq^@#%R#0iWVd65j!JZE*yad2c~gFundN2tZd>) z(YGp68{k9GJU>y29+hB5DWk+u%~#1Rw2+;?hCAUE0r+)vtcYPGg8f4!+x!(OUznyK zHN^;Gt>>c@jDzYGdlR@AOX_yfv}cfWcnyI2&vLY=$u_Z5xoM^AcUXSaleSkuUn4mq zoT9j!qD_tgRfed%mr2Ji=uS@0hUg+I(cq5v$KEGPWF-TYSu7){rj`%j1=UAUYa16b7V35rD*-1~rVuv1Ao6a#_eUoun0p~2u;b{ck z2$}`gmx>rBvo$hQDELn~&vO8Hs|8kDg<`e3qUoXQj};QW+n%G>t&>~h+}bGNwT_E2 z;2~^>h>--fX}?zojasSO5~j|}Ekx0bIdBWjGAVTNO#17i>y@wd$e;1L;dA><*-Kob;Al77?>E4Veden6k=+q+*qTEER7f-xQ? z#y*Was|;+B_@C{#Q;KQdziWRrdA<+LM+tiVa!Y{}Sh1IrCR%^fInaP4>gUG->#AuX zjqdat3{P1nulNJDpqu>~m=@e_cU##*)}7?;MU4a$^q@T)RCnQ{4}CUcZ?h`V&AZV~ z76=EnVLgdu2av5T<|TW2(!FQS!lIyiRBS83+MptXU|(NH=Mk?@9^;2YrLOC{n9VBs?+;9F8K*K_J=T2xyM=vrD;gd(U6#iT~!Ghr~x;_1@j z>0;o$yM;6eQkh{%cSuIK!J#Yw@C)GdMG*`LmrdT5ogVexE$a&CsR=JLJL|^fX_foR z8Z6^m>&irEj^ayYEW?|=+nDUqTOO&d%j0u$tY#^%OwO5`AuQbB_;lR!BmZ9Ac{94f zy|gDpA@Dq2`Dc9ff^emOb$(H`9;^z3q(smuYPB$2SH-0{x28^4jxQHP?G! zgs{N_a=~!@5Cj191%y7^KXp4YTh8*5MJ~PBuo%vkHKPpX(T6j<`|=YKZS7}1BHYc4 zRYYR)$9wyFbBWFJ8=(~CKu=q}24^kRzav_3KsXBkVFDY^We!1%WyFt}6%WDb(4y@* zY{RF};+QBJJ*-_x0|pDMMwj>vO{V9v-D>y2q?gC8ZnsbtK!?k<|NLB}rpONie;-!~ zULiEe8f}p)og9zj_{r~t{->wXdCs_=gUJo5HD>VMBAK+JhtMg3L@u+%FND~1$xr}6 z!rBFcoGDf0t_(~VAWkav_o|NXF7WY_l(WL)pv^oZLDED_ZS!yF*VjN4`M~Z zi0|zInq6R8NmWofV3vBT-~(GKAidw(0Ur;t1>XA6pt>V-Ih{Tofk-#}RH zzj?|R#0zU52i3Vv3pauBtn0#;jA>ULW--^uh#Id|>jaW!i+>JsdvnwCdyz4vLm!Ar ze(-+13RLFNdfM|NM$Y`n$x&+tJez0P5^A@sDnG#_S1^%9hAME1Mqy5Pb03FXZ(m>C z2wwF20;VChlC}i11d8=a&tiY1UX;d(>@Ijkb88lhfg|_|YRc?HVr>3o7d!jaS|b+4 ziJ6Fe!`)Zo;f3{9iyvHa?Dr*pICO>@Ge;3digR~%;$1a5o?>&$t{2X4TdR0DqE3el z!6#zE4La^l%ZqV{vz%n^5zh)xikq%s0rO8z#jxuTvugd{(E8Yx%&?FH)L7mo5{*Bt zWkM2igxB)zKJnBQ(JTExJ4-n+SosT0>%R0RKu8mGP!auLRDWLz3+i_xb4gwr2~dlZ z$?UEknv>aVeLfBqCg03nTvh&XXI1#xg+ia8g3zlTcRlR_E11}+|26nZLJ2?EMStB* ziF%A3V{Y@l<}7SoV?uFW!j~b-Q+rsQtl4>+VA7A&92*XmNH#9r`A)w>tB9|}Pi&PF*=_hPPT>2tK@N!o( znmxOMSyzh~A{K(Xg)fwXRX4-lt8J&eE8nzUy{Is)lOj{4t9yVgUCS`TJmwGmixsD&rwMrbRd2a9mX3l~@M@)hIfoEczZ)Q%%3!w1PQlkw;I$;DH-p}gerBL(C zktL$vDY;cvV-c89B%VZ_z9~AaNsro()_Q%~jCRO?5S5;?gzPO7krU3~7^G$)gkH~4&@ExJtAv7+ue_}lFOok(|IWILUV z(vXN_EhF|k3zIq38-FG2%xtvp>HIU&45t;2#P~ImWyfAoJi;T9ams1ymFZHNR}Qt& z<#a>(u9sw@OG0u{pEPZWuEtx+%6_i0a;uO1Ut5dBK?zn-w2oSmxn{-$oh~t2@u0=EKGREP- zrntA3>-vUf!}d(apDmZu43VFq(NSR^nDv?I#Qy5p7=m&qOeZ!?JUQ~vI+7^w@gAv6;->Xmp5Vs^2liIpRew@9XrBud~q6m_khn3Thf>)In@o z0Gum&2Z+7;ItnfB9cm-0yf;#y7AY;65DJMy$DMV_q7IP-5S=~y1`wpA-@(KulqNn$ zHkzvwoJtLqS=NpXNx(8)WTPseC%wj&Bahq;5luD~JB3 z(ABw8XA|{_{`*Gq_-+usEflc<#w++N$~iwF;qQq1Z!aPJ*WqnajsrIbM>4?WEQg1J zq^ak$@my&Ov`Cpv+SkV3e!O86Pd5M*&t^s^Q9}XU`|`_=`_+d_8h2t^>O0nWqw{NV zSdNV;Oq6u*=Q@@LFW`Zx{`AYrJh5H z2vu)#dvkuLE9dmG(1epc#jKaw5XR}lyArTvU>flsV7C|4JS7=GF2#1$!1^*Xbj z)u^I1KfL$Xln&dlzQ$a$ZA{JFb<#NwnnWsPqgJp2VLP6FY=9FNz{>`Sn7zFYjFoCN zXO^g(>4R+U$Mi<6$V3n;6T9EBCTn;5$}T&1GMczSw4eNW8X%4fVQ5m_j(QIY#wI>h z`VINL{~O^(kw=sF8^1J}igZ;3)-tlLm5(xT>W&r3VmwP+2)p4c@jIca+sa*D%wqjJ zbx^T>e7p-+hO*4e!C?x|LTSk#1AqgI?*9sH4wCUwX6qeE5NxOr1a=ZyyCs?i%#Q3G z$tj90j)M#jf{_I6FTjQ z9N->Tmlqw*c=ETW!MW(9Q%G3SW&M>U5hg4O2IOoGxdR9Xhmf3fnGjRO4=GqwP0fHQ z>KMVfZ1|NW`?Zl0m^@^Q9||T#8achkk-KWyJ^ZXVq%b89(>kM<7=JG_vqu;uk(51h z0X-S>0T5h;#7<8T>0QE8iDks-0LICd4T>ROlzG+9Xo8!bJqw;WTFkGtV&{sB+A4}m z6k0Tk$SL0imR6JxXwS8PloSZ!PCrrF*on1-GeMg)(ePP^1Ny9vG*(E1f@a6;h#R^J z0xU(l!surA&vgX>Y|WwCl-;GStYn_E1BVe}#HCERH;7|kB@p{21VK>Ak~RVahv4sB zf-K^x)g><`2?LOuh*)b($@|&SPuTLjSx~hhjwaH0!6XDgfipwYf@st1tStg?5@ptC z>tW}Hbqo!;He#C7Eg<&6Xm+%ON1Z+k(;BkAXk7tX^H30x0l|dX8TO%98*!y$MX=Z! zc-{DNX!CU&%ut-eG!%0F!=umzBhy+*5SS@kZFveI->)wxdG*Px5twNOOc6*iMBvOR zym(hv?#^E5QKkaTt&6gP*fQDAe z+X_I+l*a%Xt1QDHNw8{%J>7Q&Ph!0^tC|=#;BpKh^ra$iju5EP_%eQ#?0vFiiXS5> zKOvKgFWw0?h*t*-8PH23x_-(9IN(h_k!988=#y+q)(~7n->aUESF{WU6inI1opw3` zQl$+%uArh<%pIK?5u$KYhAkGtlE5;8GEnFpsL+u@Hl!7ZRa<4*rnxs4c$8AtcQmQE zha86a=xDMxZRO9M_!8IU)xGi*3G+GL3^qt|6)PLF%7F(&(=$|^!vAFfJchBb zBwwK*cUYjOh1oKuIDgz!SxpuDgUMULhk=Bl|4fOP(YFO)=U~pNLFU_v+w64W@-)-Y z;duK3Y#$v>8Dzw zr&!-d>hkPHu{x!yz$n9%6`MC!PzmYcZVXRIDPm*@TGnI%nWBLt^7P5D9cC!tJT7~@ z$~rc-F!FF~Qa-8K23Lc*8F5`d10N(g=z~6-SIX^rNZnrCVmJEmVp%wAw5u+(nn(yD z-^0For(b}~vA75L4?M)H<4Z6xU|-OZZRr%tw9gTunKqO8E_Sp4NuV+z1uYpgGg6^n z3`a8&pR4d0%A4xeVbbNIvt@6MmKv$vE+GYyrVQ2zO2RRe7FvZM)J;@N?6T20;3H8_ z4A9g!MpGrYfl z@lhs7b9a3iq=%3zP(`dDz)S)PEc+!`QA(H!zt^z&paFi<+e%!H@5zKng$u;&eISC2 zl`3lA(A9RvQY2pK9u)iVLcmtWxj>t*nm(v?uZ3O5eCFlA&8%n%#x57IF%E#QADF>*MpK6+Q z^FZ8kNn=H%aB7rD=(k2?LSpWW?u&9QID;f`Z3W|Ek402k;&o|Sf_ac1vjc+baHXyM zSU4!g@z4brfkx9Mw~1EHjV72dz>8ObV9}bkj!3b60?0|r0DE76Pa7Y(i|h1UeHf4b zU@1_TAn3v&B8Jbjvvj#_5+~UUnF&gHH+V+X%8^CXh-0pylmW9Lc#Dg*z6KC^v+!Pq zxk8!I5`i=@HAKp1MlXi^kf~iyHtl+G@l50v=4^)Yg68agN9Gdc3K{%h^Zy7G2-%;& zD6DVFSIp+dfK1hDC&Qw>JaNhX-_f}CV4u)x3?miOO#!6%%+u^8oJ1h3plIbnJvP0J zFhci|_6&QBV@)5FQC2n!lxne*#D%HH;lHSJCfS?tqC@N`5hxLXUc}DRzbNr2Vj6JzAS10 zfeTw=a2JGHK^G~_0x*p_D0GCat_|pk^IFl4td(ZPGZ;QyPKYPqK4A~hMW{=|aY70Z z{mO{iqt;*hnCzqeG5;y75&iRlp3C7sNQaDq*dwug?3oaL=|$}|S|lYetR4rKZY!fc z1jJV`e<>h*#!BK07QPfHjVmOPTH82@J!T)bVn?~%Ty}dR^MPQH8nKfRd)kE?@Z_OF z;(haE4CS@E8`TJs5o4JIYLGVO3aSZ%43L7!n7jcH04T744gi^;QDBLY$T~{gmU^B7 z&*ssFqV~AE7*R7b;-Q&^lkG3qEOc#6kU$}!-`5EuU{ij|h*u?o=#`~!Tw$rwzQE{f z1bYy~)1SgZ6elUxvLDF*7`r%n#29Bum@?5hFh{ppPN`DTg|l^quDkzf5K9PduwsA; z&ghy*mFmF(Ad{Hn8jro8BioW+VTg-lhYYj@9V2Gw z5c;UJ`M#gVP>2_eC8*TJe)4d=DktdDp5;}To6m6p^#i&)ZZ0zP0p}Z_RDL^9prc~0GfL@6{*z_S74P5?%7%ZEv!Fr9l9IujWbor^03<*96 zAJoN(_*>^(p6pryJrf{I{JiX#5g;o3z%*4KB9x>vWZ`v97zCk>`mTLF$@&ykCVT9S z40MWog=mf0ua%LAYr;x!YV6R&{uH)t2L!GQ$wq!N!KUav8jGu_jJI~Ao&K4^2j*QU z)eV}I{0d{zwaAC&d{I&CXe+8pk2r*&4zuSOulgI;GIh|XM%z|9cE__{B3s+!fZjqK8geB? z2FSP-hhQgcNogs?*w6<)_E}2-dV0V=HAPPBzfILJzO*y8ySTW6iT}z);GiB+;BW#%K$yXBB*%F1cD1bK6 z%R<#9LAsBp5Cn#;GSd+l)FpZbNj0!!w1N*=vwD={iWZOcw0g+>Fe#|b(J?L%SwkwB z3Y^*v3m#v9SjgZKtA#eneGzqzfAvUHab0^)1_i5}nknOPaqxDYgg+GqL8i88fVjJa zfMqx;Zo(2oi-Oy`3-Mdy69M7DqzKULf%x8<`PcIV)evWBM&^28&P=reWqnZq!`ij{hj+Qi^Y+m=7!!_#8K>SM=KFv3W7ql zf(#Y2qjjqJ1}neA@`sHs&2M^dIqd_ryiggPpNk(o6U zAr8RmCUVDv`Y}`Jg>IC1SOU-Um>OebWQ-U@3$^cX=a@PC2Xv#N*nMxuX%Z3MWyuc# zdht5);{lFmrJ1<}Iy6|#V&>ImK&0FtPvMUeVryH|Phak|%DKE%dX> zirfwG5c!54259+46CiR#=|i3r7UF{sL`dk2*)qpNS260^ID=lnH~a+n!=_*!c1KO+ zeLEYFMJ|vSr(yT8f6=T(q!R$-b@!krct(RK>41BP1dYm&R02naKL>yiG0(rirp^g- z-T4DY6?#NE=pvG@7CEg_HoL-_q>XR4Uc+8m&^&1K!X2|7p^}(d-9M + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/fonts/glyphicons-halflings-regular.ttf b/snow-flowable/src/main/resources/static/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a498ef4e7c8b556fc36f580c5ff524025bb11c84 GIT binary patch literal 41236 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%0Dt965W&Ju+|y^E^FA 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/fonts/lato-bold-webfont.ttf b/snow-flowable/src/main/resources/static/fonts/lato-bold-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..87107fc54ff9763d7a03f2f882d0c3c640a1f161 GIT binary patch literal 58344 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 + + + +
+
+ + {{alerts.current.message}} + +
+ {{alerts.queue.length + 1}} +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/snow-flowable/src/main/resources/static/libs/angular-animate_1.3.13/angular-animate.js b/snow-flowable/src/main/resources/static/libs/angular-animate_1.3.13/angular-animate.js new file mode 100644 index 0000000..8cd592d --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-animate_1.3.13/angular-animate.js @@ -0,0 +1,2137 @@ +/** + * @license AngularJS v1.3.13 + * (c) 2010-2014 Google, Inc. http://angularjs.org + * License: MIT + */ +(function(window, angular, undefined) {'use strict'; + +/* jshint maxlen: false */ + +/** + * @ngdoc module + * @name ngAnimate + * @description + * + * The `ngAnimate` module provides support for JavaScript, CSS3 transition and CSS3 keyframe animation hooks within existing core and custom directives. + * + *
+ * + * # Usage + * + * To see animations in action, all that is required is to define the appropriate CSS classes + * or to register a JavaScript animation via the `myModule.animation()` function. The directives that support animation automatically are: + * `ngRepeat`, `ngInclude`, `ngIf`, `ngSwitch`, `ngShow`, `ngHide`, `ngView` and `ngClass`. Custom directives can take advantage of animation + * by using the `$animate` service. + * + * Below is a more detailed breakdown of the supported animation events provided by pre-existing ng directives: + * + * | Directive | Supported Animations | + * |----------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------| + * | {@link ng.directive:ngRepeat#animations ngRepeat} | enter, leave and move | + * | {@link ngRoute.directive:ngView#animations ngView} | enter and leave | + * | {@link ng.directive:ngInclude#animations ngInclude} | enter and leave | + * | {@link ng.directive:ngSwitch#animations ngSwitch} | enter and leave | + * | {@link ng.directive:ngIf#animations ngIf} | enter and leave | + * | {@link ng.directive:ngClass#animations ngClass} | add and remove (the CSS class(es) present) | + * | {@link ng.directive:ngShow#animations ngShow} & {@link ng.directive:ngHide#animations ngHide} | add and remove (the ng-hide class value) | + * | {@link ng.directive:form#animation-hooks form} & {@link ng.directive:ngModel#animation-hooks ngModel} | add and remove (dirty, pristine, valid, invalid & all other validations) | + * | {@link module:ngMessages#animations ngMessages} | add and remove (ng-active & ng-inactive) | + * | {@link module:ngMessages#animations ngMessage} | enter and leave | + * + * You can find out more information about animations upon visiting each directive page. + * + * Below is an example of how to apply animations to a directive that supports animation hooks: + * + * ```html + * + * + * + * + * ``` + * + * Keep in mind that, by default, if an animation is running, any child elements cannot be animated + * until the parent element's animation has completed. This blocking feature can be overridden by + * placing the `ng-animate-children` attribute on a parent container tag. + * + * ```html + *
+ *
+ *
+ * ... + *
+ *
+ *
+ * ``` + * + * When the `on` expression value changes and an animation is triggered then each of the elements within + * will all animate without the block being applied to child elements. + * + * ## Are animations run when the application starts? + * No they are not. When an application is bootstrapped Angular will disable animations from running to avoid + * a frenzy of animations from being triggered as soon as the browser has rendered the screen. For this to work, + * Angular will wait for two digest cycles until enabling animations. From there on, any animation-triggering + * layout changes in the application will trigger animations as normal. + * + * In addition, upon bootstrap, if the routing system or any directives or load remote data (via $http) then Angular + * will automatically extend the wait time to enable animations once **all** of the outbound HTTP requests + * are complete. + * + * ## CSS-defined Animations + * The animate service will automatically apply two CSS classes to the animated element and these two CSS classes + * are designed to contain the start and end CSS styling. Both CSS transitions and keyframe animations are supported + * and can be used to play along with this naming structure. + * + * The following code below demonstrates how to perform animations using **CSS transitions** with Angular: + * + * ```html + * + * + *
+ *
+ *
+ * ``` + * + * The following code below demonstrates how to perform animations using **CSS animations** with Angular: + * + * ```html + * + * + *
+ *
+ *
+ * ``` + * + * Both CSS3 animations and transitions can be used together and the animate service will figure out the correct duration and delay timing. + * + * Upon DOM mutation, the event class is added first (something like `ng-enter`), then the browser prepares itself to add + * the active class (in this case `ng-enter-active`) which then triggers the animation. The animation module will automatically + * detect the CSS code to determine when the animation ends. Once the animation is over then both CSS classes will be + * removed from the DOM. If a browser does not support CSS transitions or CSS animations then the animation will start and end + * immediately resulting in a DOM element that is at its final state. This final state is when the DOM element + * has no CSS transition/animation classes applied to it. + * + * ### Structural transition animations + * + * Structural transitions (such as enter, leave and move) will always apply a `0s none` transition + * value to force the browser into rendering the styles defined in the setup (`.ng-enter`, `.ng-leave` + * or `.ng-move`) class. This means that any active transition animations operating on the element + * will be cut off to make way for the enter, leave or move animation. + * + * ### Class-based transition animations + * + * Class-based transitions refer to transition animations that are triggered when a CSS class is + * added to or removed from the element (via `$animate.addClass`, `$animate.removeClass`, + * `$animate.setClass`, or by directives such as `ngClass`, `ngModel` and `form`). + * They are different when compared to structural animations since they **do not cancel existing + * animations** nor do they **block successive transitions** from rendering on the same element. + * This distinction allows for **multiple class-based transitions** to be performed on the same element. + * + * In addition to ngAnimate supporting the default (natural) functionality of class-based transition + * animations, ngAnimate also decorates the element with starting and ending CSS classes to aid the + * developer in further styling the element throughout the transition animation. Earlier versions + * of ngAnimate may have caused natural CSS transitions to break and not render properly due to + * $animate temporarily blocking transitions using `0s none` in order to allow the setup CSS class + * (the `-add` or `-remove` class) to be applied without triggering an animation. However, as of + * **version 1.3**, this workaround has been removed with ngAnimate and all non-ngAnimate CSS + * class transitions are compatible with ngAnimate. + * + * There is, however, one special case when dealing with class-based transitions in ngAnimate. + * When rendering class-based transitions that make use of the setup and active CSS classes + * (e.g. `.fade-add` and `.fade-add-active` for when `.fade` is added) be sure to define + * the transition value **on the active CSS class** and not the setup class. + * + * ```css + * .fade-add { + * /* remember to place a 0s transition here + * to ensure that the styles are applied instantly + * even if the element already has a transition style */ + * transition:0s linear all; + * + * /* starting CSS styles */ + * opacity:1; + * } + * .fade-add.fade-add-active { + * /* this will be the length of the animation */ + * transition:1s linear all; + * opacity:0; + * } + * ``` + * + * The setup CSS class (in this case `.fade-add`) also has a transition style property, however, it + * has a duration of zero. This may not be required, however, incase the browser is unable to render + * the styling present in this CSS class instantly then it could be that the browser is attempting + * to perform an unnecessary transition. + * + * This workaround, however, does not apply to standard class-based transitions that are rendered + * when a CSS class containing a transition is applied to an element: + * + * ```css + * /* this works as expected */ + * .fade { + * transition:1s linear all; + * opacity:0; + * } + * ``` + * + * Please keep this in mind when coding the CSS markup that will be used within class-based transitions. + * Also, try not to mix the two class-based animation flavors together since the CSS code may become + * overly complex. + * + * + * ### Preventing Collisions With Third Party Libraries + * + * Some third-party frameworks place animation duration defaults across many element or className + * selectors in order to make their code small and reuseable. This can lead to issues with ngAnimate, which + * is expecting actual animations on these elements and has to wait for their completion. + * + * You can prevent this unwanted behavior by using a prefix on all your animation classes: + * + * ```css + * /* prefixed with animate- */ + * .animate-fade-add.animate-fade-add-active { + * transition:1s linear all; + * opacity:0; + * } + * ``` + * + * You then configure `$animate` to enforce this prefix: + * + * ```js + * $animateProvider.classNameFilter(/animate-/); + * ``` + *

OSg+O7v1uMt)8fRG^AH!_jP8S)SYDEQAVV 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 Z(}8g#H;8Bh09+V9mH+?&R0uEI004T*CYAsI literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/fonts/lato-regular-webfont.eot b/snow-flowable/src/main/resources/static/fonts/lato-regular-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..b294f6c349351ecfd771e3a515676f99d1fbee37 GIT binary patch literal 28222 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 WeR)}BM`fQQW#SktZW^AOnHGSvj@q99 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/fonts/lato-regular-webfont.svg b/snow-flowable/src/main/resources/static/fonts/lato-regular-webfont.svg new file mode 100644 index 0000000..96737af --- /dev/null +++ b/snow-flowable/src/main/resources/static/fonts/lato-regular-webfont.svg @@ -0,0 +1,4241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/fonts/lato-regular-webfont.ttf b/snow-flowable/src/main/resources/static/fonts/lato-regular-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0768020a579a5dfc15587aef34da5ba750f2f334 GIT binary patch literal 57528 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 DGaFlowable Forum " + }, + + "FEATURE-TOUR" : { + "BENDPOINT" : { + "TITLE": "Bend point tutorial", + "DESCRIPTION" : "When you are connecting process steps with each other using sequence flow (those arrows between process steps), you might find that these sequence flow cross each other or you would like to arrange them differently. To do this, you can add or remove a bend point to or from a sequence flow.

As shown below in the picture, you first click the 'add bendpoint' and then click on a sequence flow to add it. Note that the sequence flow will show you a subtle indication in green to show the bendpoint can be added there.

Removing a bendpoint again follows a similar pattern: click the 'remove bendpoint' button and click on the bend point to remove it again." + } + }, + + "ACTION.OK" : "Ok", + "ACTION.SAVE" : "Save", + "ACTION.SAVE-AND-CLOSE" : "Save and close editor", + "ACTION.SEND" : "Send", + "ACTION.CANCEL" : "Cancel", + "ACTION.SELECT" : "Select", + "ACTION.ADD" : "Add", + "ACTION.REMOVE" : "Remove", + "ACTION.MOVE.UP" : "Move entry up", + "ACTION.MOVE.DOWN" : "Move entry down", + + "TOOLBAR.ACTION.CLOSE" : "Close the editor and go back to the overview page", + "TOOLBAR.ACTION.SAVE" : "Save the model", + "TOOLBAR.ACTION.VALIDATE" : "Validate the model", + "TOOLBAR.ACTION.CUT" : "Cut (select one or more elements in your business process)", + "TOOLBAR.ACTION.COPY" : "Copy (select one or more elements in your business process)", + "TOOLBAR.ACTION.PASTE" : "Paste", + "TOOLBAR.ACTION.DELETE" : "Delete the selected element", + "TOOLBAR.ACTION.UNDO" : "Undo", + "TOOLBAR.ACTION.REDO" : "Redo", + "TOOLBAR.ACTION.ZOOMIN" : "Zoom in", + "TOOLBAR.ACTION.ZOOMOUT" : "Zoom out", + "TOOLBAR.ACTION.ZOOMACTUAL" : "Zoom to actual size", + "TOOLBAR.ACTION.ZOOMFIT" : "Zoom to fit", + "TOOLBAR.ACTION.BENDPOINT.ADD" : "Add bend-point to the selected sequence flow", + "TOOLBAR.ACTION.BENDPOINT.REMOVE" : "Remove bend-point from the selected sequence flow", + "TOOLBAR.ACTION.ALIGNHORIZONTAL" : "Align model horizontal", + "TOOLBAR.ACTION.ALIGNVERTICAL" : "Align model vertical", + "TOOLBAR.ACTION.SAMESIZE" : "Same size", + "TOOLBAR.ACTION.HELP": "Start the guided tour", + "TOOLBAR.ACTION.FEEDBACK": "Provide feedback", + + "FORM_TOOLBAR.ACTION.SAVE" : "Save the model", + + "APP_DEFINITION_TOOLBAR.ACTION.SAVE" : "Save the app definition", + + "BUTTON.ACTION.DELETE.TOOLTIP": "Delete the element from the model", + "BUTTON.ACTION.MORPH.TOOLTIP": "Change the element type", + + "ELEMENT.AUTHOR" : "Author", + "ELEMENT.DATE_CREATED" : "Date created", + + "PROPERTY.REMOVED" : "removed", + "PROPERTY.EMPTY" : "No value", + "PROPERTY.PROPERTY.EDIT.TITLE" : "Change value for ", + + "PROPERTY.FEEDBACK.TITLE" : "Please fill-in your feedback", + + "PROPERTY.ASSIGNMENT.TITLE" : "Assignment", + "PROPERTY.ASSIGNMENT.TYPE" : "Type", + "PROPERTY.ASSIGNMENT.TYPE.IDENTITYSTORE" : "Identity store", + "PROPERTY.ASSIGNMENT.TYPE.STATIC" : "Fixed values", + "PROPERTY.ASSIGNMENT.ASSIGNEE" : "Assignee", + "PROPERTY.ASSIGNMENT.MATCHING" : "Use ↑ and ↓ to select and press Enter to confirm or use the mouse", + "PROPERTY.ASSIGNMENT.ASSIGNEE_PLACEHOLDER" : "Enter an assignee", + "PROPERTY.ASSIGNMENT.EMPTY" : "No assignment selected", + "PROPERTY.ASSIGNMENT.NONE" : "None ...", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHUSER": "Search user", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHGROUP": "Search group", + "PROPERTY.ASSIGNMENT.SEARCH": "Search: ", + "PROPERTY.ASSIGNMENT.ASSIGNEE_DISPLAY" : "Assignee {{assignee}}", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY" : "{{length}} Candidate users", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS" : "Candidate users", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY" : "{{length}} Candidate groups", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS" : "Candidate groups", + "PROPERTY.ASSIGNMENT.USER_IDM_DISPLAY": "User {{firstName}} {{lastName}}", + "PROPERTY.ASSIGNMENT.USER_IDM_EMAIL_DISPLAY": "User {{email}}", + "PROPERTY.ASSIGNMENT.USER_IDM_FIELD_DISPLAY": "Field {{name}}", + "PROPERTY.ASSIGNMENT.IDM_EMPTY" : "Process initiator", + "PROPERTY.ASSIGNMENT.IDM.TYPE" : "Assignment", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_USERS" : "No candidate users selected...", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_GROUPS" : "No candidate groups selected...", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.INITIATOR" : "Assigned to process initiator", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USER" : "Assigned to single user", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USERS" : "Candidate users", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.GROUPS" : "Candidate groups", + "PROPERTY.ASSIGNMENT.INITIATOR-CAN-COMPLETE" : "Allow process initiator to complete task", + "PROPERTY.EXECUTIONLISTENERS.DISPLAY" : "{{length}} execution listeners", + "PROPERTY.EXECUTIONLISTENERS.EMPTY" : "No execution listeners configured", + "PROPERTY.EXECUTIONLISTENERS.EVENT" : "Event", + "PROPERTY.EXECUTIONLISTENERS.CLASS" : "Class", + "PROPERTY.EXECUTIONLISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION" : "Expression", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.EXECUTIONLISTENERS.UNSELECTED" : "No execution listener selected", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME" : "Name", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING" : "String", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.IMPLEMENTATION" : "Implementation", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EMPTY" : "No Field selected", + + "PROPERTY.FIELDS" : "{{length}} fields", + "PROPERTY.FIELDS.EMPTY" : "No fields selected", + "PROPERTY.FIELDS.NAME" : "Name", + "PROPERTY.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.FIELDS.STRING" : "String", + "PROPERTY.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.FIELDS.IMPLEMENTATION" : "Implementation", + + "PROPERTY.DATAPROPERTIES.VALUES" : "{{length}} data objects", + "PROPERTY.DATAPROPERTIES.EMPTY" : "No data objects configured", + "PROPERTY.DATAPROPERTIES.ID" : "Id", + "PROPERTY.DATAPROPERTIES.ID.PLACEHOLDER" : "Enter an id", + "PROPERTY.DATAPROPERTIES.NAME" : "Name", + "PROPERTY.DATAPROPERTIES.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.DATAPROPERTIES.TYPE" : "Type", + "PROPERTY.DATAPROPERTIES.VALUE.PLACEHOLDER" : "Enter a value (optional)", + "PROPERTY.DATAPROPERTIES.VALUE" : "Default Value", + + "PROPERTY.FORMPROPERTIES.VALUE" : "{{length}} form properties", + "PROPERTY.FORMPROPERTIES.EMPTY" : "No form properties selected", + "PROPERTY.FORMPROPERTIES.ID" : "Id", + "PROPERTY.FORMPROPERTIES.ID.PLACEHOLDER" : "Enter an id", + "PROPERTY.FORMPROPERTIES.NAME" : "Name", + "PROPERTY.FORMPROPERTIES.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.FORMPROPERTIES.TYPE" : "Type", + "PROPERTY.FORMPROPERTIES.DATEPATTERN" : "Date pattern", + "PROPERTY.FORMPROPERTIES.DATEPATTERN.PLACEHOLDER" : "Enter date pattern", + "PROPERTY.FORMPROPERTIES.VALUES" : "Values", + "PROPERTY.FORMPROPERTIES.ENUMVALUES.EMPTY" : "No enum value selected", + "PROPERTY.FORMPROPERTIES.VALUES.ID" : "Id", + "PROPERTY.FORMPROPERTIES.VALUES.NAME" : "Name", + "PROPERTY.FORMPROPERTIES.VALUES.ID.PLACEHOLDER" : "Enter id of a value", + "PROPERTY.FORMPROPERTIES.VALUES.NAME.PLACEHOLDER" : "Enter name of a value", + "PROPERTY.FORMPROPERTIES.EXPRESSION" : "Expression", + "PROPERTY.FORMPROPERTIES.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.FORMPROPERTIES.VARIABLE" : "Variable", + "PROPERTY.FORMPROPERTIES.VARIABLE.PLACEHOLDER" : "Enter a variable", + "PROPERTY.FORMPROPERTIES.DEFAULT" : "default", + "PROPERTY.FORMPROPERTIES.DEFAULT.PLACEHOLDER" : "Enter a default", + "PROPERTY.FORMPROPERTIES.REQUIRED" : "Required", + "PROPERTY.FORMPROPERTIES.READABLE" : "Readable", + "PROPERTY.FORMPROPERTIES.WRITABLE" : "Writable", + + "PROPERTY.INPARAMETERS.VALUE" : "{{length}} in-parameters", + "PROPERTY.INPARAMETERS.EMPTY" : "No in-parameters configured", + + "PROPERTY.OUTPARAMETERS.VALUE" : "{{length}} out-parameters", + "PROPERTY.OUTPARAMETERS.EMPTY" : "No out-parameters configured", + + "PROPERTY.PARAMETER.SOURCE" : "Source", + "PROPERTY.PARAMETER.SOURCE.PLACEHOLDER" : "Enter a source", + "PROPERTY.PARAMETER.SOURCEEXPRESSION" : "Source expression", + "PROPERTY.PARAMETER.SOURCEEXPRESSION.PLACEHOLDER" : "Enter a source expression", + "PROPERTY.PARAMETER.TARGET" : "Target", + "PROPERTY.PARAMETER.TARGET.PLACEHOLDER" : "Enter a target", + "PROPERTY.PARAMETER.EMPTY" : "No parameter selected", + + "PROPERTY.PROCESSREFERENCE.EMPTY" : "No reference selected", + "PROPERTY.PROCESSREFERENCE.TITLE" : "Process reference", + "PROPERTY.PROCESSREFERENCE.ERROR.PROCESS" : "There was an error loading the processes. Try again later", + "PROPERTY.PROCESSREFERENCE.PROCESS.LOADING" : "Loading processes...", + "PROPERTY.PROCESSREFERENCE.PROCESS.EMPTY" : "This folder contains no processes", + + "PROPERTY.FORMREFERENCE.EMPTY" : "No reference selected", + "PROPERTY.FORMREFERENCE.TITLE" : "Form reference", + "PROPERTY.FORMREFERENCE.DESCRIPTION" : "Reference to a form", + "PROPERTY.FORMREFERENCE.ERROR.FORM" : "There was an error loading the forms. Try again later", + "PROPERTY.FORMREFERENCE.FORM.LOADING" : "Loading forms...", + "PROPERTY.FORMREFERENCE.FORM.EMPTY" : "This folder contains no forms", + + "PROPERTY.TASKLISTENERS.VALUE" : "{{length}} task listeners", + "PROPERTY.TASKLISTENERS.EMPTY" : "No task listeners configured", + "PROPERTY.TASKLISTENERS.EVENT" : "Event", + "PROPERTY.TASKLISTENERS.CLASS" : "Class", + "PROPERTY.TASKLISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.TASKLISTENERS.EXPRESSION" : "Expression", + "PROPERTY.TASKLISTENERS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.TASKLISTENERS.UNSELECTED" : "No task listener selected", + "PROPERTY.TASKLISTENERS.FIELDS.NAME" : "Name", + "PROPERTY.TASKLISTENERS.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.TASKLISTENERS.FIELDS.STRING" : "String", + "PROPERTY.TASKLISTENERS.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.TASKLISTENERS.FIELDS.IMPLEMENTATION" : "Implementation", + "PROPERTY.TASKLISTENERS.FIELDS.EMPTY" : "No Field selected", + + "PROPERTY.EVENTLISTENERS.DISPLAY" : "{{length}} event listeners", + "PROPERTY.EVENTLISTENERS.EMPTY" : "No event listeners configured", + "PROPERTY.EVENTLISTENERS.EVENTS": "Events", + "PROPERTY.EVENTLISTENERS.RETHROW": "Rethrow event?", + "PROPERTY.EVENTLISTENERS.CLASS" : "Class", + "PROPERTY.EVENTLISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE" : "Entity type", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE.PLACEHOLDER" : "Enter an entity type", + "PROPERTY.EVENTLISTENERS.RETHROWTYPE": "Rethrow event type", + "PROPERTY.EVENTLISTENERS.ERRORCODE" : "Error code", + "PROPERTY.EVENTLISTENERS.ERRORCODE.PLACEHOLDER" : "Enter an error code", + "PROPERTY.EVENTLISTENERS.MESSAGENAME" : "Message name", + "PROPERTY.EVENTLISTENERS.MESSAGENAME.PLACEHOLDER" : "Enter a message name", + "PROPERTY.EVENTLISTENERS.SIGNALNAME" : "Signal name", + "PROPERTY.EVENTLISTENERS.SIGNALNAME.PLACEHOLDER" : "Enter a signal name", + "PROPERTY.EVENTLISTENERS.UNSELECTED" : "No event listener selected", + + "PROPERTY.PLANITEMLIFECYCLELISTENERS.VALUE" : "{{length}} lifecycle listeners", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EMPTY" : "No lifecycle listeners configured", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EVENT" : "Event", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.SOURCE_STATE" : "Source state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.TARGET_STATE" : "Target state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS" : "Class", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.UNSELECTED" : "No task listener selected", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME" : "Name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING" : "String", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.IMPLEMENTATION" : "Implementation", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EMPTY" : "No Field selected", + + "PROPERTY.SIGNALDEFINITIONS.DISPLAY" : "{{length}} signal definitions", + "PROPERTY.SIGNALDEFINITIONS.EMPTY" : "No signal definitions configured", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-GLOBAL": "Global", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-PROCESSINSTANCE": "Process Instance", + "PROPERTY.SIGNALDEFINITIONS.ID" : "Id", + "PROPERTY.SIGNALDEFINITIONS.NAME" : "Name", + "PROPERTY.SIGNALDEFINITIONS.SCOPE" : "Scope", + + "PROPERTY.MESSAGEDEFINITIONS.DISPLAY" : "{{length}} message definitions", + "PROPERTY.MESSAGEDEFINITIONS.EMPTY" : "No message definitions configured", + "PROPERTY.MESSAGEDEFINITIONS.ID" : "Id", + "PROPERTY.MESSAGEDEFINITIONS.NAME" : "Name", + + "PROPERTY.SEQUENCEFLOW.ORDER.EMPTY" : "No sequence flow order determined", + "PROPERTY.SEQUENCEFLOW.ORDER.NOT.EMPTY" : "Sequence flow order set", + "PROPERTY.SEQUENCEFLOW.ORDER.NO.OUTGOING.SEQUENCEFLOW.FOUND" : "No outgoing sequence flow found.", + "PROPERTY.SEQUENCEFLOW.ORDER.DESCRIPTION" : "Set the order in which the sequence flow need to be evaluated:", + "PROPERTY.SEQUENCEFLOW.ORDER.SEQUENCEFLOW.VALUE" : "Sequence flow to {{targetType}} {{targetTitle}}", + + "PROPERTY.SEQUENCEFLOW.CONDITION.TITLE" : "Sequence flow condition", + "PROPERTY.SEQUENCEFLOW.CONDITION.STATIC" : "Condition expression", + "PROPERTY.SEQUENCEFLOW.CONDITION.NO-CONDITION-DISPLAY": "No condition set", + + "PROPERTY.DUEDATE.EMPTY" : "No due date", + "PROPERTY.DUEDATE.DEFINED" : "Due date defined", + "PROPERTY.DUEDATE.TITLE" : "Due date", + "PROPERTY.DUEDATE.EXPRESSION-LABEL" : "Due date expression", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.NO-DUEDATE" : "No due date", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.EXPRESSION" : "Expression definition", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.STATIC" : "Fixed duration after task creation", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.FIELD" : "Based on field", + + "MODEL.SAVE.TITLE" : "Save model", + "MODEL.VALIDATE.TITLE" : "Validation results", + "MODEL.NAME" : "Name", + "MODEL.KEY" : "Key", + "MODEL.DESCRIPTION" : "Description", + "MODEL.SAVE.NEWVERSION" : "Save this as a new version? This means you can always go back to a previous version", + "MODEL.SAVE.COMMENT" : "Comment", + "MODEL.SAVE.SAVING" : "Saving model", + "MODEL.LASTMODIFIEDDATE" : "Last saved", + "MODEL.SAVE.ERROR": "Unexpected error: could not save model", + "MODEL.VALIDATIONERRORS": "Note that the model contains validation errors. This means that the model can not be deployed on the Flowable Engine in its current state.", + "MODEL.CONFLICT.WRITE": "Could not save model: '{{userFullName}}' has made changes to this model", + "MODEL.CONFLICT.WRITE.OPTIONS": "Select an option to resolve this conflict:", + "MODEL.CONFLICT.WRITE.OPTION.OVERWRITE": "Overwrite other model", + "MODEL.CONFLICT.WRITE.OPTION.DISCARDCHANGES": "Discard my changes", + "MODEL.CONFLICT.WRITE.OPTION.SAVEAS": "Save as new model", + "MODEL.CONFLICT.WRITE.OPTION.NEWVERSION": "Create new version", + "MODEL.CONFLICT.SAVEAS" : "Save as:", + + "EVENT_TYPE.ACTIVITY.COMPENSATE.TOOLTIP": "An activity is about to be executed as a compensation for another activity. The event targets the activity that is about to be executed for compensation", + "EVENT_TYPE.ACTIVITY.COMPLETED.TOOLTIP": "An activity has been completed successfully", + "EVENT_TYPE.ACTIVITY.ERROR.RECEIVED.TOOLTIP": "An activity has received an error event. Dispatched before the actual error has been received by the activity", + "EVENT_TYPE.MEMBERSHIP.CREATED.TOOLTIP": "A new membership has been created", + "EVENT_TYPE.MEMBERSHIP.DELETED.TOOLTIP": "A single membership has been deleted", + "EVENT_TYPE.MEMBERSHIPS.DELETED.TOOLTIP": "All memberships in the related group have been deleted. No individual events will be dispatched due to possible performance reasons", + "EVENT_TYPE.TASK.ASSIGNED.TOOLTIP": "A task as been assigned. This is thrown alongside with an ENTITY_UPDATED event", + "EVENT_TYPE.TASK.COMPLETED.TOOLTIP": "A task has been completed. Dispatched before the task entity is deleted", + "EVENT_TYPE.UNCAUGHT.BPMNERROR.TOOLTIP": "When a BPMN Error was thrown, but was not caught within in the process", + "EVENT_TYPE.VARIABLE.CREATED.TOOLTIP": "A new variable has been created", + "EVENT_TYPE.VARIABLE.DELETED.TOOLTIP": "An existing variable has been deleted", + "EVENT_TYPE.VARIABLE.UPDATED.TOOLTIP": "An existing variable has been updated", + + "PROPERTY.DECISIONTABLEREFERENCE.EMPTY" : "No reference selected", + "PROPERTY.DECISIONTABLEREFERENCE.TITLE" : "Decision table reference", + "PROPERTY.DECISIONTABLEREFERENCE.ERROR.FORM" : "There was an error loading the decision tables. Try again later", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.LOADING" : "Loading decision tables...", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.EMPTY" : "This folder contains no decision tables", + + "PROPERTY.CASEREFERENCE.EMPTY" : "No reference selected", + "PROPERTY.CASEREFERENCE.TITLE" : "Case model reference", + "PROPERTY.CASEREFERENCE.ERROR.FORM" : "There was an error loading the case models. Try again later", + "PROPERTY.CASEREFERENCE.CASE.LOADING" : "Loading case models...", + "PROPERTY.CASEREFERENCE.CASE.EMPTY" : "This folder contains no case models" +} diff --git a/snow-flowable/src/main/resources/static/i18n/es.json b/snow-flowable/src/main/resources/static/i18n/es.json new file mode 100644 index 0000000..9df3801 --- /dev/null +++ b/snow-flowable/src/main/resources/static/i18n/es.json @@ -0,0 +1,870 @@ +{ + "GENERAL" : { + "MAIN-TITLE": "Flowable Editor", + "NAVIGATION" : { + "PROCESSES": "Procesos", + "FORMS": "Formularios", + "DECISION-TABLES": "Tablas de decisión", + "APPS": "Aplicaciones" + }, + "TITLE": { + "SELECT-GROUP" :"Selecciona el grupo", + "MATCHING-GROUPS": "Grupos coincidentes", + "FILTER": "Filtro", + "HISTORY": "Historial" + }, + "ACTION": { + "LOGOUT": "Salir", + "RETURN-TO-LIST": "Mostrar todas las definiciones", + "CANCEL": "Cancelar", + "CLOSE": "Cerrar", + "EDIT": "Editar", + "SAVE": "Guardar", + "OPEN": "Abrir", + "OK": "Ok", + "CONFIRM": "Confirmar", + "CONFIRM-AND-CLOSE": "Confirmar y cerrar", + "NEW-FORM": "Nuevo formulario", + "CREATE-FORM": "Crear formulario", + "NEW-DECISION-TABLE": "Nueva tabla de decisión", + "CREATE-DECISION-TABLE": "Crear tabla de decisión" + }, + "MESSAGE": { + "SELECT-GROUP-HELP": "Usa ↑ y ↓ para seleccionar y presiona Enter para confirmar", + "PEOPLE-NO-MATCHING-RESULTS": "No se encontraron usuarios similares", + "GROUP-NO-MATCHING-RESULTS": "No se encontraron grupos similares", + "GROUP-SOURCE-TYPE": "Group source", + "GROUP-SOURCE-SEARCH-OPTION": "Busqueda de grupo", + "GROUP-SOURCE-FIELD-OPTION": "Campo de formulario" + } + }, + + "EDITOR": { + "POPUP": { + "UNSAVED-CHANGES": { + "TITLE": "Tienes cambios sin guardar", + "DESCRIPTION": "Que deseas realizar con los cambios sin guardar?", + "ACTION": { + "SAVE": "Guardar cambios", + "DISCARD": "Descartar cambios", + "CONTINUE": "Continiar edición" + } + } + } + }, + + "PROCESS-LIST" : { + "TITLE" : "Modelos de procesos de negocio", + "SEARCH-PLACEHOLDER": "Buscar", + "ACTION" : { + "CREATE": "Crear Proceso", + "IMPORT": "Importar Proceso" + }, + + "FILTER" : { + "PROCESSES": "Modelo de proceso", + "PROCESSES-COUNT": "Existen {{total}} modelos de proceso", + "PROCESSES-ONE": "Existe un modelo de proceso", + "PROCESSES-EMPTY": "Aun no existe un modelo de proceso creado. puedes diseñar tus propios modelos, formularios y despues incluirlos en una aplicación. El primer paso es crear un modelo de proceso:", + "PROCESSES-BPMN-HINT": "Crear un modelo BPMN usando el editor visual BPMN.", + "PROCESSES-BPMN-IMPORT-HINT": "Tambien puede importar modelos BPMN existentes.", + "FILTER-TEXT": ", parecido a \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "No existen modelos de proceso parecidos a \"{{filterText}}\"", + "RECENT": "Reciente", + "RECENT-COUNT": "{{total}} modelos usados recientemente", + "RECENT-ONE": "Existe un modelo usado recientemente", + "RECENT-EMPTY": "No existen modelos usados recientemente" + }, + + "SORT": { + "MODIFIED-ASC": "Antiguo", + "MODIFIED-DESC": "Ultimo modificado", + "NAME-ASC": "Nombre, A-Z", + "NAME-DESC": "Nombre, Z-A" + } + }, + + "FORMS-LIST" : { + "TITLE" : "Formularios", + "SEARCH-PLACEHOLDER": "Busqueda", + "ACTION" : { + "CREATE": "Crear formulario", + "CREATE-INLINE": "Crear un nuevo formulario ahora!", + "SHOW-MORE": "Mostrar más..." + }, + + "FILTER" : { + "FORMS": "Formularios", + "FORMS-COUNT": "Existen {{total}} formularios", + "FORMS-ONE": "Existe un formulario", + "FORMS-EMPTY": "No existen formularios. Para agregar uno da click en Crear formulario.", + "FILTER-TEXT": ", parecido a \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "No existe un formulario parecido a \"{{filterText}}\"" + }, + + "SORT": { + "MODIFIED-ASC": "Antiguo", + "MODIFIED-DESC": "Ultimo modificado", + "NAME-ASC": "Nombre, A-Z", + "NAME-DESC": "Nombre, Z-A" + } + }, + + "DECISION-TABLES-LIST": { + "TITLE": "Tablas de decision", + "SEARCH-PLACEHOLDER": "Busqueda", + "ACTION": { + "CREATE": "Crear tabla de decision", + "IMPORT": "Importar tabla de decision", + "CREATE-INLINE": "Crear una tabla de decision ahora!", + "SHOW-MORE": "Mostrar más..." + }, + + "FILTER": { + "DECISION-TABLES": "Tablas de decision", + "DECISION-TABLES-COUNT": "Existen {{total}} tablas de decision", + "DECISION-TABLES-ONE": "Existe una tabla de decision", + "DECISION-TABLES-EMPTY": "No existen tablas de decision. Para agregar una da click en Crear tabla de decision.", + "FILTER-TEXT": ", parecido a \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "no existen tablas de decision parecidas a \"{{filterText}}\"" + }, + + "SORT": { + "MODIFIED-ASC": "Antiguo", + "MODIFIED-DESC": "Ultimo modificado", + "NAME-ASC": "Nombre, A-Z", + "NAME-DESC": "Nombre, Z-A" + } + }, + + "APPS-LIST" : { + "TITLE" : "Aplicaciones", + "SEARCH-PLACEHOLDER": "Busqueda", + "ACTION" : { + "CREATE": "Crear App", + "IMPORT": "Importar App", + "SHOW-MORE": "Mostrar mas..." + }, + + "FILTER" : { + "APPS": "Aplicaciones", + "APPS-COUNT": "Existen {{total}} aplicaciones", + "APPS-ONE": "Existe una aplicacion", + "APPS-EMPTY": "No existen aplicaciones. Para agregar una da click en Crear App.", + "FILTER-TEXT": ", parecido a \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "No existen aplicaciones parecidas a \"{{filterText}}\"", + + "NO-APPS": "Puedes crear una aplicacion publicando un conjunto de Modelos de Proceso.", + "NO-APPS-CALL-TO-ACTION": "Puedes crear una aplicacion ahora.", + "NO-APPS-NOTE": "Recuerda publicar cuando estes listo para usar la aplicacion." + }, + + "SORT": { + "MODIFIED-ASC": "Antiguo", + "MODIFIED-DESC": "Ultimo modificado", + "NAME-ASC": "Nombre, A-Z", + "NAME-DESC": "Nombre, Z-A" + } + }, + "PROCESS": { + "NAME": "Nombre del modelo", + "KEY": "Identificador del modelo", + "DESCRIPTION": "Descripcion", + "VERSION-COMMENT": "Comentario de version", + "ACTION": { + "DETAILS": "Mostrar detalles", + "EDIT": "Modificar propiedades del modelo", + "DUPLICATE": "Duplicar este modelo", + "EXPORT_BPMN20": "Exportar a BPMN 2.0", + "DELETE": "Borrar este modelo", + "CREATE-CONFIRM": "Crear nuevo modelo", + "DUPLICATE-CONFIRM": "Duplicar el modelo", + "OPEN-IN-EDITOR": "Editor visual", + "EDIT-CONFIRM": "Guardar", + "DELETE-CONFIRM": "Borrar modelo de proceso", + "USE-AS-NEW-VERSION": "Usar como nueva version", + "FAVORITE": "Hacer modelo favorito" + + }, + "DETAILS": { + "HISTORY-TITLE": "Historial", + "LAST-UPDATED-BY": "Ultima actualizacion por {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Creado por {{createdBy}}", + "NO-DESCRIPTION": "Este modelo no tiene descripcion. Modifica las propiedades del modelo para agregar una" + }, + + "POPUP": { + "CREATE-TITLE": "Crear un nuevo modelo de proceso de negocio", + "DUPLICATE-TITLE": "Duplicar modelo de proceso de negocio", + "CREATE-DESCRIPTION": "Necesitas dar un nombre para el nuevo modelo y es recomendable que agregues una descripción al mismo tiempo.", + "DUPLICATE-DESCRIPTION": "Puedes cambiar el nombre del modelo y es recomendable que cambies la descripción al mismo tiempo.", + "EDIT-DESCRIPTION": "Cambia cualquiera de las propiedades del modelo y despues presiona Guardar para actualizar el modelo.", + "DELETE-DESCRIPTION": "Estas seguro que deseas borral el modelo de proceso de negocio \"{{name}}\"?", + "EDIT-TITLE":"Editar los detalles del modelo", + "DELETE-TITLE": "Borrar modelo", + "DELETE-LOADING-RELATIONS": "Verificando el uso del modelo...", + "DELETE-RELATIONS-DESCRIPTION-SINGLE": "Este modelo no puede ser eliminado porque esta siendo utilizado por otro modelo:", + "DELETE-RELATIONS-DESCRIPTION": "Este modelo no puede ser eliminado porque esta siendo utilizado por otros modelos:", + "DELETE-PROCESS-RELATION": "Modelo de proceso", + "DELETE-FORM-RELATION": "Formulario de modelo", + "DELETE-APP-RELATION": "Modelo de App", + "IMPORT-DESCRIPTION": "Busca o arrastra una definicion BPMN XML con la extension .bpmn o .bpmn20.xml", + "IMPORT-TITLE": "Importar un modelo de proceso", + "USE-AS-NEW-TITLE": "Usar como nueva version", + "USE-AS-NEW-DESCRIPTION": "Estas seguro que deseas utilizar la version {{version}} para crear una nueva version de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "No se pudo restaurar a la version seleccionada: Algunos modelos no se encuentran debido a que fueron borrados. Por favor actualiza el modelo de la aplicacion. Modelos faltantes:", + "USE-AS-NEW-UNRESOLVED-MODEL": "Modelo '{{name}}' con el id {{id}}, creado por {{createdBy}}", + "SHARED-WITH": "Compartido con", + "PERMISSION": "Permiso", + "ACTIONS": "Acciones", + "IMPORT": { + "DROPZONE": "Arrastra un archivo .bpmn or .bpmn20.xml BPMN XML", + "CANCEL-UPLOAD": "Cancelar la carga de archivo", + "ERROR": "Error al procesar el archivo BPMN XML", + "NO-DROP": "Arrastrar y soltar no soportado" + } + }, + "ALERT": { + "EDIT-CONFIRM": "Modelo actualizado" + }, + "ERROR": { + "NOT-FOUND": "El modelo solicitado no existe" + } + }, + + "SUBPROCESS": { + "NAME": "Nombre del Sub proceso", + "DESCRIPTION": "Descripcion", + "ACTION": { + "CREATE-CONFIRM": "Crear nuevo sub proceso" + }, + "POPUP": { + "CREATE-TITLE": "Crear nuevo sub proceso", + "CREATE-DESCRIPTION": "Necesitas proporcionar un nombre para el nuevo sub proceso y es recomendable agregar una descripcion al mismo tiempo." + } + }, + + "FORM": { + "NAME": "Nombre del formulario", + "KEY": "identificador del formulario", + "DESCRIPTION": "Descripcion", + "ACTION": { + "DETAILS": "Mostrar detalles", + "EDIT": "Modicar propiedades del modelo", + "DELETE": "Borrar este formulario", + "CREATE-CONFIRM": "Crear nuevo formulario", + "DUPLICATE-CONFIRM": "Duplicar el formulario", + "OPEN-IN-EDITOR": "Editor de formulario", + "EDIT-CONFIRM": "Guardar", + "DELETE-CONFIRM": "Borrar formulario", + "USE-AS-NEW-VERSION": "Usar como nueva version" + + }, + "DETAILS": { + "HISTORY-TITLE": "Historial", + "LAST-UPDATED-BY": "Ultima actualizacion por {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Creado por {{createdBy}}" + }, + + "POPUP": { + "CREATE-TITLE": "Crear nuevo formulario", + "DUPLICATE-TITLE": "Duplicar formulario", + "CREATE-DESCRIPTION": "Necesitas proporcionar un nombre para el nuevo formulario y es recomendable agregar una descripcion al mismo tiempo.", + "DUPLICATE-DESCRIPTION": "Necesitas proporcionar un nombre para el nuevo formulario y es recomendable agregar una descripcion al mismo tiempo.", + "SAVE-FORM-TITLE": "Guardar formulario", + "EDIT-DESCRIPTION": "Cambia cualquiera de las propiedades debajo y despues presiona Guardar para actualizar el formulario.", + "DELETE-DESCRIPTION": "Estas seguro de borrar el formulario \"{{name}}\"?", + "EDIT-TITLE":"Editar detalles de formulario", + "DELETE-TITLE": "Borrar formulario", + "USE-AS-NEW-TITLE": "Usar como nueva version", + "USE-AS-NEW-VERSION": "Usar como nueva version", + "USE-AS-NEW-DESCRIPTION": "Estas seguro que quieres utilizar la version {{version}} para crear una nueva version de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "No se pudo restaurar completamente a la version seleccionada: Algunos modelos referenciados fueron borrados. Por favor actualiza el modelo. Moodelos faltantes:", + "USE-AS-NEW-UNRESOLVED-MODEL": "Modelo '{{name}}' con identificador {{id}}, creado por {{createdBy}}" + } + }, + + "DECISION-TABLE": { + "NAME": "Nombre de la Tabla de decision", + "KEY": "Identificador de la Tabla de decision", + "DESCRIPTION": "Descripcion", + "VERSION-COMMENT": "Comentario de version", + "HIT-POLICY": "Reglas de aciertos:", + "ACTION": { + "DETAILS": "Mostrar detalles", + "EDIT": "Modificar propiedades del modelo", + "SHARE": "Compartir esta tabla de decision", + "DELETE": "Borrar esta tabla de decision", + "ADD-COMMENT": "+ Agregar comentario", + "CREATE-CONFIRM": "Crear nueva tabla de decision", + "OPEN-IN-EDITOR": "Editor de tabla de decision", + "EXPORT": "Exportar tabla de decision", + "DELETE-CONFIRM": "Borrar tabla de decision", + "USE-AS-NEW-VERSION": "Usar como nueva version", + "FAVORITE": "Maracar como favorita esta tabla de decision", + "DUPLICATE": "Duplicar esta tabla de decision" + }, + "DETAILS": { + "HISTORY-TITLE": "Historial", + "COMMENTS-TITLE": "Comentarios", + "LAST-UPDATED-BY": "Ultimavez actualizado por {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Creado por {{createdBy}}" + }, + "HIT-POLICIES": { + "FIRST": "Primero (Single pass)", + "ANY": "Cualquiera (Single pass)" + }, + "POPUP": { + "CREATE-TITLE": "Crear nueva tabla de decision", + "CREATE-DESCRIPTION": "Es necesario dar un nombre par a la tabla de decision, es recomendable proporcionar una descripcion al mismo tiempo.", + "DUPLICATE-TITLE": "Duplicar tabla de decision", + "DUPLICATE-DESCRIPTION": "Puedes dar un nombre para la nueba tabla de decision es recomendable proporcionar una descripcion al mismo tiempo.", + "SAVE-DESCRIPTION": "Es necesario proporcionar un nombre y un identificador unico para la tabla de decision, es recomendable proporcionar una descripcion al mismo tiempo", + "DELETE-TITLE": "Borrar tabla de decision", + "DELETE-DESCRIPTION": "Estas Seguro que deseas borrar esta tabla de decision \"{{name}}\"?", + "SAVE-DECISION-TABLE-TITLE": "Guardar tabla de decision", + "IMPORT-DESCRIPTION": "Busca o arrastra una definicion DMN XML con una extension .dmn o .dmn.xml", + "IMPORT-TITLE": "Importar un modelo DMN", + "IMPORT": { + "DROPZONE": "Arrastra un archivo.dmn o .dmn.xml DMN XML", + "CANCEL-UPLOAD": "Cancelar la carga", + "ERROR": "Error cuando se procesaba el archivo DMN XML", + "NO-DROP": "Arrastrar y soltar no soportado" + }, + "USE-AS-NEW-TITLE": "Usar como nueva version", + "USE-AS-NEW-VERSION": "Usar como nueva version", + "USE-AS-NEW-DESCRIPTION": "Estas seguro que quieres utilizar la version {{version}} tpara crear una nueva version de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "No se pudo restaurar completamente a la version seleccionada: Algunos modelos referenciados fueron borrados. Por favor actualiza el modelo. Moodelos faltantes:", + "USE-AS-NEW-UNRESOLVED-MODEL": "Modelo '{{name}}' con identificador {{id}}, creado por {{createdBy}}" + }, + "ALERT": { + "FAVORITE-CONFIRM": "Esta tabla de decision es ahora favorita", + "UN-FAVORITE-CONFIRM": "Esta tabla de decision ya no es favorita" + } + }, + + "APP": { + "NAME": "Nombre de la App", + "KEY": "Identificador de la App", + "DESCRIPTION": "Descripcion", + "ICON": "Icono", + "THEME": "Tema", + "GROUPS-ACCESS": "Acceso a grupos, separado por comas", + "USERS-ACCESS": "Acceso a usuarios, separado por comas", + "ACTION": { + "DETAILS": "Mostrar detalles", + "EDIT": "Modificar propiedades de la App", + "DUPLICATE": "Duplicar esta App", + "SHARE": "Compartir esta App", + "DELETE": "Borrar esta App", + "CREATE-CONFIRM": "Crear nueva App", + "DUPLICATE-CONFIRM": "Duplicar App", + "DELETE-CONFIRM": "Borrar App", + "USE-AS-NEW-VERSION": "Usar como nueva version", + "OPEN-IN-EDITOR": "Editor de App", + "PUBLISH": "Publicar", + "PUBLISH-CONFIRM": "Publicar App", + "SELECT-ICON": "Cambiar icono...", + "SELECT-THEME": "Cambiar tema...", + "EDIT-MODELS": "Editar modelos incluidos", + "EXPORT-ZIP": "Exportar App como archivo zip", + "EXPORT-BAR": "Exportar App como archivo deployable bar" + + }, + "DETAILS": { + "TITLE": "Detalles de la App: {{name}}", + "HISTORY-TITLE": "Historial", + "MODELS-TITLE": "Modelos incluidos en la App", + "LAST-UPDATED-BY": "Ultima modificacion por {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Creado por {{createdBy}}", + "NO-DESCRIPTION": "Esta App no tiene descripcion. Modifica las propiedades de la App para agregar una", + "NO-MODELS-SELECTED": "No hay modelos seleccionados para esta App" + }, + "TITLE": { + "SELECT-ICON": "Seleccionar icono de la App", + "SELECT-THEME": "Seleccionar tema de la App", + "PREVIEW": "Vista previa" + + }, + "POPUP": { + "CREATE-TITLE": "Crear nueva App", + "DUPLICATE-TITLE": "Duplicar App", + "SAVE-APP-TITLE": "Guardar App", + "SAVE-APP-SAVE-SUCCESS": "App guardada", + "CREATE-DESCRIPTION": "Necesitas dar un nombre para la nueva App es recomendable proporcionar una descripcion al mismo tiempo", + "DUPLICATE-DESCRIPTION": "Puedes dar un nombre para la nueba App es recomendable proporcionar una descripcion al mismo tiempo", + "PUBLISH-TITLE": "Publicar App", + "PUBLISH-DESCRIPTION": "Estas seguro que deseas publicar la App \"{{name}}\"? Esta App sera versionada y actualizada en la App de workflow si ya existe.", + "PUBLISH-FIELD": "Publicar? Esta App sera versionada y actualizada en la App de workflow si ya existe.", + "PUBLISH-ERROR-PROCDEF-KEY-CONFLICT": "Tu modelo de proceso \"{{modelInAppName}}\" tiene el mismo identificador \"{{processDefinitionKey}}\" que el proceso existente deployado \"{{conflictingModelName}}\" de la App \"{{conflictingAppName}}\". Por favor cambia el \"id\" del modelo de proceso a algo diferente.", + "PUBLISH-ERROR-PROCESS-ALREADY-USED": "Los siguientes modelos de proceso ya son utilizados en otra App. Esto es correcto?", + "PUBLISH-ERROR-PROCESS-ALREADY-USED-APP": "App", + "PUBLISH-ERROR-PROCDEF-DUPLICATE-KEYS": "App invalida: se encontraron identificadores de proceso duplicados (cambia el \"id\" identificador de los procesos que tienen este detalle):", + "DELETE-TITLE": "Borrar App", + "DELETE-DESCRIPTION": "Estas seguro que deseas borrar la App \"{{name}}\"?", + "DELETE-DESCRIPTION-WITH-RUNTIME": "Estas seguro que deseas borrar la App \"{{name}}\"? Esta App se ha publicado en la vista de aplicaciones si confirmas, el acceso a la App sera removido.", + "DELETE-CASCADE-FALSE": "Borrar solo la version actual de la App (v{{version}})", + "DELETE-CASCADE-TRUE": "Borrar tambien las versiones anteriores de esta App", + "HAS-CUSTOM-STENCILITEM" : "Modelo \"{{modelName}}\" uses a stencil with custom stencil items. It is not possible to use this model in an App.", + "HAS-VALIDATIONERROR" : "Model \"{{modelName}}\" has validation errors and cannot be added to an App. Open the model in the editor to see more details about the validation error(s).", + "IMPORT-DESCRIPTION":"Por favor busca o arrastra una App con una extension .zip", + "IMPORT-TITLE":"Importar una App", + "IMPORT": { + "DROPZONE": "Arrastra un archivo de App .zip", + "CANCEL-UPLOAD": "Cancelar la carga", + "RENEWIDM-IDS": "Renueva los identificadores de grupo y de usuario cuando importes los modelos BPMN. Esto es comunmente requerido cuando importas la App en un ambiente de Flowable diferente. Se intentara ligar los pasos humanos y las tareas de usuario al usuario y grupo de usuarios correctos en este ambiente.", + "ERROR": "Error mientras se procesaba el archivo de la App", + "NO-DROP": "Arrastrar y soltar no soportado" + }, + "INCLUDE-MODELS-TITLE": "Modelos incluidos en la App" + }, + "ALERT": { + "DELETE-CONFIRM": "App Borrada", + "PUBLISH-CONFIRM": "La App ha sido publicada", + "PUBLISH-ERROR": "No se pude publicar la App. Por favor revisa que los modelos de proceso incluidos sean correctos" + } + }, + + "SHARE-INFO": { + "ACTION": { + "ADD": "Agregar otra persona" + } + }, + + "FORM-BUILDER": { + "PALLETTE": { + "TEXT": "Texto", + "PASSWORD": "Contraseña", + "MULTILINE-TEXT": "Texto en varias lineas", + "NUMBER": "Numero", + "CHECKBOX": "Checkbox", + "DATE": "Fecha", + "DROPDOWN": "Lista", + "RADIO": "Radio buttons", + "PEOPLE": "Personas", + "GROUP-OF-PEOPLE": "Grupo de personas", + "UPLOAD": "Upload", + "EXPRESSION": "Expresion", + "HYPERLINK": "Hipervínculo", + "SPACER": "Spacer", + "HORIZONTAL-LINE": "Horizontal line", + "HEADLINE": "Headline", + "HEADLINE-WITH-LINE":"Headline" + }, + "TABS": { + "GENERAL": "General", + "OPTIONS": "Opciones", + "UPLOAD-OPTIONS": "Opciones Upload", + "ADVANCED-OPTIONS":"Avanzado" + }, + "VERSION": "Version {{version}}", + "LAST-UPDATED": "Ultima vez actualizado por {{lastUpdatedBy}}, {{lastUpdated | dateformat}}", + "TITLE": { + "DESIGN": "Diseño", + "OUTCOME": "Resultado" + }, + "POPUP": { + "EDIT-TITLE": "Editar campo '{{name}}'", + "EXPRESSION-TITLE": "Editar expresion" + }, + "MESSAGE": { + "EMPTY-EXPRESSION": "(No expression value)", + "EXPRESSION-HELP": "Tambien puedes mostrar valores enviados anteriormente en cualquier formulario, como parte del texto, referenciandolo utilizando una notacion como la siguiente ${myFieldId}.", + "OPTIONS-EXPRESSION-HELP": "Puede usar una expresión para completar dinámicamente las opciones, por ejemplo, haciendo referencia a una variable como esta ${optionsVariable}. La expresión debe dar como resultado un objeto java (java.util.List con objetos Option) o su representación json." + }, + "LABEL" : { + "FUNCTIONAL-GROUP": "Selecciona el grupo..", + "PERSON": "Selecciona persona..." + }, + "COMPONENT": { + "LABEL": "Etiqueta:", + "OVERRIDEID": "Sobreescribir identificador?", + "ID": "Identificador:", + "PLACEHOLDER": "Placeholder:", + "OPTIONS": "Opciones", + "RADIO-BUTTON-DEFAULT": "Opcion 1", + "DROPDOWN-DEFAULT-EMPTY-SELECTION": "Por favor elige uno...", + "DROPDOWN-EMPTY-VALUE-HELP": "Este es la opcion 'valor vacio'. Seleccionar esto en tiempo de ejecucion es igual a 'no valor' o 'vacio'. Esto esta permitido para campos opcionales, pero no para campos requeridos.", + "OPTIONS-EXPRESSION": "Expresión de opciones:", + "OPTIONS-EXPRESSION-ENABLED": "Habilitar expresión de opciones", + "REQUIRED": "Requerido", + "EXPRESSION": "Expresion", + "ADD-OPTION": "+ Agregar nueva opcion", + "UPLOAD-ALLOW-MULTIPLE": "Permitir subir varios archivos", + "MAX-LENGTH":"Longitud máxima:", + "MIN-LENGTH":"Longitud mínima:", + "PASSWORD-UNMASK-OPTION": "Opción de enmascaramiento/desenmascaramiento de contraseña", + "HYPERLINK-URL": "URL hiperlink", + "REGEX-PATTERN":"Estándar Regex", + "MASK":{ + "TITLE":"Máscara de entrada", + "EXAMPLES":{ + "TITLE":"Ejemplos:", + "NUMBER":"Cualquier número", + "LETTER":"Cualquier letra", + "NUMBERORLETTER":"Cualquier letra o número", + "OPTIONAL":"La máscara opcional (no valida)", + "PHONE":"Teléfono" + } + } + }, + "OUTCOMES": { + "DESCRIPTION": "Puedes definir multiples resultados para esta tarea. Cuando se este completando la tarea, el usuario selecciona uno de los resultados disponibles, que pueden ser utilizados por ejemplo eg. una condicion utilizada mas adelante en el proceso.", + "NO-OUTCOMES-OPTION": "Don't use custom outcomes, only show a 'Complete' button.", + "OUTCOMES-OPTION": "Usar resultados propios para este formulario.", + "POSSIBLE-OUTCOMES": "Posibles resultados", + "NEW-OUTCOME-PLACEHOLDER": "Introduce un nuevo resultado", + "ADD": "Agregar resultado", + "REMOVE": "Eliminar" + } + }, + + "DECISION-TABLE-EDITOR": { + "EMPTY-MESSAGES": { + "NO-VARIABLE-SELECTED": "Indefinido" + }, + "POPUP": { + "EXPRESSION-EDITOR": { + "INPUT-TITLE": "Editar columna de entrada", + "INPUT-DESCRIPTION": "Seleccionar variable de entrada como ebtrada para la columna", + "OUTPUT-TITLE": "Editar columna de salida", + "OUTPUT-DESCRIPTION": "Selecionar una variable de salida existente o crear una nueva", + "EXPRESSION-LABEL": "Etiqueta de columna:", + "EXPRESSION-PLACEHOLDER": "Ingresar una etiqueta opcional", + "EXPRESSION-VARIABLE-NAME": "Nombre de variable:", + "EXPRESSION-VARIABLE-NAME-PLACEHOLDER": "Ingresar nombre de variable", + "OUTPUT-NEW-VARIABLE-ID": "Identificador de variable:", + "OUTPUT-NEW-VARIABLE-TYPE": "Tipo de variable:" + } + }, + "BUTTON-ADD-INPUT-LABEL": "Agregar entrada", + "BUTTON-ADD-OUTPUT-LABEL": "Agregar salida", + "BUTTON-ADD-RULE-LABEL": "Agregar regla", + "BUTTON-MOVE-RULE-UPWARDS-LABEL": "Mover arriba", + "BUTTON-MOVE-RULE-DOWNWARDS-LABEL": "Mover abajo", + "BUTTON-REMOVE-RULE-LABEL": "Eliminar regla", + "ALERT": { + "EXPRESSION-VARIABLE-REQUIRED-ERROR": "Todas las expresiones de entrada y salida deben referenciar un campo del formulario o una variable.", + "SAVE-CONFIRM": "Guardar tabla de decision '{{name}}'" + } + }, + + "TOUR": { + "WELCOME-TITLE": "Bienvenido, {{userName}}", + "WELCOME-CONTENT": "Esta es una pequeña guia del Editor Flowable. Los siguientes pasos te guiaran a traves de diferentes secciones de la aplicacion.Presion ESC para detener la guia en cualquier momento." , + "PALETTE-TITLE": "Barra de dibujo", + "PALETTE-CONTENT": "Todos los simbolos necesarios para crear un proceso de negocio pueden ser encontrados aqui. Se encuentran agrupados de manera logica. Para abrir un grupo simplemente da click en el:", + "CANVAS-TITLE": "El area de trabajo", + "CANVAS-CONTENT": "En este espacio crea tu proceso de negocio. Arrastra elementos desde la barra de dibujoe en la izquierda y sueltalos en esta area para empezar a modelar.", + "DRAGDROP-TITLE": "Ejemplo arrastrar y soltar", + "DRAGDROP-CONTENT": "aqui esta un ejemplo de como comenzar a modelar:", + "PROPERTIES-TITLE": "Propiedades", + "PROPERTIES-CONTENT": "Aqui puedes configurar las propuedades de un proceso de negocios. Simplemente selecciona un elemento en el area de trabajo y sus propiedades serán mostradas. Da click en la propiedad si deseas editarla", + "TOOLBAR-TITLE": "Barra de herramientas", + "TOOLBAR-CONTENT": "Todas las acciones pueden ser encontradas aqui: guardar o validar un modelo, copiar y pegar partes del proceso, y continua. Pasa sobre los botnones para ver lo que realizan.", + "END-TITLE": "Fin", + "END-CONTENT": "Ahora puedes modelar tus procesos. Si tienes alguna duda, sientete libre de preguntar en Flowable Forum " + }, + + "FEATURE-TOUR" : { + "BENDPOINT" : { + "TITLE": "Tutorial punto de curva", + "DESCRIPTION" : "Cuando estas conectando un elemento con otro usando un flujo de secuencia (Esas flechas entre los pasos del proceso), encontraras que esos flujos de secuencia se crean de manera automatica, si deseas modificar la direccione de las flechas, puedes agregar o eliminar un punto de curva de un flujo de secuencia.
Como se muestra debajo en la figura, primero das click en el boton 'Agregar punto curva'y despues das click en el flujo de secuencia al que deseas agregarlo. El fluo de secuencia te indicará con un punto en verde que el punto curva puede ser agregado.
Para eliminar un punto curva, click en 'eliminar punto curva' y da click en el flujo de secuencia del cual deseas eliminar." + } + }, + + "ACTION.OK" : "Ok", + "ACTION.SAVE" : "Guardar", + "ACTION.SAVE-AND-CLOSE" : "Guardar y cerrar el editor", + "ACTION.SEND" : "Enviar", + "ACTION.CANCEL" : "Cancelar", + "ACTION.SELECT" : "Seleccionar", + "ACTION.ADD" : "Agregar", + "ACTION.REMOVE" : "Eliminar", + "ACTION.MOVE.UP" : "Mover arriba", + "ACTION.MOVE.DOWN" : "Mover abajo", + + "TOOLBAR.ACTION.CLOSE" : "Cerrar el editor y volver a la pagina de previsualizacion", + "TOOLBAR.ACTION.SAVE" : "Guardar el modelo", + "TOOLBAR.ACTION.VALIDATE" : "Validar el modelo", + "TOOLBAR.ACTION.CUT" : "Cortar (seleciona uno o mas elementos en tu proceso de negocio)", + "TOOLBAR.ACTION.COPY" : "Copiar (seleciona uno o mas elementos en tu proceso de negocio)", + "TOOLBAR.ACTION.PASTE" : "Pegar", + "TOOLBAR.ACTION.DELETE" : "Borrar el elemento seleccionado", + "TOOLBAR.ACTION.UNDO" : "Deshacer", + "TOOLBAR.ACTION.REDO" : "Rehacer", + "TOOLBAR.ACTION.ZOOMIN" : "Zoom in", + "TOOLBAR.ACTION.ZOOMOUT" : "Zoom out", + "TOOLBAR.ACTION.ZOOMACTUAL" : "Zoom a tamaño actual", + "TOOLBAR.ACTION.ZOOMFIT" : "Zoom para ajustar", + "TOOLBAR.ACTION.BENDPOINT.ADD" : "Agregar punto de curva al flujo de secuencia seleccionado", + "TOOLBAR.ACTION.BENDPOINT.REMOVE" : "Eliminar punto de curva al flujo de secuencia seleccionado", + "TOOLBAR.ACTION.ALIGNHORIZONTAL" : "Alinear modelo horizontalmente", + "TOOLBAR.ACTION.ALIGNVERTICAL" : "Alinear modelo verticalmente", + "TOOLBAR.ACTION.SAMESIZE" : "Mismo tamaño", + "TOOLBAR.ACTION.HELP": "Iniciar la visita guiada", + "TOOLBAR.ACTION.FEEDBACK": "Proveer retroalimentacion", + + "FORM_TOOLBAR.ACTION.SAVE" : "Guardar el modelo", + + "APP_DEFINITION_TOOLBAR.ACTION.SAVE" : "Guardar la App", + + "BUTTON.ACTION.DELETE.TOOLTIP": "Borrar elemento del modelo", + "BUTTON.ACTION.MORPH.TOOLTIP": "Cambiar tipo del elemento", + + "ELEMENT.AUTHOR" : "Autor", + "ELEMENT.DATE_CREATED" : "Fecha de creacion", + + "PROPERTY.REMOVED" : "eliminado", + "PROPERTY.EMPTY" : "Sin valor", + "PROPERTY.PROPERTY.EDIT.TITLE" : "Cambiar valor por", + + "PROPERTY.FEEDBACK.TITLE" : "Por favor proporciona tu retroalimentacion", + + "PROPERTY.ASSIGNMENT.TITLE" : "Asignacion", + "PROPERTY.ASSIGNMENT.TYPE" : "Tipo", + "PROPERTY.ASSIGNMENT.TYPE.IDENTITYSTORE" : "Almacen de identidad", + "PROPERTY.ASSIGNMENT.TYPE.STATIC" : "Valores arreglados", + "PROPERTY.ASSIGNMENT.ASSIGNEE" : "Asignado", + "PROPERTY.ASSIGNMENT.MATCHING" : "Usa ↑ y ↓ para seleccionar y presiona Enter para confirmar o usa el mouse", + "PROPERTY.ASSIGNMENT.ASSIGNEE_PLACEHOLDER" : "Introduce un asignado", + "PROPERTY.ASSIGNMENT.EMPTY" : "No hay asignacion seleccionada", + "PROPERTY.ASSIGNMENT.NONE" : "Ninguno ...", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHUSER": "Buscar usuario", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHGROUP": "Buscar grupo", + "PROPERTY.ASSIGNMENT.SEARCH": "Buscar: ", + "PROPERTY.ASSIGNMENT.ASSIGNEE_DISPLAY" : "Assignado {{assignee}}", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY" : "{{length}} Usuarios candidatos", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS" : "Usuarios candidatos", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY" : "{{length}} Grupos candidatos", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS" : "Grupos candidatos", + "PROPERTY.ASSIGNMENT.USER_IDM_DISPLAY": "Usuario {{firstName}} {{lastName}}", + "PROPERTY.ASSIGNMENT.USER_IDM_EMAIL_DISPLAY": "Usuario {{email}}", + "PROPERTY.ASSIGNMENT.USER_IDM_FIELD_DISPLAY": "Campo {{name}}", + "PROPERTY.ASSIGNMENT.IDM_EMPTY" : "Iniciador del proceso", + "PROPERTY.ASSIGNMENT.IDM.TYPE" : "Asignacion", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_USERS" : "No hay usuarios candidatos seleccionados...", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_GROUPS" : "No hay grupos candidatos seleccionados...", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.INITIATOR" : "Asignar al iniciador del proceso", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USER" : "Asignar a un solo usuario", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USERS" : "Usuarios candidatos", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.GROUPS" : "Grupos candidatos", + "PROPERTY.ASSIGNMENT.INITIATOR-CAN-COMPLETE" : "Permitir al iniciador del proceso completar la tarea", + "PROPERTY.EXECUTIONLISTENERS.DISPLAY" : "{{length}} escuchadores de ejecucion", + "PROPERTY.EXECUTIONLISTENERS.EMPTY" : "No hay escuchadores de ejecucion configurados", + "PROPERTY.EXECUTIONLISTENERS.EVENT" : "Evento", + "PROPERTY.EXECUTIONLISTENERS.CLASS" : "Clase", + "PROPERTY.EXECUTIONLISTENERS.CLASS.PLACEHOLDER" : "Introduce un nombre de clase", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION" : "Expresion", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION.PLACEHOLDER" : "Introduce una expresion", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION" : "Expresion delegada", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Introduce una expresion delegada", + "PROPERTY.EXECUTIONLISTENERS.UNSELECTED" : "No hay escuchadores de ejecucion seleccionados", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME" : "Nombre", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME.PLACEHOLDER" : "Introduce un nombre", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION" : "Expresion", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Introduce una expresion", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE" : "Valor cadena", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Introduce una cadena", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING" : "Cadena", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING.PLACEHOLDER" : "Introduce una cadena", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.IMPLEMENTATION" : "Implementacion", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EMPTY" : "No hay un campo seleccionado", + + "PROPERTY.FIELDS" : "{{length}} campos", + "PROPERTY.FIELDS.EMPTY" : "No hay campos seleccionados", + "PROPERTY.FIELDS.NAME" : "Nombre", + "PROPERTY.FIELDS.NAME.PLACEHOLDER" : "Introduce un nombre", + "PROPERTY.FIELDS.EXPRESSION" : "Expresion", + "PROPERTY.FIELDS.EXPRESSION.PLACEHOLDER" : "Ingresa una expresion", + "PROPERTY.FIELDS.STRINGVALUE" : "Valor cadena", + "PROPERTY.FIELDS.STRINGVALUE.PLACEHOLDER" : "Introduce una cadena", + "PROPERTY.FIELDS.STRING" : "Cadena", + "PROPERTY.FIELDS.STRING.PLACEHOLDER" : "Introduce una cadena", + "PROPERTY.FIELDS.IMPLEMENTATION" : "Implementacion", + + "PROPERTY.FORMPROPERTIES.VALUE" : "{{length}} propiedades del formulario", + "PROPERTY.FORMPROPERTIES.EMPTY" : "No hay propiedades del formulario seleccionadas", + "PROPERTY.FORMPROPERTIES.ID" : "Identificador", + "PROPERTY.FORMPROPERTIES.ID.PLACEHOLDER" : "Introduce un identificador", + "PROPERTY.FORMPROPERTIES.NAME" : "Nombre", + "PROPERTY.FORMPROPERTIES.NAME.PLACEHOLDER" : "Introduce un nombre", + "PROPERTY.FORMPROPERTIES.TYPE" : "Tipo", + "PROPERTY.FORMPROPERTIES.DATEPATTERN" : "Patron de fecha", + "PROPERTY.FORMPROPERTIES.DATEPATTERN.PLACEHOLDER" : "Introduce un patron de fecha", + "PROPERTY.FORMPROPERTIES.VALUES" : "Valores", + "PROPERTY.FORMPROPERTIES.ENUMVALUES.EMPTY" : "Nose selecciono un valor enum", + "PROPERTY.FORMPROPERTIES.VALUES.ID" : "Identificador", + "PROPERTY.FORMPROPERTIES.VALUES.NAME" : "Nombre", + "PROPERTY.FORMPROPERTIES.VALUES.ID.PLACEHOLDER" : "Introdice el identificador del valor", + "PROPERTY.FORMPROPERTIES.VALUES.NAME.PLACEHOLDER" : "Introduce el nombre del valor", + "PROPERTY.FORMPROPERTIES.EXPRESSION" : "Expresion", + "PROPERTY.FORMPROPERTIES.EXPRESSION.PLACEHOLDER" : "Introduce una expresion", + "PROPERTY.FORMPROPERTIES.VARIABLE" : "Variable", + "PROPERTY.FORMPROPERTIES.VARIABLE.PLACEHOLDER" : "Introduce una variable", + "PROPERTY.FORMPROPERTIES.DEFAULT" : "default", + "PROPERTY.FORMPROPERTIES.DEFAULT.PLACEHOLDER" : "Introduce una default", + "PROPERTY.FORMPROPERTIES.REQUIRED" : "Requerido", + "PROPERTY.FORMPROPERTIES.READABLE" : "Leible", + "PROPERTY.FORMPROPERTIES.WRITABLE" : "Escribible", + + "PROPERTY.INPARAMETERS.VALUE" : "{{length}} parametros de entrada", + "PROPERTY.INPARAMETERS.EMPTY" : "No hay parametros de entrada configurados", + + "PROPERTY.OUTPARAMETERS.VALUE" : "{{length}} parametros de salida", + "PROPERTY.OUTPARAMETERS.EMPTY" : "No hay parametros de salida configurados", + + "PROPERTY.PARAMETER.SOURCE" : "Fuente", + "PROPERTY.PARAMETER.SOURCE.PLACEHOLDER" : "Introduce una fuente", + "PROPERTY.PARAMETER.SOURCEEXPRESSION" : "Expresion de fuente", + "PROPERTY.PARAMETER.SOURCEEXPRESSION.PLACEHOLDER" : "Expresion de fuente", + "PROPERTY.PARAMETER.TARGET" : "Objetivo", + "PROPERTY.PARAMETER.TARGET.PLACEHOLDER" : "Introduce un objetivo", + "PROPERTY.PARAMETER.EMPTY" : "No hay parametro seleccionado", + + "PROPERTY.SUBPROCESSREFERENCE.EMPTY" : "No hay referencia seleccionada", + "PROPERTY.SUBPROCESSREFERENCE.TITLE" : "Referencia a subproceso colapsado", + "PROPERTY.SUBPROCESSREFERENCE.ERROR.SUBPROCESS" : "Ocurrio un error cargando subprocesos. Intenta mas tarde", + "PROPERTY.SUBPROCESSREFERENCE.SUBPROCESS.LOADING" : "Cargando subprocesos...", + "PROPERTY.SUBPROCESSREFERENCE.SUBPROCESS.EMPTY" : "Este folder no contiene subprocesos", + + "PROPERTY.FORMREFERENCE.EMPTY" : "No hay referencia seleccionada", + "PROPERTY.FORMREFERENCE.TITLE" : "Referencia a formulario", + "PROPERTY.FORMREFERENCE.DESCRIPTION" : "Referencia a formulario", + "PROPERTY.FORMREFERENCE.ERROR.FORM" : "Ocurrio un error cargando los formularios. Intenta mas tarde", + "PROPERTY.FORMREFERENCE.FORM.LOADING" : "Cargando formularios...", + "PROPERTY.FORMREFERENCE.FORM.EMPTY" : "Este folder no contiene formularios", + + "PROPERTY.TASKLISTENERS.VALUE" : "{{length}} escuchadores de tarea", + "PROPERTY.TASKLISTENERS.EMPTY" : "No hay escuchadores de tarea configurados", + "PROPERTY.TASKLISTENERS.EVENT" : "Evento", + "PROPERTY.TASKLISTENERS.CLASS" : "Clase", + "PROPERTY.TASKLISTENERS.CLASS.PLACEHOLDER" : "Introduce un nombre de clase", + "PROPERTY.TASKLISTENERS.EXPRESSION" : "Expresion", + "PROPERTY.TASKLISTENERS.EXPRESSION.PLACEHOLDER" : "Introduce una expresion", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION" : "Delegar expresion", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Introduce una expresion de delegado", + "PROPERTY.TASKLISTENERS.UNSELECTED" : "No hay escuchadores de tarea seleccionados", + "PROPERTY.TASKLISTENERS.FIELDS.NAME" : "Nombre", + "PROPERTY.TASKLISTENERS.FIELDS.NAME.PLACEHOLDER" : "Introduce un nombre", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION" : "Expresion", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Introduce una expresion", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE" : "Valor cadena", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Introduce una cadena", + "PROPERTY.TASKLISTENERS.FIELDS.STRING" : "Cadena", + "PROPERTY.TASKLISTENERS.FIELDS.STRING.PLACEHOLDER" : "Introduce una cadena", + "PROPERTY.TASKLISTENERS.FIELDS.IMPLEMENTATION" : "Implementacion", + "PROPERTY.TASKLISTENERS.FIELDS.EMPTY" : "No hay campo seleccionado", + + "PROPERTY.EVENTLISTENERS.DISPLAY" : "{{length}} escuchadores de evento", + "PROPERTY.EVENTLISTENERS.EMPTY" : "No hay esuchadores de evento seleecionados", + "PROPERTY.EVENTLISTENERS.EVENTS": "Eventos", + "PROPERTY.EVENTLISTENERS.RETHROW": "Relanzar evento?", + "PROPERTY.EVENTLISTENERS.CLASS" : "Clase", + "PROPERTY.EVENTLISTENERS.CLASS.PLACEHOLDER" : "Introduce un nombre de clase", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION" : "Expresion delegada", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Introduce una expresion de delegado", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE" : "Tipo de entidad", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE.PLACEHOLDER" : "Introduce un tipo de entidad", + "PROPERTY.EVENTLISTENERS.RETHROWTYPE": "Relanzar tipo de evento", + "PROPERTY.EVENTLISTENERS.ERRORCODE" : "Codigo de error", + "PROPERTY.EVENTLISTENERS.ERRORCODE.PLACEHOLDER" : "Introduce un codigo de error", + "PROPERTY.EVENTLISTENERS.MESSAGENAME" : "Nombre de mensaje", + "PROPERTY.EVENTLISTENERS.MESSAGENAME.PLACEHOLDER" : "Introduce un nombre de mensaje", + "PROPERTY.EVENTLISTENERS.SIGNALNAME" : "Nombre de señal", + "PROPERTY.EVENTLISTENERS.SIGNALNAME.PLACEHOLDER" : "Introduce un nombre de señal", + "PROPERTY.EVENTLISTENERS.UNSELECTED" : "No hay escuchador de evento seleccionado", + + "PROPERTY.PLANITEMLIFECYCLELISTENERS.VALUE" : "{{length}} lifecycle listeners", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EMPTY" : "No lifecycle listeners configured", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EVENT" : "Event", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.SOURCE_STATE" : "Source state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.TARGET_STATE" : "Target state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS" : "Class", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.UNSELECTED" : "No task listener selected", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME" : "Name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING" : "String", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.IMPLEMENTATION" : "Implementation", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EMPTY" : "No Field selected", + + "PROPERTY.SIGNALDEFINITIONS.DISPLAY" : "{{length}} definiciones de señal", + "PROPERTY.SIGNALDEFINITIONS.EMPTY" : "No hay definiciones de señal", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-GLOBAL": "Global", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-PROCESSINSTANCE": "Instancia de proceso", + "PROPERTY.SIGNALDEFINITIONS.ID" : "Identificador", + "PROPERTY.SIGNALDEFINITIONS.NAME" : "Nombre", + "PROPERTY.SIGNALDEFINITIONS.SCOPE" : "Alcance", + + "PROPERTY.MESSAGEDEFINITIONS.DISPLAY" : "{{length}} definiciones de mensaje", + "PROPERTY.MESSAGEDEFINITIONS.EMPTY" : "No hay definiciones de mensaje configuradas", + "PROPERTY.MESSAGEDEFINITIONS.ID" : "Identificador", + "PROPERTY.MESSAGEDEFINITIONS.NAME" : "Nombre", + + "PROPERTY.SEQUENCEFLOW.ORDER.EMPTY" : "No se definio el orden de los flujos de secuencia", + "PROPERTY.SEQUENCEFLOW.ORDER.NOT.EMPTY" : "Orden de flujos de secuencia fijado", + "PROPERTY.SEQUENCEFLOW.ORDER.NO.OUTGOING.SEQUENCEFLOW.FOUND" : "No se encontro un flujo de secuencia de salida.", + "PROPERTY.SEQUENCEFLOW.ORDER.DESCRIPTION" : "Fijar el orden en el cual el flujo de secuencia necesita ser evaluado:", + "PROPERTY.SEQUENCEFLOW.ORDER.SEQUENCEFLOW.VALUE" : "Flujo de secuencia a {{targetType}} {{targetTitle}}", + + "PROPERTY.SEQUENCEFLOW.CONDITION.TITLE" : "Condicion del flujo de secuencia", + "PROPERTY.SEQUENCEFLOW.CONDITION.STATIC" : "Expresion de la condicion", + "PROPERTY.SEQUENCEFLOW.CONDITION.NO-CONDITION-DISPLAY": "No hay condicion fijada", + + "PROPERTY.DUEDATE.EMPTY" : "No se definio fecha de vencimiento", + "PROPERTY.DUEDATE.DEFINED" : "Se definio fecha de vencimiento", + "PROPERTY.DUEDATE.TITLE" : "Fecha de vencimiento", + "PROPERTY.DUEDATE.EXPRESSION-LABEL" : "Expression de fecha de vencimiento", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.NO-DUEDATE" : "No hay fecha de vencimiento", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.EXPRESSION" : "Definicion de expresion", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.STATIC" : "Duracion arreglada despues de la creacion de la tarea", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.FIELD" : "Basado en un campo", + + "MODEL.SAVE.TITLE" : "Guardar modelo", + "MODEL.VALIDATE.TITLE" : "Resultados de validacion", + "MODEL.NAME" : "Nombre", + "MODEL.KEY" : "Llave", + "MODEL.DESCRIPTION" : "Descripcion", + "MODEL.SAVE.NEWVERSION" : "Guardar como nueva version? Esto significa que siempre podras volver a una version anterior", + "MODEL.SAVE.COMMENT" : "Comentario", + "MODEL.SAVE.SAVING" : "Guardando modelo", + "MODEL.LASTMODIFIEDDATE" : "Ultimo guardado", + "MODEL.SAVE.ERROR": "Error inesperado: No se pudo guardar el modelo", + "MODEL.VALIDATIONERRORS": "El modelo tiene errores de validacion. El modelo no puede deployarse al Flowable Engine en el estado actual.", + "MODEL.CONFLICT.WRITE": "No se puede guardar el modelo: '{{userFullName}}' ha echo cambios a este modelo", + "MODEL.CONFLICT.WRITE.OPTIONS": "Selecciona una opcion para solucionar esto:", + "MODEL.CONFLICT.WRITE.OPTION.OVERWRITE": "Sobreescribir el otro modelo", + "MODEL.CONFLICT.WRITE.OPTION.DISCARDCHANGES": "Descartar mis cambios", + "MODEL.CONFLICT.WRITE.OPTION.SAVEAS": "Guardar como nuevo modelo", + "MODEL.CONFLICT.WRITE.OPTION.NEWVERSION": "Crrear una nueva version", + "MODEL.CONFLICT.SAVEAS" : "Guardar como:", + + "EVENT_TYPE.ACTIVITY.COMPENSATE.TOOLTIP": "Una actividad esta apunto de ser ejecutada como compensacion para otra actividad. Los eventos objetivo de la actividad que esta apunto de ser ejecutada para la compensacion", + "EVENT_TYPE.ACTIVITY.COMPLETED.TOOLTIP": "Una actividad se ha completado exitosamente", + "EVENT_TYPE.ACTIVITY.ERROR.RECEIVED.TOOLTIP": "Una actividad ha recibido un mensaje de error. Enviado antes que el actual error haya sido recibido por la actividad", + "EVENT_TYPE.MEMBERSHIP.CREATED.TOOLTIP": "Una nueva membresia ha sido creada", + "EVENT_TYPE.MEMBERSHIP.DELETED.TOOLTIP": "Una sola membresia ha sido borrada", + "EVENT_TYPE.MEMBERSHIPS.DELETED.TOOLTIP": "Todas las membresias relacionadas a un grupo han sido borradas. No se enviaran eventos individuales debido a razones de desempeño", + "EVENT_TYPE.TASK.ASSIGNED.TOOLTIP": "Una tarea se ha asignado. Se lanzo junto al evento ENTITY_UPDATED", + "EVENT_TYPE.TASK.COMPLETED.TOOLTIP": "Una tarea ha sido completada. Antes que la entidad sea borrada", + "EVENT_TYPE.UNCAUGHT.BPMNERROR.TOOLTIP": "Cuando un error BPMN fue lanzado, pero no fue atrapado dentro del proceso", + "EVENT_TYPE.VARIABLE.CREATED.TOOLTIP": "Una nueva variable se creo", + "EVENT_TYPE.VARIABLE.DELETED.TOOLTIP": "Una variable existente fue borrada", + "EVENT_TYPE.VARIABLE.UPDATED.TOOLTIP": "Una variable existente fue actualizada", + + "PROPERTY.DECISIONTABLEREFERENCE.EMPTY" : "No hay referencia selecionada", + "PROPERTY.DECISIONTABLEREFERENCE.TITLE" : "Tabla de decision referenciada", + "PROPERTY.DECISIONTABLEREFERENCE.ERROR.FORM" : "Ocurrio un error cargando la tabla de decisiones. Intenta mas tarde", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.LOADING" : "Cargando tabla de decisiones...", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.EMPTY" : "Este folder no contiene tablas de decisiones" +} diff --git a/snow-flowable/src/main/resources/static/i18n/fr.json b/snow-flowable/src/main/resources/static/i18n/fr.json new file mode 100644 index 0000000..7c5c5a0 --- /dev/null +++ b/snow-flowable/src/main/resources/static/i18n/fr.json @@ -0,0 +1,1006 @@ +{ + "GENERAL" : { + "MAIN-TITLE": "Flowable Editeur", + "NAVIGATION" : { + "PROCESSES": "Processus", + "CASEMODELS": "Modèle de cas", + "FORMS": "Formulaires", + "DECISION-TABLES": "Tables de décision", + "APPS": "Apps" + }, + "TITLE": { + "SELECT-GROUP" :"Sélectionner un groupe", + "MATCHING-GROUPS": "Groupes correspondants", + "FILTER": "Filtre", + "HISTORY": "Historique" + }, + "ACTION": { + "LOGOUT": "Déconnexion", + "RETURN-TO-LIST": "Afficher toutes les définitions", + "CANCEL": "Annuler", + "CLOSE": "Fermer", + "EDIT": "Editer", + "SAVE": "Sauver", + "OPEN": "Ouvrir", + "OK": "Ok", + "CONFIRM": "Confirmer", + "CONFIRM-AND-CLOSE": "Confirmer et fermer", + "NEW-FORM": "Nouveau formulaire", + "CREATE-FORM": "Créer un formulaire", + "NEW-DECISION-TABLE": "Nouvelle table de décision", + "CREATE-DECISION-TABLE": "Créer une table de décision" + }, + "MESSAGE": { + "SELECT-GROUP-HELP": "Utiliser ↑ et ↓ pour sélectionner et appuyer sur entrée pour confirmer ", + "PEOPLE-NO-MATCHING-RESULTS": "Aucun utilisateur correspondant n'a été trouvé", + "GROUP-NO-MATCHING-RESULTS": "Aucun groupe correspondant n'a été trouvé", + "GROUP-SOURCE-TYPE": "Groupe source", + "GROUP-SOURCE-SEARCH-OPTION": "Recherche de Groupe", + "GROUP-SOURCE-FIELD-OPTION": "Champ de formulaire" + } + }, + + "EDITOR": { + "POPUP": { + "UNSAVED-CHANGES": { + "TITLE": "Vous avez des modifications non enregistrées ", + "DESCRIPTION": "Que voulez vous faire des modifications non sauvegardées ?", + "ACTION": { + "SAVE": "Sauver", + "DISCARD": "Ignorer les changements", + "CONTINUE": "Continuer à éditer" + } + } + } + }, + + "PROCESS-LIST" : { + "TITLE" : "Modèles de processus métiers", + "SEARCH-PLACEHOLDER": "Rechercher", + "ACTION" : { + "CREATE": "Créer un processus", + "IMPORT": "Importer un processus" + }, + + "FILTER" : { + "PROCESSES": "Modèles de processus", + "PROCESSES-COUNT": "Il y a {{total}} modèles de processus", + "PROCESSES-ONE": "Il y a un modèle de processus", + "PROCESSES-EMPTY": "Il n'y a pas de modèle de processus encore créé. Vous pouvez créer des modèles de processus, des formulaires et les grouper au sein d'une application. La première étpage consiste à créer ce modèle de processus:", + "PROCESSES-BPMN-HINT": "Créer un modèle BPMN en utilisant l'Editeur visuel BPMN.", + "PROCESSES-BPMN-IMPORT-HINT": "Vous pouvez aussi importer des modèles BPMN existants.", + "FILTER-TEXT": ", correspondant à \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "Il n'y a pas de modèles de processus correspondant à \"{{filterText}}\"", + "RECENT": "Récent", + "RECENT-COUNT": "{{total}} modèles récemment utilisés", + "RECENT-ONE": "Un modèle récemment utilisé", + "RECENT-EMPTY": "Aucun modèle récemment utilisé" + }, + + "SORT": { + "MODIFIED-ASC": "Du plus vieux", + "MODIFIED-DESC": "Dernières modifications", + "NAME-ASC": "Nom, A-Z", + "NAME-DESC": "Nom, Z-A" + } + }, + + "CASE-LIST" : { + "TITLE" : "Modèles de Cas", + "SEARCH-PLACEHOLDER": "Recherche", + "ACTION" : { + "CREATE": "Créer un Cas", + "IMPORT": "Importer un Cas" + }, + + "FILTER" : { + "CASES": "Modèles de Cas", + "CASES-COUNT": "Il y a {{total}} modèles de Cas", + "CASES-ONE": "Il y a un modèle de Cas", + "CASES-EMPTY": "Aucun modèle de cas n'a encore été créé. Vous pouvez créer un modèle de cas, des formulaires et les grouper au sein d'une définition d'App. La première étape consiste à créer ce modèle de Cas:", + "CASES-CMMN-HINT": "Créer un modèle CMMN en utilisant l'éditeur visuel CMMN.", + "CASES-CMMN-IMPORT-HINT": "Vous pouvez aussi importer un modèle CMMN existant.", + "FILTER-TEXT": ", correspondant à \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "Il n'y a pas de modèle de cas correspondant à \"{{filterText}}\"", + "RECENT": "Récent", + "RECENT-COUNT": "{{total}}modèles récemment utilisés", + "RECENT-ONE": "Un modèle récemment utilisé", + "RECENT-EMPTY": "Aucun modèle récemment utilisé" + }, + + "SORT": { + "MODIFIED-ASC": "Du plus vieux", + "MODIFIED-DESC": "Dernières modifications", + "NAME-ASC": "Nom, A-Z", + "NAME-DESC": "Nom, Z-A" + } + }, + + "FORMS-LIST" : { + "TITLE" : "Formulaires", + "SEARCH-PLACEHOLDER": "Recherche", + "ACTION" : { + "CREATE": "Créer un formulaire", + "CREATE-INLINE": "Créer un nouveau formulaire maintenant!", + "SHOW-MORE": "Voir plus..." + }, + + "FILTER" : { + "FORMS": "Formulaires", + "FORMS-COUNT": "Il y a {{total}} formulaires", + "FORMS-ONE": "Il y a un formulaire", + "FORMS-EMPTY": "Il n'y a pas formulaires. Pour en ajouter un, cliquer sur Créer formulaire.", + "FILTER-TEXT": ", correspondant \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "Il n'y a pas de formulaires correspondant à \"{{filterText}}\"" + }, + + "SORT": { + "MODIFIED-ASC": "Du plus vieux", + "MODIFIED-DESC": "Dernières modifications", + "NAME-ASC": "Nom, A-Z", + "NAME-DESC": "Nom, Z-A" + } + }, + + "DECISION-TABLES-LIST": { + "TITLE": "Tables de décision", + "SEARCH-PLACEHOLDER": "Recherche", + "ACTION": { + "CREATE": "Créer une table de décision", + "IMPORT": "Importer une table de décision", + "CREATE-INLINE": "Créer une nouvelle table de décision maintenant!", + "SHOW-MORE": "Voir plus..." + }, + + "FILTER": { + "DECISION-TABLES": "Table de décisions", + "DECISION-TABLES-COUNT": "Il y a {{total}} tables de décision", + "DECISION-TABLES-ONE": "Il y a une table de décision", + "DECISION-TABLES-EMPTY": "Il n'y a pas de table de décisions. Pour en ajouter une, cliquer sur Créer une table de décision.", + "FILTER-TEXT": ", correspondant \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "Il n'y a pas de table de décision correpondants à \"{{filterText}}\"" + }, + + "SORT": { + "MODIFIED-ASC": "Du plus vieux", + "MODIFIED-DESC": "Dernières modifications", + "NAME-ASC": "Nom, A-Z", + "NAME-DESC": "Nom, Z-A" + } + }, + + "APPS-LIST" : { + "TITLE" : "Définitions d'App", + "SEARCH-PLACEHOLDER": "Recherche", + "ACTION" : { + "CREATE": "Créer une App", + "IMPORT": "Importer une App", + "SHOW-MORE": "Voir plus..." + }, + + "FILTER" : { + "APPS": "Définitions d'App", + "APPS-COUNT": "Il y a {{total}} définitions d'App", + "APPS-ONE": "Il y a une définition d'App", + "APPS-EMPTY": "Il n'y a pas de définitions d'App. Pour en ajouter une, cliquer sur Créer une Définition d'App .", + "FILTER-TEXT": ", correspondant à \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "Il n'y a pas de définitions d'App correpondant à \"{{filterText}}\"", + + "NO-APPS": "Vous pouvez créer une définition d'App en publiant un paquet de modèles de processus.", + "NO-APPS-CALL-TO-ACTION": "Vous pouvez créer une définition d'App maintenant.", + "NO-APPS-NOTE": "N'oubliez pas de Publier quand vous êtes prêt à l'utiliser." + }, + + "SORT": { + "MODIFIED-ASC": "Du plus vieux", + "MODIFIED-DESC": "Dernières modifications", + "NAME-ASC": "Nom, A-Z", + "NAME-DESC": "Nom, Z-A" + } + }, + "PROCESS": { + "NAME": "Nom du Modèle", + "KEY": "Clé du Modèle", + "DESCRIPTION": "Description", + "VERSION-COMMENT": "Commentaire de version", + "ACTION": { + "DETAILS": "Voir les détails", + "EDIT": "Modifier les propriétés du modèle", + "DUPLICATE": "Dupliquer le modèle", + "EXPORT_BPMN20": "Exporter en BPMN 2.0", + "DELETE": "Supprimer le modèle", + "CREATE-CONFIRM": "Créer un nouveau modèle", + "DUPLICATE-CONFIRM": "Dupliquer le modèle", + "OPEN-IN-EDITOR": "Editeur Visuel", + "EDIT-CONFIRM": "Sauvegarder", + "DELETE-CONFIRM": "Supprimer le modèle de processus", + "USE-AS-NEW-VERSION": "Utiliser en tant que nouvelle version", + "FAVORITE": "Mettre en favori ce modèle" + + }, + "DETAILS": { + "HISTORY-TITLE": "Historique", + "LAST-UPDATED-BY": "Dernière modification par {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Créé par {{createdBy}}", + "NO-DESCRIPTION": "Ce modèle n'a pas de description. Modifier les propriétés du modèle pour en ajouter un." + }, + + "POPUP": { + "CREATE-TITLE": "Créer un nouveau modèle de processus métier", + "DUPLICATE-TITLE": "Dupliquer un modèle de processus métier", + "CREATE-DESCRIPTION": "Vous devez donner un nom à ce modèle et en même temps vous devriez en profiter pour ajouter une description. ", + "DUPLICATE-DESCRIPTION": "Vous pouvez changer le nom du nouveau modèle et en même temps vous devriez en profiter pour ajouter une description.", + "EDIT-DESCRIPTION": "Modifier les propriétés ci-dessous et ensuite appuyer sur Sauvegarder pour mettre à jour le modèle.", + "DELETE-DESCRIPTION": "Êtes-vous sûr de vouloir supprimer le modèle de processus \"{{name}}\"?", + "EDIT-TITLE":"Modifier les détails du modèle", + "DELETE-TITLE": "Supprimer le modèle", + "DELETE-LOADING-RELATIONS": "Vérification des usages du modèle...", + "DELETE-RELATIONS-DESCRIPTION-SINGLE": "Ce modèle ne peut être supprimé car un autre modèle l'utilise:", + "DELETE-RELATIONS-DESCRIPTION": "Ce modèle ne peut être supprimé car il est utilisé par d'autres modèles:", + "DELETE-PROCESS-RELATION": "Modèle de processus", + "DELETE-FORM-RELATION": "Modèle de formulaire", + "DELETE-APP-RELATION": "Modèle d'App", + "IMPORT-DESCRIPTION": "Veuillez naviguer vers ou déposer un fichier de défnition BPMN XML avec une extension en .bpmn ou .bpmn20.xml", + "IMPORT-TITLE": "Importer un modèle de processus", + "USE-AS-NEW-TITLE": "Utiliser en tant que nouvelle version", + "USE-AS-NEW-DESCRIPTION": "Êtes-vous sûr de vouloir utiliser la version {{version}} pour créer une nouvelle version de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "Impossibilité de restaurer le modèle d'App dans la version choisie: certains modèles référencés sont manquants car précédemment supprimés. Veuillez mettre à jour votre modèle d'App en conséquence. Modèles manquants:", + "USE-AS-NEW-UNRESOLVED-MODEL": "Modèle '{{name}}' avec un identifiant interne {{id}}, créé par {{createdBy}}", + "SHARED-WITH": "Partagé avec", + "PERMISSION": "Permission", + "ACTIONS": "Actions", + "IMPORT": { + "DROPZONE": "Déposer un fichier BPMN avec une extension en .bpmn ou .bpmn20.xml", + "CANCEL-UPLOAD": "Annuler l'envoi", + "ERROR": "Une erreur s'est produite lors du traitement du fichier BPMN XML", + "NO-DROP": "Glisser/déposer n'est pas supporté" + } + }, + "ALERT": { + "EDIT-CONFIRM": "Modèle mise à jour" + }, + "ERROR": { + "NOT-FOUND": "Le modèle demandé n'existe pas." + } + }, + + "SUBPROCESS": { + "NAME": "Nom du sous-processus", + "DESCRIPTION": "Description", + "ACTION": { + "CREATE-CONFIRM": "Créer un nouveau sous-processus" + }, + "POPUP": { + "CREATE-TITLE": "Créer un nouveau sous-processus", + "CREATE-DESCRIPTION": "Vous devez donner un nom au nouveau sous-processus et en même temps vous devriez ajouter une description." + } + }, + + "CASE": { + "NAME": "Nom du Modèle", + "KEY": "Clé du Modèle", + "DESCRIPTION": "Description", + "VERSION-COMMENT": "Commentaire de Version", + "ACTION": { + "DETAILS": "Voir les détails", + "EDIT": "Modifier les propriétés du modèle", + "DUPLICATE": "Dupliquer ce modèle", + "EXPORT_CMMN": "Exporter en CMMN 1.1", + "DELETE": "Supprimer ce modèle", + "CREATE-CONFIRM": "Créer un nouveau modèle", + "DUPLICATE-CONFIRM": "Dupliquer ce modèle", + "OPEN-IN-EDITOR": "Editeur Visuel", + "EDIT-CONFIRM": "Sauvegarder", + "DELETE-CONFIRM": "Supprimer ce modèle de Cas ", + "USE-AS-NEW-VERSION": "Utiliser en tant que nouvelle version", + "FAVORITE": "Mettre en favori ce modèle" + + }, + "DETAILS": { + "HISTORY-TITLE": "Historique", + "LAST-UPDATED-BY": "Dernière modification par {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Created by {{createdBy}}", + "NO-DESCRIPTION": "Ce modèle n'a pas de description. Modifier les propriétés du modèle pour en ajouter un." + }, + + "POPUP": { + "CREATE-TITLE": "Créer un nouveau modèle de Cas ", + "DUPLICATE-TITLE": "Dupliquer le modèle de Cas ", + "CREATE-DESCRIPTION": "Vous devez donner un nom au nouveau modèle et en même temps vous devriez ajouter une description.", + "DUPLICATE-DESCRIPTION": "Vous pouvez changer le nom du nouveau modèle et en même temps vous devriez en profiter pour ajouter une description.", + "EDIT-DESCRIPTION": "Modifier les propriétés ci-dessous du modèle et appuyez sur Sauvegarder pour mettre à jour le modèle.", + "DELETE-DESCRIPTION": "Êtes-vous sûr de want to supprimer the modèle de processus \"{{name}}\"?", + "EDIT-TITLE":"Edit modèle details", + "DELETE-TITLE": "Supprimer modèle", + "DELETE-LOADING-RELATIONS": "Checking modèle usage...", + "DELETE-RELATIONS-DESCRIPTION-SINGLE": "This modèle cannot be deleted, because another modèle is using it:", + "DELETE-RELATIONS-DESCRIPTION": "This modèle cannot be deleted, because it is used by other models:", + "DELETE-PROCESS-RELATION": "Cas modèle", + "DELETE-FORM-RELATION": "formulaire modèle", + "DELETE-APP-RELATION": "App modèle", + "IMPORT-DESCRIPTION": "Please browse for or drop a CMMN XML definition with an .cmmn or .cmmn.xml extension", + "IMPORT-TITLE": "Import a Cas modèle", + "USE-AS-NEW-TITLE": "Use as new version", + "USE-AS-NEW-DESCRIPTION": "Êtes-vous sûr de vouloir utiliser la version {{version}} afin de créer une nouvelle version de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "Impossibilité de restaurer le modèle à la version choisie: certains modèles référencés sont manquants car précédemment supprimés. Veuillez mettre à jour votre modèle d'App en conséquence. Modèles manquants:", + "USE-AS-NEW-UNRESOLVED-MODEL": "Modèle '{{name}}' avec l'identifiant interne {{id}}, créé par {{createdBy}}", + "SHARED-WITH": "Partagé avec", + "PERMISSION": "Permission", + "ACTIONS": "Actions", + "IMPORT": { + "DROPZONE": "Déposer un fichier CMMN XML avec une extension .cmmn ou .cmmn.xml ", + "CANCEL-UPLOAD": "Annuler l'envoi", + "ERROR": "Erreur durant le traitement du fichier CMMN XML ", + "NO-DROP": "Glisser/Déposer n'est pas supporté." + } + }, + "ALERT": { + "EDIT-CONFIRM": "Modèle mis à jour" + }, + "ERROR": { + "NOT-FOUND": "Le modèle demandé n'existe pas" + } + }, + + "FORM": { + "NAME": "Nom du formulaire", + "KEY": "Clé du formulaire", + "DESCRIPTION": "Description", + "ACTION": { + "DETAILS": "Afficher les détails", + "EDIT": "Modifier les propriétés du modèle", + "DELETE": "Supprimer le formulaire", + "CREATE-CONFIRM": "Créer un nouveau formulaire", + "DUPLICATE": "Dupliquer ce formulaire", + "DUPLICATE-CONFIRM": "Dupliquer le formulaire", + "OPEN-IN-EDITOR": "Editeur de formulaire", + "EDIT-CONFIRM": "Sauvegarder", + "DELETE-CONFIRM": "Supprimer le formulaire", + "USE-AS-NEW-VERSION": "Utiliser en tant que nouvelle version" + + }, + "DETAILS": { + "HISTORY-TITLE": "Historique", + "LAST-UPDATED-BY": "Dernière modification par {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Créé par {{createdBy}}" + }, + + "POPUP": { + "CREATE-TITLE": "Créer un nouveau formulaire", + "DUPLICATE-TITLE": "Dupliquer le formulaire", + "CREATE-DESCRIPTION": "Vous devez donner un nom au nouveau formulaire et en même temps vous devriez ajouter une description.", + "DUPLICATE-DESCRIPTION": "Vous devez donner un nom au nouveau formulaire et en même temps vous devriez ajouter une description.", + "SAVE-FORM-TITLE": "Sauvegarder le formulaire", + "EDIT-DESCRIPTION": "Modifier les propriétés ci-dessous du formulaire et ensuite appuyer sur Sauvegarder pour mettre à jour le formulaire", + "DELETE-DESCRIPTION": "Êtes-vous sûr de vouloir supprimer le formulaire \"{{name}}\"?", + "EDIT-TITLE":"Editer les détails du formulaire", + "DELETE-TITLE": "Supprimer le formulaire", + "USE-AS-NEW-TITLE": "Utiliser en tant que nouvelle version", + "USE-AS-NEW-VERSION": "Utiliser en tant que nouvelle version", + "USE-AS-NEW-DESCRIPTION": "Êtes-vous sûr d'utiliser la version {{version}} pour créer une nouvelle version de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "Impossibilité de restaurer le modèle à la version choisie: certains modèles référencés sont manquants car précédemment supprimés. Veuillez mettre à jour votre modèle d'App en conséquence. Modèles manquants:", + "USE-AS-NEW-UNRESOLVED-MODEL": "Modèle '{{name}}'avec l'identifiant interne {{id}}, créé par {{createdBy}}" + } + }, + + "DECISION-TABLE": { + "NAME": "Nom de la table de décision", + "KEY": "Clé de la table de décision", + "DESCRIPTION": "Description", + "VERSION-COMMENT": "Commentaire de Version", + "HIT-POLICY": "Hit Policy:", + "ACTION": { + "DETAILS": "Afficher les détails", + "EDIT": "Modifier les propriétés du modèle", + "SHARE": "Partager cette table de décision", + "DELETE": "Supprimer cette table de décision", + "ADD-COMMENT": "+ Ajouter un commentaire", + "CREATE-CONFIRM": "Créer une nouvelle table de décision", + "OPEN-IN-EDITOR": "Editeur de table de décision", + "EXPORT": "Exporter la table de décision", + "DELETE-CONFIRM": "Supprimer la table de décision", + "USE-AS-NEW-VERSION": "Utiliser en tant que nouvelle version", + "FAVORITE": "Mettre en favori cette table de décision", + "DUPLICATE": "Dupliquer cette table de décision" + }, + "DETAILS": { + "HISTORY-TITLE": "Historique", + "COMMENTS-TITLE": "Commentaires", + "LAST-UPDATED-BY": "Dernière modification par {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Créé par {{createdBy}}" + }, + "HIT-POLICIES": { + "FIRST": "Les premiers", + "ANY": "Tous", + "UNIQUE": "Unique", + "PRIORITY": "Priorité", + "RULE ORDER": "Ordre des règles", + "OUTPUT ORDER": "Ordre de résultats", + "COLLECT": "Collecte" + }, + "COLLECT-OPERATORS": { + "SUM": "Sum", + "MIN": "Min", + "MAX": "Max", + "COUNT": "Count" + }, + "POPUP": { + "CREATE-TITLE": "Créer une nouvelle table de décision", + "CREATE-DESCRIPTION": "Vous devez donner un nom à la nouvelle table de décision et en même temps vous devriez ajouter une description.", + "SAVE-DESCRIPTION": "Vous devez donner un nom à la nouvelle table de décision ainsi qu'une clé unique et en même temps vous devriez ajouter une description.", + "DUPLICATE-TITLE": "Dupliquer la table de décision", + "DUPLICATE-DESCRIPTION": "Vous devez donner un nom à la nouvelle table de décision et en même temps vous devriez ajouter une description.", + "DELETE-TITLE": "Supprimer la table de décision", + "DELETE-DESCRIPTION": "Êtes-vous sûr de vouloir supprimer la table de décision \"{{name}}\"?", + "SAVE-DECISION-TABLE-TITLE": "Sauvegarder la table de décision", + "IMPORT-DESCRIPTION": "Veuillez naviguer vers ou déposer un fichier de définition DMN XML avec une extension en .dmn ou .dmn.xml", + "IMPORT-TITLE": "Importer un modèle DMN ", + "IMPORT": { + "DROPZONE": "Déposer un fichier DMN XML avec une extension en a .dmn ou .dmn.xml", + "CANCEL-UPLOAD": "Annuler l'envoi", + "ERROR": "Erreurr lors du tratiement du fichier DMN XML", + "NO-DROP": "Glisser/Déposer n'est pas supporté." + }, + "USE-AS-NEW-TITLE": "Utiliser en tant que nouvelle version", + "USE-AS-NEW-VERSION": "Utiliser en tant que nouvelle version", + "USE-AS-NEW-DESCRIPTION": "Êtes-vous sûr de vouloir utiliser la version {{version}} pour créer une nouvelle version de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "Impossibilité de restaurer le modèle à la version choisie: certains modèles référencés sont manquants car précédemment supprimés. Veuillez mettre à jour votre modèle d'App en conséquence. Modèles manquants:", + "USE-AS-NEW-UNRESOLVED-MODEL": "Modèle '{{name}}' avec l'identifiant interne {{id}}, créé par {{createdBy}}" + }, + "ALERT": { + "FAVORITE-CONFIRM": "La table de décision est maintenant en favori", + "UN-FAVORITE-CONFIRM": "La table de décision n'est plus marqué en favori" + } + }, + + "APP": { + "NAME": "Nom de la définition d'App", + "KEY": "Clé de la définition d'App", + "DESCRIPTION": "Description", + "ICON": "Icône", + "THEME": "Thème", + "GROUPS-ACCESS": "Groupes avec accès, séparés par des virgules", + "USERS-ACCESS": "Utilisateurs avec access, séparés par des virgules", + "ACTION": { + "DETAILS": "Afficher les détails", + "EDIT": "Modifier les propriétés de la définition d'App", + "DUPLICATE": "Dupliquer la définition", + "SHARE": "Partagé la définition d'App", + "DELETE": "Supprimer la définition d'App", + "CREATE-CONFIRM": "Créer une nouvelle définition d'App", + "DUPLICATE-CONFIRM": "Dupliquer la définition d'App", + "DELETE-CONFIRM": "Supprimer la définition d'App", + "USE-AS-NEW-VERSION": "Utiliser en tant que nouvelle version", + "OPEN-IN-EDITOR": "Editeur d'App", + "PUBLISH": "Publier", + "PUBLISH-CONFIRM": "Publier la définition d'App", + "SELECT-ICON": "Changer l'icône...", + "SELECT-THEME": "Change le thème...", + "EDIT-MODELS": "Editer les modèles inclus", + "EXPORT-ZIP": "Exporter la définition d'App dans un fichier zip", + "EXPORT-BAR": "Exporter la définition d'App en tant que fichier bar deployable" + + }, + "DETAILS": { + "TITLE": "Détails de la définition d'App: {{name}}", + "HISTORY-TITLE": "Historique", + "MODELS-TITLE": "Modèles inclus dans la définition d'App", + "LAST-UPDATED-BY": "Dernière modification par {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Créé par {{createdBy}}", + "NO-DESCRIPTION": "La définition d'App n'a pas de description. Modifier les propriétés de la définition d'App pour en ajouter une", + "NO-MODELS-SELECTED": "Aucun modèle n'a été sélectionné pour cette App" + }, + "TITLE": { + "SELECT-ICON": "Choisir une icône d'App", + "SELECT-THEME": "Choisir des couleurs d'App", + "PREVIEW": "Prévisualiser" + + }, + "POPUP": { + "CREATE-TITLE": "Créer une nouvelle définition d'App", + "DUPLICATE-TITLE": "Dupliquer une définition d'App", + "SAVE-APP-TITLE": "Sauvegarder la définition d'App", + "SAVE-APP-SAVE-SUCCESS": "La définition d'App a été sauvé", + "CREATE-DESCRIPTION": "Vous devez donner un nom à la nouvelle définition d'App et en même temps vous devriez ajouter une description.", + "DUPLICATE-DESCRIPTION": "Vous devez donner un nom à la nouvelle définition d'App et en même temps vous devriez ajouter une description.", + "PUBLISH-TITLE": "Publier la définition d'App", + "PUBLISH-DESCRIPTION": "Êtes-vous sûr de vouloir publier la définition d'App \"{{name}}\"? A noter que cette définition d'App sera versionné et l'App de sera mise à jour s'il existe", + "PUBLISH-FIELD": "Publier? A noter que si la publication est activé,la définition d'App sera versionné et que l'App de workflow sera mis à jour s'il existe. .", + "PUBLISH-ERROR-PROCDEF-KEY-CONFLICT": "Votre modèle de processus \"{{modelInAppName}}\" a le même identifiant \"{{processDefinitionKey}}\" que le processus déjà déployé \"{{conflictingModelName}}\" de l'App \"{{conflictingAppName}}\". Veuillez changer la valeur de la propriété \"id\" du modèle de processus.", + "PUBLISH-ERROR-PROCESS-ALREADY-USED": "Les modèles de processus sont déjà utilisés dans d'autres applications. Est ce normal ?", + "PUBLISH-ERROR-PROCESS-ALREADY-USED-APP": "App", + "PUBLISH-ERROR-PROCDEF-DUPLICATE-KEYS": "App invalide: Duplication trouvé des identifians de processus (modifier la propriété \"id\" des modèles de processus mise en cause):", + "DELETE-TITLE": "Supprimer la définition d'App", + "DELETE-DESCRIPTION": "Êtes-vous sûr de vouloir supprimer la définition d'App \"{{name}}\"?", + "DELETE-DESCRIPTION-WITH-RUNTIME": "Êtes-vous sûr de vouloir supprimer la définition d'App \"{{name}}\"? A noter que la définition d'App a été déployé sur la page d'accueil des tâches et en confirmant l'App sera supprimé des pages d'accueil.", + "DELETE-CASCADE-FALSE": "Supprimer uniquement la version courante de la définition d'App (v{{version}})", + "DELETE-CASCADE-TRUE": "Supprimer aussi toutes les versions précédentes de la définition d'App", + "HAS-CUSTOM-STENCILITEM" : "Modèle \"{{modelName}}\" utilise un stencil avec des objets personnalisés de stencil. Il n'est pas possible d'utiliser ce modèle dans une définition d'App.", + "HAS-VALIDATIONERROR" : "Modèle \"{{modelName}}\" a des erreurs de validations et ne peut être ajouté à une définition d'App. Ouvrez le modèle dans l'éditeur and vérifier les détails des erreurs.", + "IMPORT-DESCRIPTION":"Veuillez naviguer ou déposer une définition d'App avec une extension en .zip", + "IMPORT-TITLE":"Importer un modèle de définition d'App ", + "IMPORT": { + "DROPZONE": "Déposer un fichier de définition d'App en .zip", + "CANCEL-UPLOAD": "Annuler l'envoi", + "RENEWIDM-IDS": "Renouveler les identifiants d'utilisateur et de groupe lors de l'importation de modèles d'étapes et BPMN. Ceci est souvent requis lors de l'importation de la définition d'application dans un environnement Flowable différent. Il essaiera de lier les étapes humaines et les tâches utilisateur au bon utilisateur et groupe dans cet environnement cible.", + "ERROR": "Une erreur s'est produite lors du traitement du fichier", + "NO-DROP": "Glisser/Déposer n'est pas supporté." + }, + "INCLUDE-MODELS-TITLE": "Modèles inclus dans la définition d'App" + }, + "ALERT": { + "DELETE-CONFIRM": "La définition d'App a été supprimé", + "PUBLISH-CONFIRM": "La définition d'App a été publié", + "PUBLISH-ERROR": "Impossible de publier la définition d'App. Veuillez vérifier la validité des références de modèles de processus" + } + }, + + "SHARE-INFO": { + "ACTION": { + "ADD": "Ajouter une autre personne" + } + }, + + "FORM-BUILDER": { + "PALLETTE": { + "TEXT": "Texte", + "MULTILINE-TEXT": "Texte Multiligne", + "PASSWORD": "Mot de passe", + "NUMBER": "Nombre", + "CHECKBOX": "Case à cocher", + "DATE": "Date", + "DROPDOWN": "Liste déroulante", + "RADIO": "Boutton radio", + "PEOPLE": "Personnes", + "GROUP-OF-PEOPLE": "Groupes de personnes", + "UPLOAD": "Téléchargement", + "EXPRESSION": "Expression", + "DECIMAL": "Décimal", + "HYPERLINK": "Lien Hypertexte", + "SPACER": "Spacer", + "HORIZONTAL-LINE": "Horizontal line", + "HEADLINE": "Headline", + "HEADLINE-WITH-LINE":"Headline" + }, + "TABS": { + "GENERAL": "Général", + "OPTIONS": "Options", + "UPLOAD-OPTIONS": "Options de téléchargement", + "ADVANCED-OPTIONS":"Avancé" + }, + "VERSION": "Version {{version}}", + "LAST-UPDATED": "Dernière modification par {{lastUpdatedBy}}, {{lastUpdated | dateformat}}", + "TITLE": { + "DESIGN": "Conception", + "OUTCOME": "Résultats" + }, + "POPUP": { + "EDIT-TITLE": "Editer le champ '{{name}}'", + "EXPRESSION-TITLE": "Editer l'expression" + }, + "MESSAGE": { + "EMPTY-EXPRESSION": "(Aucune valeur de l'expression)", + "EXPRESSION-HELP": "Vous pouvez également afficher les valeurs préalablement soumises dans tout formulaire, dans le cadre du texte, en utilisant une notation de référence comme ${myFieldId}.", + "OPTIONS-EXPRESSION-HELP": "Vous pouvez utiliser une expression pour remplir dynamiquement des options, par exemple en référençant une variable telle que ${optionsVariable}. L'expression doit aboutir à un objet java (java.util.List avec des objets Option) ou à sa représentation json." + }, + "LABEL" : { + "FUNCTIONAL-GROUP": "Sélectionner un groupe..", + "PERSON": "Sélectionner une personne.." + }, + "COMPONENT": { + "LABEL": "Libellé:", + "OVERRIDEID": "Surcharger l'identifiant?", + "ID": "Identifiant:", + "PLACEHOLDER": "Paramètre fictif:", + "OPTIONS": "Options", + "RADIO-BUTTON-DEFAULT": "Option 1", + "DROPDOWN-DEFAULT-EMPTY-SELECTION": "Veuillez en choisir un...", + "DROPDOWN-EMPTY-VALUE-HELP": "Ceci est l'option pour la 'valeur à vide'. Le sélectionner lors de l'utilisation signifie 'aucune valeur' ou 'vide'. Ceci est autorisé pour les champs optionnels mais pas pour les champs obligatoires.", + "OPTIONS-EXPRESSION": "Expression des options:", + "OPTIONS-EXPRESSION-ENABLED": "Activer l'expression des options", + "REQUIRED": "Requis", + "READONLY": "Lecture seul", + "EXPRESSION": "Expression", + "ADD-OPTION": "+ Ajouter une nouvelle option", + "UPLOAD-ALLOW-MULTIPLE": "Autoriser le téléchargement de plusieurs fichiers", + "SIZE": "Taille", + "MAX-LENGTH":"Longueur maximale:", + "MIN-LENGTH":"Longueur minimum:", + "PASSWORD-UNMASK-OPTION": "Option de masquage / démasquage de mot de passe", + "HYPERLINK-URL": "URL line hypertexte", + "REGEX-PATTERN":"Regex standard", + "MASK":{ + "TITLE":"Masque de saisie", + "EXAMPLES":{ + "TITLE":"Exemples:", + "NUMBER":"tous les nombres", + "LETTER":"toutes les lettres", + "NUMBERORLETTER":"N'importe quel nombre ou lettre", + "OPTIONAL":"Rendre le masque optionel (non valide)", + "PHONE":"Téléphone" + } + } + }, + "OUTCOMES": { + "DESCRIPTION": "Vous pouvez définir plusieurs résultats pour cette tâche. Une fois la tâche complété, les utilisateurs choisissent la variable de résultat qui pourra ensuite être utilisé en tant que tel dans le processus.", + "NO-OUTCOMES-OPTION": "Ne pas utiliser les résultats personnalisés, afficher uniquement le boutton 'Terminer'", + "OUTCOMES-OPTION": "Utiliser des résultats personnalisés pour ce formulaire.", + "POSSIBLE-OUTCOMES": "Résultats possibles", + "NEW-OUTCOME-PLACEHOLDER": "Entrer un nouveau résultat", + "ADD": "Ajouter un résultat", + "REMOVE": "Retirer" + } + }, + + "DECISION-TABLE-EDITOR": { + "EMPTY-MESSAGES": { + "NO-VARIABLE-SELECTED": "Indéfini" + }, + "POPUP": { + "EXPRESSION-EDITOR": { + "INPUT-TITLE": "Modifier la colonne d'entrée", + "INPUT-DESCRIPTION": "Sélectionnez la variable d'entrée comme entrée pour la colonne", + "OUTPUT-TITLE": "Modifier la colonne de sortiee", + "OUTPUT-DESCRIPTION": "Sélectionnez une variable de sortie existante ou créez une nouvelle", + "EXPRESSION-LABEL": "Libellé de colonne:", + "EXPRESSION-PLACEHOLDER": "Entrer un libellé optionnel", + "EXPRESSION-VARIABLE-NAME": "Nom de variable:", + "EXPRESSION-VARIABLE-TYPE": "Type de variable:", + "EXPRESSION-VARIABLE-NAME-PLACEHOLDER": "Entrer un nom de variable", + "OUTPUT-NEW-VARIABLE-ID": "Variable ID:", + "OUTPUT-NEW-VARIABLE-TYPE": "Type de variable:", + "COMPLEX-EXPRESSION-LABEL": "Expression complexe :", + "ALLOWED-VALUES": "Valeurs autorisées (optionel):", + "OUTPUT-VALUES": "Valeurs de résultats ", + "OUTPUT-VALUES-OPTIONAL": "(optionel):", + "OUTPUT-VALUES-NOT-OPTIONAL": "(drag rows for priority / output order):" + } + }, + "BUTTON-ACTIONS-LABEL": "Actions", + "BUTTON-ADD-INPUT-LABEL": "Ajouter une entrée", + "BUTTON-ADD-OUTPUT-LABEL": "Ajouter une sortie", + "BUTTON-ADD-RULE-LABEL": "Ajouter une règle", + "BUTTON-MOVE-RULE-UPWARDS-LABEL": "Déplacer vers le haut", + "BUTTON-MOVE-RULE-DOWNWARDS-LABEL": "Déplacer vers le bas", + "BUTTON-REMOVE-RULE-LABEL": "Retirer une règle", + "ALERT": { + "EXPRESSION-VARIABLE-REQUIRED-ERROR": "Toutes les expressions d'entrée et de sorties doivent référencer un champs de formulaire ou une variable.", + "SAVE-CONFIRM": "La table de décision '{{name}}' a été sauvegardée" + } + }, + + "TOUR": { + "WELCOME-TITLE": "Bienvenue, {{userName}}", + "WELCOME-CONTENT": "Ceci est une introduction à l'éditeur Flowable. Les prochaines étapes vous guideront dans les différentes sections de l'application pour vous aider à démarrer. Appuyez sur la touche ESC pour arrêter à tout moment." , + "PALETTE-TITLE": "La Palette", + "PALETTE-CONTENT": "Tous les éléments disponibles pour créer un processus métier peuvent être trouvées ici. Ils sont organisés dans des groupes logiques. Pour ouvrir un groupe, cliquez simplement dessus:", + "CANVAS-TITLE": "Le Canevas", + "CANVAS-CONTENT": "C'est l'espace de travail sur lequel vous créez votre processus métier. Faites glisser des éléments de la palette sur la gauche et déposez-les sur le canevas pour commencer la modélisation..", + "DRAGDROP-TITLE": "Exemple de glisser-déposer", + "DRAGDROP-CONTENT": "Voici un exemple de comment commencer avec la modélisation:", + "PROPERTIES-TITLE": "Propriétés", + "PROPERTIES-CONTENT": "Ici, vous pouvez configurer les propriétés des éléments constitutif de votre processus métier. Il suffit de sélectionner l'élément sur le canevas et ses propriétés seront affichées. Cliquez sur la propriété si vous souhaitez l'éditer", + "TOOLBAR-TITLE": "La Barre d'outils", + "TOOLBAR-CONTENT": "Toutes les actions peuvent être trouvées ici: sauvegarder ou valider un modèle, copier et coller des éléments d'un processus, etc. Survolez les boutons pour obtenir une description pour une action.", + "END-TITLE": "La Fin", + "END-CONTENT": "C'est tout! Vous pouvez maintenant commencer à modéliser vos processus. Si vous avez des questions, n'hésitez pas à les poser sur le Forum Flowable " + }, + + "FEATURE-TOUR" : { + "BENDPOINT" : { + "TITLE": "Tutorial sur les points de courbure", + "DESCRIPTION" : "Lorsque vous connectez les étapes d'un processus l'une à l'autre en utilisant le flux de séquence (les flèches entre les étapes d'un processus), vous pourriez constater que ces flux de séquence se croisent ou que vous souhaitez les répartir différemment. Pour ce faire, vous pouvez ajouter ou supprimer un point de courbure vers ou à partir d'un flux de séquence.

Comme indiqué ci-dessous dans l'image, cliquez d'abord sur 'Ajouter un point de courbure', puis cliquez sur un flux de séquence pour ajoutez-le. Notez que le flux de séquence vous montrera une indication subtile en vert pour montrer que le point de flexion peut être ajouté là.

La suppression d'un point de courbure suit à nouveau un motif similaire: cliquez sur le bouton 'supprimer le point de courbure' et cliquez sur le bouton courber le point pour le retirer à nouveau." + } + }, + + "ACTION.OK" : "Ok", + "ACTION.SAVE" : "Sauvegarder", + "ACTION.SAVE-AND-CLOSE" : "Sauvegarder et fermer l'éditeur", + "ACTION.SEND" : "Envoyer", + "ACTION.CANCEL" : "Annuler", + "ACTION.SELECT" : "Sélectionner", + "ACTION.ADD" : "Ajouter", + "ACTION.REMOVE" : "Retirer", + "ACTION.MOVE.UP" : "Déplacer l'entrée vers le haut", + "ACTION.MOVE.DOWN" : "Déplacer l'entrée vers le base", + + "TOOLBAR.ACTION.CLOSE" : "Fermer l'éditeur et revenir vers la page de vue d'ensemble", + "TOOLBAR.ACTION.SAVE" : "Sauvegarder le modèle", + "TOOLBAR.ACTION.VALIDATE" : "Valider le modèle", + "TOOLBAR.ACTION.CUT" : "Couper (sélectionner un ou plusieurs éléments dans votre processus métier)", + "TOOLBAR.ACTION.COPY" : "Copier (sélectionner un ou plusieurs éléments dans votre processus métier)", + "TOOLBAR.ACTION.PASTE" : "Coller", + "TOOLBAR.ACTION.DELETE" : "Supprimer l'élément sélectionné", + "TOOLBAR.ACTION.UNDO" : "Annuler", + "TOOLBAR.ACTION.REDO" : "Refaire", + "TOOLBAR.ACTION.ZOOMIN" : "Zoom avant", + "TOOLBAR.ACTION.ZOOMOUT" : "Zoom arrière", + "TOOLBAR.ACTION.ZOOMACTUAL" : "Zoom en taille réelle", + "TOOLBAR.ACTION.ZOOMFIT" : "Zoom pour s'adapter", + "TOOLBAR.ACTION.BENDPOINT.ADD" : "Ajouter un point de courbure sur le flux de séquence sélectionné", + "TOOLBAR.ACTION.BENDPOINT.REMOVE" : "Retirer un point de courbure sur le flux de séquence sélectionné", + "TOOLBAR.ACTION.ALIGNHORIZONTAL" : "Aligner le modèle horizontalement", + "TOOLBAR.ACTION.ALIGNVERTICAL" : "Aligner modèle verticalement", + "TOOLBAR.ACTION.SAMESIZE" : "Même taille", + "TOOLBAR.ACTION.HELP": "Démarrer la visite guidée", + "TOOLBAR.ACTION.FEEDBACK": "Faire un retour d'information", + + "FORM_TOOLBAR.ACTION.SAVE" : "Sauvegarder le modèle", + + "APP_DEFINITION_TOOLBAR.ACTION.SAVE" : "Sauvegarder la définition d'App", + + "BUTTON.ACTION.DELETE.TOOLTIP": "Supprimer un élément from the modèle", + "BUTTON.ACTION.MORPH.TOOLTIP": "Changer un type d'élément", + + "ELEMENT.AUTHOR" : "Auteur", + "ELEMENT.DATE_CREATED" : "Date de creation", + + "PROPERTY.REMOVED" : "supprimé", + "PROPERTY.EMPTY" : "Aucune valeur", + "PROPERTY.PROPERTY.EDIT.TITLE" : "Changer la valeur pour ", + + "PROPERTY.FEEDBACK.TITLE" : "Veuillez ajouter vos commentaires", + + "PROPERTY.ASSIGNMENT.TITLE" : "Tâche", + "PROPERTY.ASSIGNMENT.TYPE" : "Type", + "PROPERTY.ASSIGNMENT.TYPE.IDENTITYSTORE" : "Identity store", + "PROPERTY.ASSIGNMENT.TYPE.STATIC" : "Valeurs fixées", + "PROPERTY.ASSIGNMENT.ASSIGNEE" : "Personne assignée", + "PROPERTY.ASSIGNMENT.MATCHING" : "Utiliser ↑ et ↓ pour sélectionner et appuyer sur Entrée pour confirmer ou utiliser la souris", + "PROPERTY.ASSIGNMENT.ASSIGNEE_PLACEHOLDER" : "Choisir une personne assignée", + "PROPERTY.ASSIGNMENT.EMPTY" : "Aucune personne assignée sélectionné", + "PROPERTY.ASSIGNMENT.NONE" : "Aucune ...", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHUSER": "Recherche un utilisateur", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHGROUP": "Recherche un groupe", + "PROPERTY.ASSIGNMENT.SEARCH": "Recherche: ", + "PROPERTY.ASSIGNMENT.ASSIGNEE_DISPLAY" : "Personne assignée {{assignee}}", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY" : "{{length}} utilisateurs candidats", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS" : "Utilisateurs candidats", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY" : "{{length}} groupes candidats", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS" : "Groupes candidats", + "PROPERTY.ASSIGNMENT.USER_IDM_DISPLAY": "Utilisateur {{firstName}} {{lastName}}", + "PROPERTY.ASSIGNMENT.USER_IDM_EMAIL_DISPLAY": "Utilisateur {{email}}", + "PROPERTY.ASSIGNMENT.USER_IDM_FIELD_DISPLAY": "Champs {{name}}", + "PROPERTY.ASSIGNMENT.IDM_EMPTY" : "Initiateur de processus", + "PROPERTY.ASSIGNMENT.IDM.TYPE" : "Tâche", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_USERS" : "Aucun utilisateur candidat sélectionné...", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_GROUPS" : "Aucun groupe candidat sélectionné...", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.INITIATOR" : "Assigné à l'initiateur de processus", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USER" : "Assigné à un seul utilisateur", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USERS" : "Utilisateurs candidats", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.GROUPS" : "Groupes candidats", + "PROPERTY.ASSIGNMENT.INITIATOR-CAN-COMPLETE" : "Autoriser l'initiateur de processus à terminer la tâche", + "PROPERTY.EXECUTIONLISTENERS.DISPLAY" : "{{length}} execution listeners", + "PROPERTY.EXECUTIONLISTENERS.EMPTY" : "No execution listeners configured", + "PROPERTY.EXECUTIONLISTENERS.EVENT" : "Événement", + "PROPERTY.EXECUTIONLISTENERS.CLASS" : "Class", + "PROPERTY.EXECUTIONLISTENERS.CLASS.PLACEHOLDER" : "Entrer un classname", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION" : "Expression", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION.PLACEHOLDER" : "Entrer une expression", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Entrer une delegate expression", + "PROPERTY.EXECUTIONLISTENERS.UNSELECTED" : "Aucun execution listener sélectionné", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME" : "Nom", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME.PLACEHOLDER" : "Entrer un nom", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Entrer une expression", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE" : "valeur de chaîne", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Entrer une valeur de chaîne", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING" : "String", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING.PLACEHOLDER" : "Entrer une valeur de chaîne", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.IMPLEMENTATION" : "Implementation", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EMPTY" : "Aucun champ sélectionné", + + "PROPERTY.FIELDS" : "{{length}} champs", + "PROPERTY.FIELDS.EMPTY" : "Aucun champ sélectionné", + "PROPERTY.FIELDS.NAME" : "Nom", + "PROPERTY.FIELDS.NAME.PLACEHOLDER" : "Entrer un nom", + "PROPERTY.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.FIELDS.EXPRESSION.PLACEHOLDER" : "Entrer une expression", + "PROPERTY.FIELDS.STRINGVALUE" : "valeur de chaîne", + "PROPERTY.FIELDS.STRINGVALUE.PLACEHOLDER" : "Entrer a string value", + "PROPERTY.FIELDS.STRING" : "String", + "PROPERTY.FIELDS.STRING.PLACEHOLDER" : "Entrer a string", + "PROPERTY.FIELDS.IMPLEMENTATION" : "Implémentation", + + "PROPERTY.DATAPROPERTIES.VALUES" : "{{length}} data objects", + "PROPERTY.DATAPROPERTIES.EMPTY" : "Aucun objet de données configuré", + "PROPERTY.DATAPROPERTIES.ID" : "Id", + "PROPERTY.DATAPROPERTIES.ID.PLACEHOLDER" : "Entrer une id", + "PROPERTY.DATAPROPERTIES.NAME" : "Nom", + "PROPERTY.DATAPROPERTIES.NAME.PLACEHOLDER" : "Entrer a nom", + "PROPERTY.DATAPROPERTIES.TYPE" : "Type", + "PROPERTY.DATAPROPERTIES.VALUE.PLACEHOLDER" : "Entrer une value (optionnel)", + "PROPERTY.DATAPROPERTIES.VALUE" : "Valeur par défaut", + + "PROPERTY.FORMPROPERTIES.VALUE" : "{{length}} propriétés de formulaire", + "PROPERTY.FORMPROPERTIES.EMPTY" : "Aucune propriété du formulaire sélectionné", + "PROPERTY.FORMPROPERTIES.ID" : "Identifiant", + "PROPERTY.FORMPROPERTIES.ID.PLACEHOLDER" : "Entrer un identifiant", + "PROPERTY.FORMPROPERTIES.NAME" : "Nom", + "PROPERTY.FORMPROPERTIES.NAME.PLACEHOLDER" : "Entrer un nom", + "PROPERTY.FORMPROPERTIES.TYPE" : "Type", + "PROPERTY.FORMPROPERTIES.DATEPATTERN" : "Pattern de Date", + "PROPERTY.FORMPROPERTIES.DATEPATTERN.PLACEHOLDER" : "Entrer un Pattern de date", + "PROPERTY.FORMPROPERTIES.VALUES" : "Valeurs", + "PROPERTY.FORMPROPERTIES.ENUMVALUES.EMPTY" : "Aucune valeur d'énumération sélectionné", + "PROPERTY.FORMPROPERTIES.VALUES.ID" : "Identifiant", + "PROPERTY.FORMPROPERTIES.VALUES.NAME" : "Nom", + "PROPERTY.FORMPROPERTIES.VALUES.ID.PLACEHOLDER" : "Entrer un identifiant pour la valeur", + "PROPERTY.FORMPROPERTIES.VALUES.NAME.PLACEHOLDER" : "Entrer un nom pour la valeur", + "PROPERTY.FORMPROPERTIES.EXPRESSION" : "Expression", + "PROPERTY.FORMPROPERTIES.EXPRESSION.PLACEHOLDER" : "Entrer une expression", + "PROPERTY.FORMPROPERTIES.VARIABLE" : "Variable", + "PROPERTY.FORMPROPERTIES.VARIABLE.PLACEHOLDER" : "Entrer une variable", + "PROPERTY.FORMPROPERTIES.DEFAULT" : "default", + "PROPERTY.FORMPROPERTIES.DEFAULT.PLACEHOLDER" : "Entrer une default", + "PROPERTY.FORMPROPERTIES.REQUIRED" : "Requise", + "PROPERTY.FORMPROPERTIES.READABLE" : "Lecture", + "PROPERTY.FORMPROPERTIES.WRITABLE" : "Ecriture", + + "PROPERTY.INPARAMETERS.VALUE" : "{{length}} paramètres d'entrée", + "PROPERTY.INPARAMETERS.EMPTY" : "Aucun paramètres d'entrée configuré", + + "PROPERTY.OUTPARAMETERS.VALUE" : "{{length}} paramètres de sortie", + "PROPERTY.OUTPARAMETERS.EMPTY" : "No paramètres de sortie configuré", + + "PROPERTY.PARAMETER.SOURCE" : "Source", + "PROPERTY.PARAMETER.SOURCE.PLACEHOLDER" : "Entrer une source", + "PROPERTY.PARAMETER.SOURCEEXPRESSION" : "Expression de source", + "PROPERTY.PARAMETER.SOURCEEXPRESSION.PLACEHOLDER" : "Entrer une expression de source", + "PROPERTY.PARAMETER.TARGET" : "Cible (Target)", + "PROPERTY.PARAMETER.TARGET.PLACEHOLDER" : "Entrer une Cible", + "PROPERTY.PARAMETER.EMPTY" : "Aucun paramètre sélectionné", + + "PROPERTY.PROCESSREFERENCE.EMPTY" : "Aucune référence sélectionnée", + "PROPERTY.PROCESSREFERENCE.TITLE" : "Référence de processus", + "PROPERTY.PROCESSREFERENCE.ERROR.SUBPROCESS" : "Une erreur a été rencontré lors du chargement des processus. Veuillez réessayer ultérieurement", + "PROPERTY.PROCESSREFERENCE.PROCESS.LOADING" : "Chargement des processus...", + "PROPERTY.PROCESSREFERENCE.PROCESS.EMPTY" : "Ce répertoire ne contient pas de processus", + + "PROPERTY.FORMREFERENCE.EMPTY" : "Aucune reference sélectionnée", + "PROPERTY.FORMREFERENCE.TITLE" : "Référence de formulaire", + "PROPERTY.FORMREFERENCE.DESCRIPTION" : "Référence vers un formulaire", + "PROPERTY.FORMREFERENCE.ERROR.FORM" : "Une erreur a été rencontré lors du chargement des formulaires. Veuillez réessayer ultérieurement", + "PROPERTY.FORMREFERENCE.FORM.LOADING" : "Chargement des formulaires...", + "PROPERTY.FORMREFERENCE.FORM.EMPTY" : "Ce répertoire ne contient pas de formulaires", + + "PROPERTY.TASKLISTENERS.VALUE" : "{{length}} task listeners", + "PROPERTY.TASKLISTENERS.EMPTY" : "Aucun task listeners configuré", + "PROPERTY.TASKLISTENERS.EVENT" : "Événements", + "PROPERTY.TASKLISTENERS.CLASS" : "Class", + "PROPERTY.TASKLISTENERS.CLASS.PLACEHOLDER" : "Entrer un classname", + "PROPERTY.TASKLISTENERS.EXPRESSION" : "Expression", + "PROPERTY.TASKLISTENERS.EXPRESSION.PLACEHOLDER" : "Entrer une expression", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Entrer une delegate expression", + "PROPERTY.TASKLISTENERS.UNSELECTED" : "Aucun task listener sélectionné", + "PROPERTY.TASKLISTENERS.FIELDS.NAME" : "Nom", + "PROPERTY.TASKLISTENERS.FIELDS.NAME.PLACEHOLDER" : "Entrer un nom", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Entrer une expression", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE" : "valeur de chaîne", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Entrer une valeur de chaîne", + "PROPERTY.TASKLISTENERS.FIELDS.STRING" : "String", + "PROPERTY.TASKLISTENERS.FIELDS.STRING.PLACEHOLDER" : "Entrer a string", + "PROPERTY.TASKLISTENERS.FIELDS.IMPLEMENTATION" : "Implémentation", + "PROPERTY.TASKLISTENERS.FIELDS.EMPTY" : "Aucun champ sélectionné", + + "PROPERTY.EVENTLISTENERS.DISPLAY" : "{{length}} événement listeners", + "PROPERTY.EVENTLISTENERS.EMPTY" : "Aucun événement listeners configured", + "PROPERTY.EVENTLISTENERS.EVENTS": "Événements", + "PROPERTY.EVENTLISTENERS.RETHROW": "Renvoyer l'événement?", + "PROPERTY.EVENTLISTENERS.CLASS" : "Class", + "PROPERTY.EVENTLISTENERS.CLASS.PLACEHOLDER" : "Entrer un classname", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Entrer une delegate expression", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE" : "Type de l'entité", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE.PLACEHOLDER" : "Entrer le type de l'entité ", + "PROPERTY.EVENTLISTENERS.RETHROWTYPE": "Renvoyer le type d'événement", + "PROPERTY.EVENTLISTENERS.ERRORCODE" : "Code d'erreur", + "PROPERTY.EVENTLISTENERS.ERRORCODE.PLACEHOLDER" : "Entrer un code d'erreur ", + "PROPERTY.EVENTLISTENERS.MESSAGENAME" : "Nom du Message", + "PROPERTY.EVENTLISTENERS.MESSAGENAME.PLACEHOLDER" : "Entrer le nom du message", + "PROPERTY.EVENTLISTENERS.SIGNALNAME" : "Nom du Signal", + "PROPERTY.EVENTLISTENERS.SIGNALNAME.PLACEHOLDER" : "Entrer le nom du signal", + "PROPERTY.EVENTLISTENERS.UNSELECTED" : "Aucun événement listener sélectionné", + + "PROPERTY.PLANITEMLIFECYCLELISTENERS.VALUE" : "{{length}} lifecycle listeners", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EMPTY" : "No lifecycle listeners configured", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EVENT" : "Event", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.SOURCE_STATE" : "Source state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.TARGET_STATE" : "Target state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS" : "Class", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.UNSELECTED" : "No task listener selected", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME" : "Name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING" : "String", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.IMPLEMENTATION" : "Implementation", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EMPTY" : "No Field selected", + + "PROPERTY.SIGNALDEFINITIONS.DISPLAY" : "{{length}} définitions de signal", + "PROPERTY.SIGNALDEFINITIONS.EMPTY" : "Aucune définitions de signal configuré", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-GLOBAL": "Global", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-PROCESSINSTANCE": "Instance de processus ", + "PROPERTY.SIGNALDEFINITIONS.ID" : "Identifiant", + "PROPERTY.SIGNALDEFINITIONS.NAME" : "Nom", + "PROPERTY.SIGNALDEFINITIONS.SCOPE" : "Portée", + + "PROPERTY.MESSAGEDEFINITIONS.DISPLAY" : "{{length}} definitions de message", + "PROPERTY.MESSAGEDEFINITIONS.EMPTY" : "Aucune définitions de message configuré", + "PROPERTY.MESSAGEDEFINITIONS.ID" : "Identifiant", + "PROPERTY.MESSAGEDEFINITIONS.NAME" : "Nom", + + "PROPERTY.SEQUENCEFLOW.ORDER.EMPTY" : "Aucune ordre de flux de séquence défini", + "PROPERTY.SEQUENCEFLOW.ORDER.NOT.EMPTY" : "Ordre flux de séquence order défini", + "PROPERTY.SEQUENCEFLOW.ORDER.NO.OUTGOING.SEQUENCEFLOW.FOUND" : "Aucun flux de séquence sortant trouvé.", + "PROPERTY.SEQUENCEFLOW.ORDER.DESCRIPTION" : "Définir l'ordre dans lequel le flux de séquence doit être évalué:", + "PROPERTY.SEQUENCEFLOW.ORDER.SEQUENCEFLOW.VALUE" : "Flux de séquence vers {{targetType}} {{targetTitle}}", + + "PROPERTY.SEQUENCEFLOW.CONDITION.TITLE" : "condition du flux de séquence ", + "PROPERTY.SEQUENCEFLOW.CONDITION.STATIC" : "Condition expression", + "PROPERTY.SEQUENCEFLOW.CONDITION.NO-CONDITION-DISPLAY": "Aucune condition définie", + + "PROPERTY.DUEDATE.EMPTY" : "Aucune date d'échéance", + "PROPERTY.DUEDATE.DEFINED" : "Date d'échéance définie", + "PROPERTY.DUEDATE.TITLE" : "Date d'échéance", + "PROPERTY.DUEDATE.EXPRESSION-LABEL" : "Expression de la Date d'échéance ", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.NO-DUEDATE" : "Aucune date d'échéance", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.EXPRESSION" : "Définition de l'expression ", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.STATIC" : "Durée fixe après la création de la tâche", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.FIELD" : "Basé sur le champ", + + "MODEL.SAVE.TITLE" : "Sauvegarder le modèle", + "MODEL.VALIDATE.TITLE" : "Validation des résultats", + "MODEL.NAME" : "Nom", + "MODEL.KEY" : "Clé", + "MODEL.DESCRIPTION" : "Description", + "MODEL.SAVE.NEWVERSION" : "Sauvegarder ceci en tant que nouvelle version? Cela signifie que vous pouvez toujours revenir à une version précédente", + "MODEL.SAVE.COMMENT" : "Commentaire", + "MODEL.SAVE.SAVING" : "Sauvegarder du modèle", + "MODEL.LASTMODIFIEDDATE" : "Dernière sauvegarde", + "MODEL.SAVE.ERROR": "Erreur innatendue: impossible de sauvegarder le modèle", + "MODEL.VALIDATIONERRORS": "Notez que le modèle contient des erreurs de validation. Cela signifie que le modèle ne peut pas être déployé sur le Moteur Flowable dans son état actuel.", + "MODEL.CONFLICT.WRITE": "Impossible de sauvegarder le modèle: '{{userFullName}}' a éffectué des changements à ce modèle", + "MODEL.CONFLICT.WRITE.OPTIONS": "Sélectionner une option pour résoudre ce conflit:", + "MODEL.CONFLICT.WRITE.OPTION.OVERWRITE": "Surcharger l'autre modèle", + "MODEL.CONFLICT.WRITE.OPTION.DISCARDCHANGES": "Ignorer mes modifications", + "MODEL.CONFLICT.WRITE.OPTION.SAVEAS": "Sauvegarder en tant que nouveau modèle", + "MODEL.CONFLICT.WRITE.OPTION.NEWVERSION": "Créer une nouvelle version", + "MODEL.CONFLICT.SAVEAS" : "Sauvegarder en tant que:", + + "EVENT_TYPE.ACTIVITY.COMPENSATE.TOOLTIP": "Une activité est sur le point d'être exécutée en compensation d'une autre activité. L'événement cible l'activité qui va être exécutée par compensation", + "EVENT_TYPE.ACTIVITY.COMPLETED.TOOLTIP": "Une activité a été terminée avec succès", + "EVENT_TYPE.ACTIVITY.ERROR.RECEIVED.TOOLTIP": "Une activité a reçu un événement d'erreur. Expédié avant que l'erreur réelle n'ait été reçue par l'activité", + "EVENT_TYPE.MEMBERSHIP.CREATED.TOOLTIP": "Une nouvelle adhésion a été créée", + "EVENT_TYPE.MEMBERSHIP.DELETED.TOOLTIP": "Une seule adhésion a été supprimée", + "EVENT_TYPE.MEMBERSHIPS.DELETED.TOOLTIP": "Toutes les adhésions au groupe concerné ont été supprimées. Aucun évènement individuel ne sera envoyé pour des raisons de performances", + "EVENT_TYPE.TASK.ASSIGNED.TOOLTIP": "Une tâche a été assignée. Ceci est executé en même temps qu'un événement ENTITY_UPDATED", + "EVENT_TYPE.TASK.COMPLETED.TOOLTIP": "Une tâche a été effectuée. Déployé avant que l'entité de tâche ne soit supprimée", + "EVENT_TYPE.UNCAUGHT.BPMNERROR.TOOLTIP": "Lorsqu'une erreur BPMN a été lancée, mais elle n'a pas été prise dans le processus", + "EVENT_TYPE.VARIABLE.CREATED.TOOLTIP": "Une nouvelle variable a été créé", + "EVENT_TYPE.VARIABLE.DELETED.TOOLTIP": "Une variable existante a été supprimé", + "EVENT_TYPE.VARIABLE.UPDATED.TOOLTIP": "Une variable existante a été mis à jour", + + "PROPERTY.DECISIONTABLEREFERENCE.EMPTY" : "Aucune référence sélectionné", + "PROPERTY.DECISIONTABLEREFERENCE.TITLE" : "Référence de la table de décision", + "PROPERTY.DECISIONTABLEREFERENCE.ERROR.FORM" : "Une erreur s'est produite lors du chargement des tables de décision. Veuillez réessayer ultérieurement", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.LOADING" : "Chargement des tables de décision...", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.EMPTY" : "Ce répertoire ne contient pas de tables de décision", + + "PROPERTY.CASEREFERENCE.EMPTY" : "Aucune référence sélectionné", + "PROPERTY.CASEREFERENCE.TITLE" : "Réference du modèle de cas", + "PROPERTY.CASEREFERENCE.ERROR.FORM" : "Une erreur a été rencontré lors du chargement des modèles de cas. Veuillez réessayer ultérieurement", + "PROPERTY.CASEREFERENCE.CASE.LOADING" : "Chargement des modèles de cas...", + "PROPERTY.CASEREFERENCE.CASE.EMPTY" : "Ce répertoire ne contient pas de modèle de cas" +} diff --git a/snow-flowable/src/main/resources/static/i18n/pt-BR.json b/snow-flowable/src/main/resources/static/i18n/pt-BR.json new file mode 100644 index 0000000..e56587a --- /dev/null +++ b/snow-flowable/src/main/resources/static/i18n/pt-BR.json @@ -0,0 +1,816 @@ +{ + "GENERAL":{ + "MAIN-TITLE":"Editor Flowable", + "NAVIGATION":{ + "PROCESSES":"Processos", + "FORMS":"Formulários", + "DECISION-TABLES":"Tabelas de Decisão", + "APPS":"Aplicativos" + }, + "TITLE":{ + "SELECT-GROUP":"Selecionar grupo", + "MATCHING-GROUPS":"Grupos correspondentes", + "FILTER":"Filtro", + "HISTORY":"Histórico" + }, + "ACTION":{ + "LOGOUT":"Sair", + "RETURN-TO-LIST":"Mostrar todas as definições", + "CANCEL":"Cancelar", + "CLOSE":"Fechar", + "EDIT":"Editar", + "SAVE":"Salvar", + "OPEN":"Abrir", + "OK":"Ok", + "CONFIRM":"Confirmar", + "CONFIRM-AND-CLOSE":"Confirmar e fechar", + "NEW-FORM":"Novo formulário", + "CREATE-FORM":"Criar formulário", + "NEW-DECISION-TABLE":"Nova tabela de decisão", + "CREATE-DECISION-TABLE":"Criar tabela de decisão" + }, + "MESSAGE":{ + "SELECT-GROUP-HELP":"Use ↑ e ↓ para selecionar e pressione Enter para confirmar", + "PEOPLE-NO-MATCHING-RESULTS":"Nenhum usuário correspondente foi encontrado", + "GROUP-NO-MATCHING-RESULTS":"Nenhum grupo correspondente foi encontrado", + "GROUP-SOURCE-TYPE":"Grupo de origem", + "GROUP-SOURCE-SEARCH-OPTION":"Pesquisa por grupo", + "GROUP-SOURCE-FIELD-OPTION":"Campo de formulário" + } + }, + "EDITOR":{ + "POPUP":{ + "UNSAVED-CHANGES":{ + "TITLE":"Você tem alterações não salvas", + "DESCRIPTION":"O que deseja fazer com as suas alterações não salvas?", + "ACTION":{ + "SAVE":"Salvar as alterações", + "DISCARD":"Descartar as alterações", + "CONTINUE":"Continuar editando" + } + } + } + }, + "PROCESS-LIST":{ + "TITLE":"Modelo de processo de negócios", + "SEARCH-PLACEHOLDER":"Pesquisar", + "ACTION":{ + "CREATE":"Criar processo", + "IMPORT":"Importar processo" + }, + "FILTER":{ + "PROCESSES":"Modelos de processo", + "PROCESSES-COUNT":"Existem {{total}} modelos de processos", + "PROCESSES-ONE":"Há um modelo de processo", + "PROCESSES-EMPTY":"Não há modelo de processo criado ainda. Você pode projetar modelos de processos, formulários de usuário e então empacotá-los em um aplicativo de processo. O primeiro passo é criar um modelo de processo:", + "PROCESSES-BPMN-HINT":"Crie um modelo BPMN usando o Editor Visual de BPMN.", + "PROCESSES-BPMN-IMPORT-HINT":"Você também pode importar modelos BPMN existentes.", + "FILTER-TEXT":", correspondente a \"{{filterText}}\"", + "FILTER-TEXT-EMPTY":"Não há modelo de processo correspondente a \"{{filterText}}\"", + "RECENT":"Recente", + "RECENT-COUNT":"{{total}} modelos usados recentemente", + "RECENT-ONE":"Um modelo usado recentemente", + "RECENT-EMPTY":"Nenhum modelo usado recentemente" + }, + "SORT":{ + "MODIFIED-ASC":"Mais antigo", + "MODIFIED-DESC":"Modificado por último", + "NAME-ASC":"Nome, A-Z", + "NAME-DESC":"Nome, Z-A" + } + }, + "FORMS-LIST":{ + "TITLE":"Formulários", + "SEARCH-PLACEHOLDER":"Pesquisar", + "ACTION":{ + "CREATE":"Criar formulário", + "CREATE-INLINE":"Crie um novo formulário agora!", + "SHOW-MORE":"Mostrar mais..." + }, + "FILTER":{ + "FORMS":"Formulários", + "FORMS-COUNT":"Existem {{total}} formulários", + "FORMS-ONE":"Existe um formulário", + "FORMS-EMPTY":"Não existem formulários. Para adicionar um, clique em criar formulário.", + "FILTER-TEXT":", correspondente a \"{{filterText}}\"", + "FILTER-TEXT-EMPTY":"Não há formulário correspondente a \"{{filterText}}\"" + }, + "SORT":{ + "MODIFIED-ASC":"Mais antigo", + "MODIFIED-DESC":"Último Modificado", + "NAME-ASC":"Nome, A-Z", + "NAME-DESC":"Nome, Z-A" + } + }, + "DECISION-TABLES-LIST":{ + "TITLE":"Tabelas de Decisão", + "SEARCH-PLACEHOLDER":"Busca", + "ACTION":{ + "CREATE":"Criar Tabela de Decisão", + "IMPORT":"Importar tabela de decisão", + "CREATE-INLINE":"Criar uma nova tabela de decisão agora!", + "SHOW-MORE":"Mostrar mais..." + }, + "FILTER":{ + "DECISION-TABLES":"Tabelas de decisão", + "DECISION-TABLES-COUNT":"Existem {{total}} tabelas de decisão", + "DECISION-TABLES-ONE":"Há uma tabela de decisão", + "DECISION-TABLES-EMPTY":"Não há tabela de decisão. Para adicionar uma, clique em criar tabela de decisão.", + "FILTER-TEXT":", correspondente a \"{{filterText}}\"", + "FILTER-TEXT-EMPTY":"Não há tabela de decisão correspondente a \"{{filterText}}\"" + }, + "SORT":{ + "MODIFIED-ASC":"Mais antigo", + "MODIFIED-DESC":"Modificado por último", + "NAME-ASC":"Nome, A-Z", + "NAME-DESC":"Nome, Z-A" + } + }, + "APPS-LIST":{ + "TITLE":"Definições de Aplicativo", + "SEARCH-PLACEHOLDER":"Pesquisar", + "ACTION":{ + "CREATE":"Criar Aplicativo", + "IMPORT":"Importar aplicativo", + "SHOW-MORE":"Mostrar mais..." + }, + "FILTER":{ + "APPS":"Definições de Aplicativo", + "APPS-COUNT":"Existem {{total}} definições de aplicativos", + "APPS-ONE":"Há uma definição de aplicativo", + "APPS-EMPTY":"Não há definições de aplicativo. Para adicionar uma, clique em criar definição de Aplicativo.", + "FILTER-TEXT":", correspondente a \"{{filterText}}\"", + "FILTER-TEXT-EMPTY":"Não há definições de aplicativo correspondentes a \"{{filterText}}\"", + "NO-APPS":"Você pode criar uma definição de Aplicativo, através da publicação de um pacote de modelos de processo.", + "NO-APPS-CALL-TO-ACTION":"Você pode criar uma definição de Aplicativo agora.", + "NO-APPS-NOTE":"Lembre-se de publicá-lo quando você estiver pronto para usá-lo." + }, + "SORT":{ + "MODIFIED-ASC":"Mais antigo", + "MODIFIED-DESC":"Modificado por último", + "NAME-ASC":"Nome, A-Z", + "NAME-DESC":"Nome, Z-A" + } + }, + "PROCESS":{ + "NAME":"Nome do modelo", + "KEY":"Chave do modelo", + "DESCRIPTION":"Descrição", + "VERSION-COMMENT":"Comentários da versão", + "ACTION":{ + "DETAILS":"Mostrar detalhes", + "EDIT":"Modificar propriedades do modelo", + "DUPLICATE":"Duplicar este modelo", + "EXPORT_BPMN20":"Exportar para BPMN 2.0", + "DELETE":"Excluir este modelo", + "CREATE-CONFIRM":"Criar novo modelo", + "DUPLICATE-CONFIRM":"Duplique o modelo", + "OPEN-IN-EDITOR":"Editor Visual", + "EDIT-CONFIRM":"Salvar", + "DELETE-CONFIRM":"Excluir o modelo de processo", + "USE-AS-NEW-VERSION":"Usar como uma nova versão", + "FAVORITE":"Adicionar este modelo aos favoritos" + }, + "DETAILS":{ + "HISTORY-TITLE":"Histórico", + "LAST-UPDATED-BY":"Última atualização feita por {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY":"Criado por {{createdBy}}", + "NO-DESCRIPTION":"Este modelo não tem descrição. Modifique as propriedades do modelo para adicionar uma" + }, + "POPUP":{ + "CREATE-TITLE":"Criar um novo modelo de processo de negócio", + "DUPLICATE-TITLE":"Duplicar o modelo de processo de negócio", + "CREATE-DESCRIPTION":"Você precisa dar um nome para o novo modelo e você pode querer também adicionar uma descrição ao mesmo tempo.", + "DUPLICATE-DESCRIPTION":"Você pode alterar o nome para o novo modelo e você pode querer alterar a descrição ao mesmo tempo.", + "EDIT-DESCRIPTION":"Altere qualquer uma das propriedades modelo abaixo e em seguida pressione Salvar para atualizar o modelo.", + "DELETE-DESCRIPTION":"Tem certeza que deseja excluir o modelo de processo \"{{name}}\"?", + "EDIT-TITLE":"Editar detalhes do modelo", + "DELETE-TITLE":"Excluir o modelo", + "DELETE-LOADING-RELATIONS":"Verificar o uso de modelo...", + "DELETE-RELATIONS-DESCRIPTION-SINGLE":"Este modelo não pode ser excluído, porque o outro modelo está a usá-lo:", + "DELETE-RELATIONS-DESCRIPTION":"Este modelo não pode ser excluído, porque ele é usado por outros modelos:", + "DELETE-PROCESS-RELATION":"Modelos de processo", + "DELETE-FORM-RELATION":"Modelo de formulário", + "DELETE-APP-RELATION":"Modelo de aplicativo", + "IMPORT-DESCRIPTION":"Por favor, procure ou arraste e solte uma definição de BPMN XML com um arquivo .bpmn ou .bpmn20.xml", + "IMPORT-TITLE":"Importar um modelo de processo", + "USE-AS-NEW-TITLE":"Use como nova versão", + "USE-AS-NEW-DESCRIPTION":"Tem certeza que quer usar a versão {{version}} para criar uma nova versão de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR":"Não foi possível restaurar completamente o modelo de aplicativo para a versão escolhida: alguns modelos referenciados estão ausentes poque foram excluído no passado. Por favor, atualize o modelo de aplicativo em conformidade. Modelos faltantes:", + "USE-AS-NEW-UNRESOLVED-MODEL":"Modelo '{{name}}' com id interno {{id}}, criado por {{createdBy}}", + "SHARED-WITH":"Compartilhado com", + "PERMISSION":"Permissão", + "ACTIONS":"Ações", + "IMPORT":{ + "DROPZONE":"Arraste e solte um arquivo .bpmn ou bpmn20.xml", + "CANCEL-UPLOAD":"Cancelar o upload", + "ERROR":"Erro ao processar o arquivo XML BPMN", + "NO-DROP":"Arrastar e soltar não suportado" + } + }, + "ALERT":{ + "EDIT-CONFIRM":"Modelo atualizado" + }, + "ERROR":{ + "NOT-FOUND":"O modelo solicitado não existe" + } + }, + "SUBPROCESS":{ + "NAME":"Nome do subprocesso", + "DESCRIPTION":"Descrição", + "ACTION":{ + "CREATE-CONFIRM":"Criar novo subprocesso" + }, + "POPUP":{ + "CREATE-TITLE":"Criar um novo subprocesso", + "CREATE-DESCRIPTION":"Você precisa dar um nome para o novo subprocesso e você pode querer adicionar uma descrição ao mesmo tempo." + } + }, + "FORM":{ + "NAME":"Nome do formulário", + "KEY":"Chave do formulário", + "DESCRIPTION":"Descrição", + "ACTION":{ + "DETAILS":"Mostrar detalhes", + "EDIT":"Modificar propriedades do modelo", + "DELETE":"Excluir este formulário", + "CREATE-CONFIRM":"Criar novo formulário", + "DUPLICATE-CONFIRM":"Duplicar o formulário", + "OPEN-IN-EDITOR":"Editor de formulário", + "EDIT-CONFIRM":"Salvar", + "DELETE-CONFIRM":"Excluir Formulário", + "USE-AS-NEW-VERSION":"Usar como uma nova versão" + }, + "DETAILS":{ + "HISTORY-TITLE":"Histórico", + "LAST-UPDATED-BY":"Última atualização feita por {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY":"Criado por {{createdBy}}" + }, + "POPUP":{ + "CREATE-TITLE":"Criar novo formulário", + "DUPLICATE-TITLE":"Duplicar o formulário", + "CREATE-DESCRIPTION":"Você precisa dar um nome para o novo formulário e você pode querer adicionar uma descrição ao mesmo tempo.", + "DUPLICATE-DESCRIPTION":"Você precisa dar um nome para o novo formulário e você pode querer adicionar uma descrição ao mesmo tempo.", + "SAVE-FORM-TITLE":"Salvar formulário", + "EDIT-DESCRIPTION":"Altere qualquer uma das propriedades do formulário abaixo e em seguida pressione Salvar para atualizar o formulário.", + "DELETE-DESCRIPTION":"Tem certeza que deseja excluir o formulário \"{{name}}\"?", + "EDIT-TITLE":"Editar detalhes do formulário", + "DELETE-TITLE":"Excluir Formulário", + "USE-AS-NEW-TITLE":"Usar como uma nova versão", + "USE-AS-NEW-VERSION":"Usar como uma nova versão", + "USE-AS-NEW-DESCRIPTION":"Tem certeza que quer usar a versão {{version}} para criar uma nova versão de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR":"Não foi possível restaurar completamente o modelo de aplicativo para a versão escolhida: alguns modelos referenciados estão ausentes poque foram excluído no passado. Por favor, atualize o modelo de aplicativo em conformidade. Modelos faltantes:", + "USE-AS-NEW-UNRESOLVED-MODEL":"Modelo '{{name}}' com id interno {{id}}, criado por {{createdBy}}" + } + }, + "DECISION-TABLE":{ + "NAME":"Nome da tabela de decisão", + "KEY":"Chave de tabela de decisão", + "DESCRIPTION":"Descrição", + "VERSION-COMMENT":"Comentários da versão", + "HIT-POLICY":"Acertar política:", + "ACTION":{ + "DETAILS":"Mostrar detalhes", + "EDIT":"Modificar propriedades do modelo", + "SHARE":"Compartilhar esta tabela de decisão", + "DELETE":"Excluir esta tabela de decisão", + "ADD-COMMENT":"+ Adicionar comentário", + "CREATE-CONFIRM":"Criar nova tabela de decisão", + "OPEN-IN-EDITOR":"Editor de tabela de decisão", + "EXPORT":"Exportar tabela de decisão", + "DELETE-CONFIRM":"Excluir a tabela de decisão", + "USE-AS-NEW-VERSION":"Usar como uma nova versão", + "FAVORITE":"Adicionar esta tabela de decisão aos favoritos", + "DUPLICATE":"Duplicar esta tabela de decisão" + }, + "DETAILS":{ + "HISTORY-TITLE":"Histórico", + "COMMENTS-TITLE":"Comentários", + "LAST-UPDATED-BY":"Última atualização feita por {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY":"Criado por {{createdBy}}" + }, + "HIT-POLICIES":{ + "FIRST":"Primeiro (passagem única)", + "ANY":"Qualquer (passagem única)" + }, + "POPUP":{ + "CREATE-TITLE":"Criar uma nova tabela de decisão", + "CREATE-DESCRIPTION":"Você precisa dar um nome para a nova tabela de decisão, e você pode querer adicionar uma descrição ao mesmo tempo.", + "SAVE-DESCRIPTION":"Você precisa dar um nome e uma chave exclusiva para a nova tabela de decisão, e você pode querer adicionar uma descrição ao mesmo tempo.", + "DUPLICATE-TITLE":"Duplicar uma tabela de decisão", + "DUPLICATE-DESCRIPTION":"Você pode dar um nome para a tabela de decisão, e pode querer alterar a descrição ao mesmo tempo.", + "DELETE-TITLE":"Excluir a tabela de decisão", + "DELETE-DESCRIPTION":"Tem certeza que deseja excluir a tabela de decisão \"{{name}}\"?", + "SAVE-DECISION-TABLE-TITLE":"Salvar a tabela de decisão", + "IMPORT-DESCRIPTION":"Por favor, procure ou arraste e solte uma definição de DMN XML com uma extensão .dmn ou .dmn.xml", + "IMPORT-TITLE":"Importar um modelo DMN", + "IMPORT":{ + "DROPZONE":"Arraste e solte um arquivo DMN XML com extensão .dmn ou .dmn.xml", + "CANCEL-UPLOAD":"Cancelar o carregamento", + "ERROR":"Erro ao processar o arquivo XML DMN", + "NO-DROP":"Arrastar e soltar não suportado" + }, + "USE-AS-NEW-TITLE":"Usar como uma nova versão", + "USE-AS-NEW-VERSION":"Usar como uma nova versão", + "USE-AS-NEW-DESCRIPTION":"Tem certeza que quer usar a versão {{version}} para criar uma nova versão de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR":"Não foi possível restaurar completamente o modelo de aplicativo para a versão escolhida: alguns modelos referenciados estão ausentes poque foram excluído no passado. Por favor, atualize o modelo de aplicativo em conformidade. Modelos faltantes:", + "USE-AS-NEW-UNRESOLVED-MODEL":"Modelo '{{name}}' com id interno {{id}}, criado por {{createdBy}}" + }, + "ALERT":{ + "FAVORITE-CONFIRM":"Esta tabela de decisão agora está adicionada aos favoritos", + "UN-FAVORITE-CONFIRM":"Esta tabela de decisão já não está mais nos favoritos" + } + }, + "APP":{ + "NAME":"Nome de definição do Aplicativo", + "KEY":"Chave de definição do aplicativo", + "DESCRIPTION":"Descrição", + "ICON":"Ícone", + "THEME":"Tema", + "GROUPS-ACCESS":"Acesso de grupos, separado por vírgulas", + "USERS-ACCESS":"Acesso de usuários, separado por vírgulas", + "ACTION":{ + "DETAILS":"Mostrar detalhes", + "EDIT":"Modificar propriedades de definição do aplicativo", + "DUPLICATE":"Duplique esta aplicação", + "SHARE":"Compartilhar esta definição de aplicativo", + "DELETE":"Excluir esta definição de aplicativo", + "CREATE-CONFIRM":"Criar nova definição de aplicativo", + "DUPLICATE-CONFIRM":"Duplicar a definição de aplicativo", + "DELETE-CONFIRM":"Excluir a definição de aplicativo", + "USE-AS-NEW-VERSION":"Usar como uma nova versão", + "OPEN-IN-EDITOR":"Editor de Aplicativo", + "PUBLISH":"Publicar", + "PUBLISH-CONFIRM":"Publicar a definição de aplicativo", + "SELECT-ICON":"Mudar ícone...", + "SELECT-THEME":"Alterar tema...", + "EDIT-MODELS":"Editar modelos incluídos", + "EXPORT-ZIP":"Exportar definição de aplicativo como um arquivo zip", + "EXPORT-BAR":"Exportar definição de aplicativo como um arquivo de implantação bar" + }, + "DETAILS":{ + "TITLE":"Detalhes da definição do aplicativo: {{name}}", + "HISTORY-TITLE":"Histórico", + "MODELS-TITLE":"Modelos incluídos na definição do aplicativo", + "LAST-UPDATED-BY":"Última atualização feita por {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY":"Criado por {{createdBy}}", + "NO-DESCRIPTION":"Esta definição de aplicativo não tem descrição. Modifique as propriedades de definição do aplicativo para adicionar uma", + "NO-MODELS-SELECTED":"Não há modelos selecionados para este aplicativo" + }, + "TITLE":{ + "SELECT-ICON":"Selecione o ícone para o aplicativo", + "SELECT-THEME":"Selecione as cores para o aplicativo", + "PREVIEW":"Visualizar" + }, + "POPUP":{ + "CREATE-TITLE":"Criar uma nova definição de aplicativo", + "DUPLICATE-TITLE":"Duplicar uma definição de aplicativo", + "SAVE-APP-TITLE":"Salvar a definição de aplicativo", + "SAVE-APP-SAVE-SUCCESS":"Definição de aplicativo salva", + "CREATE-DESCRIPTION":"Você precisa dar um nome para a nova definição do aplicativo, e você pode querer também adicionar uma descrição ao mesmo tempo.", + "DUPLICATE-DESCRIPTION":"Você pode dar um nome para a nova definição de aplicativo, e pode querer alterar a descrição ao mesmo tempo.", + "PUBLISH-TITLE":"Publicar a definição de aplicativo", + "PUBLISH-DESCRIPTION":"Tem certeza que deseja publicar a definição do aplicativo \"{{name}}\"? Note que esta definição de aplicativo será versionada e o aplicativo de worflow será atualizado se existente.", + "PUBLISH-FIELD":"Publicar? Observe que, se a publicação estiver habilitado, esta definição de aplicativo será versionada e o aplicativo de workflow será atualizado se já existente.", + "PUBLISH-ERROR-PROCDEF-KEY-CONFLICT":"Seu modelo de processo \"{{modelInAppName}}\" tem o mesmo identificador de \"{{processDefinitionKey}}\" com o processo previamente implantado \"{{conflictingModelName}}\" do aplicativo \"{{conflictingAppName}}\". Por favor, altere a propriedade \"id\" do modelo de processo para algo diferente.", + "PUBLISH-ERROR-PROCESS-ALREADY-USED":"Os seguintes modelos de processos já são utilizados em outro aplicativo. Isto está correto?", + "PUBLISH-ERROR-PROCESS-ALREADY-USED-APP":"Aplicativo", + "PUBLISH-ERROR-PROCDEF-DUPLICATE-KEYS":"Aplicativo inválido: identificadores de processo duplicados foram encontrados (altere a propriedade de \"id\" dos modelos de processo com id duplicados):", + "DELETE-TITLE":"Excluir a definição de aplicativo", + "DELETE-DESCRIPTION":"Tem certeza que deseja excluir a definição do aplicativo \"{{name}}\"?", + "DELETE-DESCRIPTION-WITH-RUNTIME":"Tem certeza que deseja excluir a definição do aplicativo \"{{name}}\"? Note que esta definição de aplicativo foi implantada como uma tarefa de página inicial, o aplicativo será removido da página inicial.", + "DELETE-CASCADE-FALSE":"Somente apagar a versão atual desta definição de aplicativo (v{{version}})", + "DELETE-CASCADE-TRUE":"Também excluir todas as versões anteriores desta definição de aplicativo", + "HAS-CUSTOM-STENCILITEM":"O modelo \"{{modelName}}\" usa um estêncil com itens de estêncil personalizado. Não é possível usar este modelo em uma definição de aplicativo.", + "HAS-VALIDATIONERROR":"O modelo \"{{modelName}}\" tem erros de validação e não pode ser adicionado a uma definição de aplicativo. Abra o modelo no editor para ver mais detalhes sobre o(s) erro(s) de validação.", + "IMPORT-DESCRIPTION":"Por favor, procure ou arraste e solte uma definição de aplicativo com a extensão .zip", + "IMPORT-TITLE":"Importar um modelo de definição de aplicativo", + "IMPORT":{ + "DROPZONE":"Arraste e solte um arquivo de definição de aplicativo .zip", + "CANCEL-UPLOAD":"Cancelar o carregamento", + "RENEWIDM-IDS":"Renove os identificadores de usuário e grupo ao importar os passos e modelos BPMN. Isso é muitas vezes necessário ao importar a definição de aplicativo em um ambiente Flowable diferente. Isto vai tentar vincular o etapas humanas e tarefas de usuário para usuário e grupo correto no ambiente de destino.", + "ERROR":"Erro ao processar o arquivo de definição de aplicativo", + "NO-DROP":"Arrastar e soltar não suportado" + }, + "INCLUDE-MODELS-TITLE":"Modelos incluídos na definição do aplicativo" + }, + "ALERT":{ + "DELETE-CONFIRM":"Definição de Aplicativo excluída", + "PUBLISH-CONFIRM":"A definição de aplicativo foi publicada", + "PUBLISH-ERROR":"Não foi possível publicar a definição de aplicativo. Por favor, verifique a validade dos modelos de processos referenciados" + } + }, + "SHARE-INFO":{ + "ACTION":{ + "ADD":"Adicionar outra pessoa" + } + }, + "FORM-BUILDER":{ + "PALLETTE":{ + "TEXT":"Texto", + "PASSWORD": "Senha", + "MULTILINE-TEXT":"Texto de multilinhas", + "NUMBER":"Número", + "CHECKBOX":"Caixa de seleção", + "DATE":"Data", + "DROPDOWN":"Seleção simples", + "RADIO":"Botões de opção", + "PEOPLE":"Pessoas", + "GROUP-OF-PEOPLE":"Grupo de pessoas", + "UPLOAD":"Carregar", + "EXPRESSION":"Expressão", + "DECIMAL":"Decimal", + "HYPERLINK":"Hiperlink", + "SPACER": "Spacer", + "HORIZONTAL-LINE": "Horizontal line", + "HEADLINE": "Headline", + "HEADLINE-WITH-LINE":"Headline" + }, + "TABS":{ + "GENERAL":"Geral", + "OPTIONS":"Opções", + "UPLOAD-OPTIONS":"Opções de carregamento", + "ADVANCED-OPTIONS":"Avançado" + }, + "VERSION":"Versão {{version}}", + "LAST-UPDATED":"Última atualização feita por {{lastUpdatedBy}}, {{lastUpdated | dateformat}}", + "TITLE":{ + "DESIGN":"Desenho", + "OUTCOME":"Resultados" + }, + "POPUP":{ + "EDIT-TITLE":"Editar o campo '{{name}}'", + "EXPRESSION-TITLE":"Editar expressão" + }, + "MESSAGE":{ + "EMPTY-EXPRESSION":"(Nenhuma expressão)", + "EXPRESSION-HELP":"Você também pode exibir valores anteriormente apresentados sob qualquer formulário, como parte do texto, referenciando-os usando uma notação como segue ${myFieldId}.", + "OPTIONS-EXPRESSION-HELP": "Você pode usar uma expressão para preencher dinamicamente opções, por exemplo, fazendo referência a uma variável como esta ${optionsVariable}. A expressão precisa resultar em um objeto java (java.util.List com objetos Option) ou sua representação json." + }, + "LABEL":{ + "FUNCTIONAL-GROUP":"Selecione o grupo..", + "PERSON":"Selecione a pessoa.." + }, + "COMPONENT":{ + "LABEL":"Rótulo:", + "OVERRIDEID":"Substituir o id?", + "ID":"Id:", + "PLACEHOLDER":"Marcador:", + "OPTIONS":"Opções", + "RADIO-BUTTON-DEFAULT":"Opção 1", + "DROPDOWN-DEFAULT-EMPTY-SELECTION":"Por favor, escolha uma...", + "DROPDOWN-EMPTY-VALUE-HELP":"Esta é a opção 'valor vazio'. Selecionar isto em tempo de execução significa dizer 'sem valor' ou 'vazio'. Isto é permitido para campos opcionais, mas não permitido para campos obrigatórios.", + "OPTIONS-EXPRESSION": "Expressão de opções:", + "OPTIONS-EXPRESSION-ENABLED": "Ativar expressão de opções", + "REQUIRED":"Obrigatório", + "READONLY":"Somente leitura", + "EXPRESSION":"Expressão", + "ADD-OPTION":"+ Adicionar uma nova opção", + "UPLOAD-ALLOW-MULTIPLE":"Permitir o upload de vários arquivos", + "MAX-LENGTH":"Comprimento máximo:", + "MIN-LENGTH":"Comprimento mínimo:", + "PASSWORD-UNMASK-OPTION": "opção de mascaramento/desmascarar senha", + "HYPERLINK-URL": "URL de hiperlink", + "REGEX-PATTERN":"Padrão Regex", + "MASK":{ + "TITLE":"Máscara de entrada", + "EXAMPLES":{ + "TITLE":"Exemplos:", + "NUMBER":"Qualquer número", + "LETTER":"Qualquer letra", + "NUMBERORLETTER":"Qualquer letra ou número", + "OPTIONAL":"Torna a máscara opcional (não valida)", + "PHONE":"Dinheiro" + } + } + }, + "OUTCOMES":{ + "DESCRIPTION":"Você pode definir várias saídas para esta tarefa. Quando concluir uma tarefa, os usuários seleciona uma das saídas disponíveis, que podem ser usados em, por exemplo, em uma condição futura no processo.", + "NO-OUTCOMES-OPTION":"Não use as saídas personalizados, apenas mostre um botão 'Completar'.", + "OUTCOMES-OPTION":"Use saídas personalizados para este formulário.", + "POSSIBLE-OUTCOMES":"Saídas possíveis", + "NEW-OUTCOME-PLACEHOLDER":"Insira uma nova saída", + "ADD":"Adicionar saída", + "REMOVE":"Excluir" + } + }, + "DECISION-TABLE-EDITOR":{ + "EMPTY-MESSAGES":{ + "NO-VARIABLE-SELECTED":"Indefinido" + }, + "POPUP":{ + "EXPRESSION-EDITOR":{ + "INPUT-TITLE":"Editar a coluna de entrada", + "INPUT-DESCRIPTION":"Selecione a variável de entrada como entrada para a coluna", + "OUTPUT-TITLE":"Editar a coluna de saída", + "OUTPUT-DESCRIPTION":"Selecione uma variável de saída existente ou crie uma nova", + "EXPRESSION-LABEL":"Rótulo de coluna:", + "EXPRESSION-PLACEHOLDER":"Digite um rótulo opcional", + "EXPRESSION-VARIABLE-NAME":"Nome da variável:", + "EXPRESSION-VARIABLE-NAME-PLACEHOLDER":"Entre com um nome de variável", + "OUTPUT-NEW-VARIABLE-ID":"ID da variável:", + "OUTPUT-NEW-VARIABLE-TYPE":"Tipo da variável:" + } + }, + "BUTTON-ADD-INPUT-LABEL":"Adicionar entrada", + "BUTTON-ADD-OUTPUT-LABEL":"Adicionar saída", + "BUTTON-ADD-RULE-LABEL":"Adicionar regra", + "BUTTON-MOVE-RULE-UPWARDS-LABEL":"Mover para cima", + "BUTTON-MOVE-RULE-DOWNWARDS-LABEL":"Mover para baixo", + "BUTTON-REMOVE-RULE-LABEL":"Excluir Regra", + "ALERT":{ + "EXPRESSION-VARIABLE-REQUIRED-ERROR":"Todas as expressões de entrada e saídas devem fazer referência a uma variável ou o campo do formulário.", + "SAVE-CONFIRM":"Tabela de decisão '{{name}}' salva" + } + }, + "TOUR":{ + "WELCOME-TITLE":"Bem-vindo, {{userName}}", + "WELCOME-CONTENT":"Esta uma pequena turnê do editor Flowable. Os próximos passos irão guiá-lo através de diferentes seções do aplicativo. Pressione a tecla ESC para parar a turnê a qualquer momento.", + "PALETTE-TITLE":"A paleta", + "PALETTE-CONTENT":"Todas as construções disponíveis para criar um processo de negócios podem ser encontradas aqui. Elas estão organizadas em grupos lógicos. Para abrir um grupo simplesmente clicar nele:", + "CANVAS-TITLE":"O Canvas", + "CANVAS-CONTENT":"Este é o espaço de trabalho no qual você cria seu processo de negócios. Arraste os elementos da paleta da esquerda e solte-os sobre esta tela para iniciar a modelagem.", + "DRAGDROP-TITLE":"Exemplo de arrastar e soltar", + "DRAGDROP-CONTENT":"Aqui está um exemplo de como você deve iniciar com a modelagem:", + "PROPERTIES-TITLE":"Propriedades", + "PROPERTIES-CONTENT":"Aqui você pode configurar as propriedades de uma construção de processo de negócios. Basta selecionar o item na tela e suas propriedades serão mostradas. Clique na propriedade se você quiser editá-la", + "TOOLBAR-TITLE":"A barra de ferramentas", + "TOOLBAR-CONTENT":"Todas as ações podem ser encontradas aqui: salvar ou validar um modelo, copiar e colar partes de um processo e assim por diante. Passe o mouse sobre os botões para obter uma descrição de uma ação.", + "END-TITLE":"Fim", + "END-CONTENT":"É isso! Agora você pode começar a modelagem de seus processos. Se você tiver alguma dúvida, não hesite em perguntar em Fórum Flowable " + }, + "FEATURE-TOUR":{ + "BENDPOINT":{ + "TITLE":"Tutorial de ponto curva", + "DESCRIPTION":"Quando você estiver se conectando as etapas do processo com o as outras usando o fluxo de sequência (as setas entre as etapas do processo), você pode achar que esses fluxo de sequência se cruzam, ou gostaria de organizá-los de forma diferente. Para fazer isso, você pode adicionar ou remover um ponto de curva para/de um fluxo de sequência.

Como mostrado abaixo na foto, primeiro, clique o 'Adicionar ponto de curva' e, em seguida, clique em um fluxo de sequência para adicioná-lo. Observe que o fluxo de sequência irá mostrar-lhe uma indicação sutil em verde para mostrar o ponto de curva pode ser adicionado lá.

Remover um ponto de curva novo segue um padrão semelhante: clique no botão 'remover ponto de curva' e clique em ponto de curva para removê-lo novamente." + } + }, + "ACTION.OK":"Ok", + "ACTION.SAVE":"Salvar", + "ACTION.SAVE-AND-CLOSE":"Salve e feche o editor", + "ACTION.SEND":"Enviar", + "ACTION.CANCEL":"Cancelar", + "ACTION.SELECT":"Selecione", + "ACTION.ADD":"Adicionar", + "ACTION.REMOVE":"Excluir", + "ACTION.MOVE.UP":"Mover a entrada para cima", + "ACTION.MOVE.DOWN":"Mover a entrada para baixo", + "TOOLBAR.ACTION.CLOSE":"Fechar o editor e voltar para a página de visão geral", + "TOOLBAR.ACTION.SAVE":"Salvar o modelo", + "TOOLBAR.ACTION.VALIDATE":"Validar o modelo", + "TOOLBAR.ACTION.CUT":"Recortar (selecione um ou mais elementos em seu processo de negócios)", + "TOOLBAR.ACTION.COPY":"Copiar (selecione um ou mais elementos em seu processo de negócios)", + "TOOLBAR.ACTION.PASTE":"Colar", + "TOOLBAR.ACTION.DELETE":"Excluir o elemento selecionado", + "TOOLBAR.ACTION.UNDO":"Desfazer", + "TOOLBAR.ACTION.REDO":"Refazer", + "TOOLBAR.ACTION.ZOOMIN":"Aumentar Zoom", + "TOOLBAR.ACTION.ZOOMOUT":"Diminuir o zoom", + "TOOLBAR.ACTION.ZOOMACTUAL":"Voltar para o tamanho real", + "TOOLBAR.ACTION.ZOOMFIT":"Enquadrar", + "TOOLBAR.ACTION.BENDPOINT.ADD":"Adicionar ponto de curva ao fluxo de sequência selecionado", + "TOOLBAR.ACTION.BENDPOINT.REMOVE":"Remover ponto de curva do fluxo de sequência selecionado", + "TOOLBAR.ACTION.ALIGNHORIZONTAL":"Alinhar o modelo horizontalmente", + "TOOLBAR.ACTION.ALIGNVERTICAL":"Alinhar o modelo verticalmente", + "TOOLBAR.ACTION.SAMESIZE":"Mesmo tamanho", + "TOOLBAR.ACTION.HELP":"Iniciar uma visita guiada", + "TOOLBAR.ACTION.FEEDBACK":"Fornecer feedback", + "FORM_TOOLBAR.ACTION.SAVE":"Salvar o modelo", + "APP_DEFINITION_TOOLBAR.ACTION.SAVE":"Salvar a definição de aplicativo", + "BUTTON.ACTION.DELETE.TOOLTIP":"Excluir o elemento do modelo", + "BUTTON.ACTION.MORPH.TOOLTIP":"Alterar o tipo do elemento", + "ELEMENT.AUTHOR":"Autor", + "ELEMENT.DATE_CREATED":"Data de criação", + "PROPERTY.REMOVED":"removido", + "PROPERTY.EMPTY":"Nenhum valor", + "PROPERTY.PROPERTY.EDIT.TITLE":"Altere o valor para ", + "PROPERTY.FEEDBACK.TITLE":"Por favor, nos envie seu feedback", + "PROPERTY.ASSIGNMENT.TITLE":"Atribuição", + "PROPERTY.ASSIGNMENT.TYPE":"Tipo", + "PROPERTY.ASSIGNMENT.TYPE.IDENTITYSTORE":"Identidades", + "PROPERTY.ASSIGNMENT.TYPE.STATIC":"Valores fixos", + "PROPERTY.ASSIGNMENT.ASSIGNEE":"Responsável", + "PROPERTY.ASSIGNMENT.MATCHING":"Use ↑ e ↓ para selecionar e pressione Enter para confirmar ou use o mouse", + "PROPERTY.ASSIGNMENT.ASSIGNEE_PLACEHOLDER":"Insira um candidato", + "PROPERTY.ASSIGNMENT.EMPTY":"Nenhuma atribuição selecionada", + "PROPERTY.ASSIGNMENT.ASSIGNEE_DISPLAY":"Designado {{assignee}}", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY":"{{length}} Usuários candidatos", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS":"Usuários candidatos", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY":"{{length}} Grupos candidatos", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS":"Grupos de candidatos", + "PROPERTY.ASSIGNMENT.USER_IDM_DISPLAY":"Usuário {{firstName}} {{lastName}}", + "PROPERTY.ASSIGNMENT.USER_IDM_EMAIL_DISPLAY":"Usuário {{email}}", + "PROPERTY.ASSIGNMENT.USER_IDM_FIELD_DISPLAY":"Campo {{name}}", + "PROPERTY.ASSIGNMENT.IDM_EMPTY":"Iniciador do processo", + "PROPERTY.ASSIGNMENT.IDM.TYPE":"Atribuição", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_USERS":"Nenhum usuário candidato selecionado...", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_GROUPS":"Nenhum grupo candidato selecionados...", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.INITIATOR":"Atribuído ao iniciador do processo", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USER":"Atribuído a um único usuário", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USERS":"Usuários candidatos", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.GROUPS":"Grupos de candidatos", + "PROPERTY.ASSIGNMENT.INITIATOR-CAN-COMPLETE":"Permitir que o iniciador do processo complete a tarefa", + "PROPERTY.EXECUTIONLISTENERS.DISPLAY":"{{length}} ouvintes da execução", + "PROPERTY.EXECUTIONLISTENERS.EMPTY":"Nenhum ouvinte de execução configurado", + "PROPERTY.EXECUTIONLISTENERS.EVENT":"Evento", + "PROPERTY.EXECUTIONLISTENERS.CLASS":"Classe", + "PROPERTY.EXECUTIONLISTENERS.CLASS.PLACEHOLDER":"Digite um nome de classe", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION":"Expressão", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION.PLACEHOLDER":"Insira uma expressão", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION":"Expressão de atribuição", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER":"Insira uma expressão de atribuição", + "PROPERTY.EXECUTIONLISTENERS.UNSELECTED":"Nenhum ouvinte de execução selecionado", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME":"Nome", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME.PLACEHOLDER":"Digite um nome", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION":"Expressão", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER":"Insira uma expressão", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE":"Valor da string", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER":"Insira um valor da string", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING":"String", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING.PLACEHOLDER":"Entre com o texto", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.IMPLEMENTATION":"Implementação", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EMPTY":"Nenhum campo selecionado", + "PROPERTY.FIELDS":"{{length}} campos", + "PROPERTY.FIELDS.EMPTY":"Nenhum campo selecionado", + "PROPERTY.ASSIGNMENT.NONE" : "Nenhum...", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHUSER": "Pesquisar usuário", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHGROUP": "Pesquisar grupo", + "PROPERTY.ASSIGNMENT.SEARCH": "Pesquisa: ", + "PROPERTY.FIELDS.NAME":"Nome", + "PROPERTY.FIELDS.NAME.PLACEHOLDER":"Digite um nome", + "PROPERTY.FIELDS.EXPRESSION":"Expressão", + "PROPERTY.FIELDS.EXPRESSION.PLACEHOLDER":"Insira uma expressão", + "PROPERTY.FIELDS.STRINGVALUE":"Valor da string", + "PROPERTY.FIELDS.STRINGVALUE.PLACEHOLDER":"Insira um valor da string", + "PROPERTY.FIELDS.STRING":"String", + "PROPERTY.FIELDS.STRING.PLACEHOLDER":"Entre com o texto", + "PROPERTY.FIELDS.IMPLEMENTATION":"Implementação", + "PROPERTY.FORMPROPERTIES.VALUE":"{{length}} propriedades de formulário", + "PROPERTY.FORMPROPERTIES.EMPTY":"Não há propriedades de formulário selecionadas", + "PROPERTY.FORMPROPERTIES.ID":"Id", + "PROPERTY.FORMPROPERTIES.ID.PLACEHOLDER":"Entre com um id", + "PROPERTY.FORMPROPERTIES.NAME":"Nome", + "PROPERTY.FORMPROPERTIES.NAME.PLACEHOLDER":"Digite um nome", + "PROPERTY.FORMPROPERTIES.TYPE":"Tipo", + "PROPERTY.FORMPROPERTIES.DATEPATTERN":"Padrão de data", + "PROPERTY.FORMPROPERTIES.DATEPATTERN.PLACEHOLDER":"Digite um padrão de data", + "PROPERTY.FORMPROPERTIES.VALUES":"Valores", + "PROPERTY.FORMPROPERTIES.ENUMVALUES.EMPTY":"Nenhum valor válido (enum) foi selecionado", + "PROPERTY.FORMPROPERTIES.VALUES.ID":"Id", + "PROPERTY.FORMPROPERTIES.VALUES.NAME":"Nome", + "PROPERTY.FORMPROPERTIES.VALUES.ID.PLACEHOLDER":"Digite o id de um valor", + "PROPERTY.FORMPROPERTIES.VALUES.NAME.PLACEHOLDER":"Digite o nome do valor", + "PROPERTY.FORMPROPERTIES.EXPRESSION":"Expressão", + "PROPERTY.FORMPROPERTIES.EXPRESSION.PLACEHOLDER":"Insira uma expressão", + "PROPERTY.FORMPROPERTIES.VARIABLE":"Variável", + "PROPERTY.FORMPROPERTIES.VARIABLE.PLACEHOLDER":"Insira uma variável", + "PROPERTY.FORMPROPERTIES.DEFAULT" : "default", + "PROPERTY.FORMPROPERTIES.DEFAULT.PLACEHOLDER" : "Insira uma default", + "PROPERTY.FORMPROPERTIES.REQUIRED":"Obrigatório", + "PROPERTY.FORMPROPERTIES.READABLE":"Possibilita Leitura", + "PROPERTY.FORMPROPERTIES.WRITABLE":"Possibilita Escrita", + "PROPERTY.INPARAMETERS.VALUE":"{{length}} parâmetros de entrada", + "PROPERTY.INPARAMETERS.EMPTY":"Nenhum parâmetro de entrada configurado", + "PROPERTY.OUTPARAMETERS.VALUE":"{{length}} parâmetros de saída", + "PROPERTY.OUTPARAMETERS.EMPTY":"Nenhum parâmetro de saída configurado", + "PROPERTY.PARAMETER.SOURCE":"Origem", + "PROPERTY.PARAMETER.SOURCE.PLACEHOLDER":"Insira uma origem", + "PROPERTY.PARAMETER.SOURCEEXPRESSION":"Expressão de origem", + "PROPERTY.PARAMETER.SOURCEEXPRESSION.PLACEHOLDER":"Insira uma expressão de origem", + "PROPERTY.PARAMETER.TARGET":"Destino", + "PROPERTY.PARAMETER.TARGET.PLACEHOLDER":"Insira um destino", + "PROPERTY.PARAMETER.EMPTY":"Nenhum parâmetro selecionado", + "PROPERTY.SUBPROCESSREFERENCE.EMPTY":"Nenhuma referência selecionada", + "PROPERTY.SUBPROCESSREFERENCE.TITLE":"Referência de subprocesso recolhida", + "PROPERTY.SUBPROCESSREFERENCE.ERROR.SUBPROCESS":"Houve um erro ao carregar os subprocessos. Tente novamente mais tarde", + "PROPERTY.SUBPROCESSREFERENCE.SUBPROCESS.LOADING":"Carregando subprocessos...", + "PROPERTY.SUBPROCESSREFERENCE.SUBPROCESS.EMPTY":"Esta pasta não contém subprocessos", + "PROPERTY.FORMREFERENCE.EMPTY":"Nenhuma referência selecionada", + "PROPERTY.FORMREFERENCE.TITLE":"Formulário de referência", + "PROPERTY.FORMREFERENCE.DESCRIPTION":"Referência a um formulário", + "PROPERTY.FORMREFERENCE.ERROR.FORM":"Houve um erro ao carregar o formulário. Tente novamente mais tarde", + "PROPERTY.FORMREFERENCE.FORM.LOADING":"Carregando formulários...", + "PROPERTY.FORMREFERENCE.FORM.EMPTY":"Esta pasta não contém formulários", + "PROPERTY.TASKLISTENERS.VALUE":"{{length}} ouvintes de tarefa", + "PROPERTY.TASKLISTENERS.EMPTY":"Nenhum ouvintes tarefa configurado", + "PROPERTY.TASKLISTENERS.EVENT":"Evento", + "PROPERTY.TASKLISTENERS.CLASS":"Classe", + "PROPERTY.TASKLISTENERS.CLASS.PLACEHOLDER":"Digite um nome de classe", + "PROPERTY.TASKLISTENERS.EXPRESSION":"Expressão", + "PROPERTY.TASKLISTENERS.EXPRESSION.PLACEHOLDER":"Insira uma expressão", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION":"Expressão de atribuição", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER":"Insira uma expressão de atribuição", + "PROPERTY.TASKLISTENERS.UNSELECTED":"Nenhum ouvinte de tarefas selecionado", + "PROPERTY.TASKLISTENERS.FIELDS.NAME":"Nome", + "PROPERTY.TASKLISTENERS.FIELDS.NAME.PLACEHOLDER":"Digite um nome", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION":"Expressão", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER":"Insira uma expressão", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE":"Valor da string", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER":"Insira um valor da string", + "PROPERTY.TASKLISTENERS.FIELDS.STRING":"String", + "PROPERTY.TASKLISTENERS.FIELDS.STRING.PLACEHOLDER":"Entre com o texto", + "PROPERTY.TASKLISTENERS.FIELDS.IMPLEMENTATION":"Implementação", + "PROPERTY.TASKLISTENERS.FIELDS.EMPTY":"Nenhum campo selecionado", + "PROPERTY.EVENTLISTENERS.DISPLAY":"{{length}} ouvintes de evento", + "PROPERTY.EVENTLISTENERS.EMPTY":"Nenhum ouvintes de evento configurado", + "PROPERTY.EVENTLISTENERS.EVENTS":"Eventos", + "PROPERTY.EVENTLISTENERS.RETHROW":"Relançar o evento?", + "PROPERTY.EVENTLISTENERS.CLASS":"Classe", + "PROPERTY.EVENTLISTENERS.CLASS.PLACEHOLDER":"Digite um nome de classe", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION":"Expressão de atribuição", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER":"Insira uma expressão de atribuição", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE":"Tipo de entidade", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE.PLACEHOLDER":"Entre com um tipo de entidade", + "PROPERTY.EVENTLISTENERS.RETHROWTYPE":"Relançar o tipo de evento", + "PROPERTY.EVENTLISTENERS.ERRORCODE":"Código de erro", + "PROPERTY.EVENTLISTENERS.ERRORCODE.PLACEHOLDER":"Entre com um código de erro", + "PROPERTY.EVENTLISTENERS.MESSAGENAME":"Nome da mensagem", + "PROPERTY.EVENTLISTENERS.MESSAGENAME.PLACEHOLDER":"Entre com um nome de mensagem", + "PROPERTY.EVENTLISTENERS.SIGNALNAME":"Nome do sinal", + "PROPERTY.EVENTLISTENERS.SIGNALNAME.PLACEHOLDER":"Entre com o nome do sinal", + "PROPERTY.EVENTLISTENERS.UNSELECTED":"Nenhum ouvinte de evento selecionado", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.VALUE" : "{{length}} lifecycle listeners", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EMPTY" : "No lifecycle listeners configured", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EVENT" : "Event", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.SOURCE_STATE" : "Source state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.TARGET_STATE" : "Target state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS" : "Class", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.UNSELECTED" : "No task listener selected", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME" : "Name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING" : "String", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.IMPLEMENTATION" : "Implementation", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EMPTY" : "No Field selected", + "PROPERTY.SIGNALDEFINITIONS.DISPLAY":"{{length}} definições de sinal", + "PROPERTY.SIGNALDEFINITIONS.EMPTY":"Nenhuma definição de sinal configurada", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-GLOBAL":"Global", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-PROCESSINSTANCE":"Instâncias de processos", + "PROPERTY.SIGNALDEFINITIONS.ID":"Id", + "PROPERTY.SIGNALDEFINITIONS.NAME":"Nome", + "PROPERTY.SIGNALDEFINITIONS.SCOPE":"Escopo", + "PROPERTY.MESSAGEDEFINITIONS.DISPLAY":"{{length}} definições de mensagem", + "PROPERTY.MESSAGEDEFINITIONS.EMPTY":"Nenhuma definição de mensagem configurada", + "PROPERTY.MESSAGEDEFINITIONS.ID":"Id", + "PROPERTY.MESSAGEDEFINITIONS.NAME":"Nome", + "PROPERTY.SEQUENCEFLOW.ORDER.EMPTY":"Nenhuma ordem de fluxo de sequência determinada", + "PROPERTY.SEQUENCEFLOW.ORDER.NOT.EMPTY":"Conjunto de ordem de fluxo de sequência", + "PROPERTY.SEQUENCEFLOW.ORDER.NO.OUTGOING.SEQUENCEFLOW.FOUND":"Não foi encontrado nenhum fluxo de sequência de saída.", + "PROPERTY.SEQUENCEFLOW.ORDER.DESCRIPTION":"Defina a ordem em que o fluxo de sequência precisa ser analisado:", + "PROPERTY.SEQUENCEFLOW.ORDER.SEQUENCEFLOW.VALUE":"Fluxo de sequência para {{targetType}} {{targetTitle}}", + "PROPERTY.SEQUENCEFLOW.CONDITION.TITLE":"Condição de fluxo de sequência", + "PROPERTY.SEQUENCEFLOW.CONDITION.STATIC":"Expressão de condição", + "PROPERTY.SEQUENCEFLOW.CONDITION.NO-CONDITION-DISPLAY":"Nenhum conjunto de condição", + "PROPERTY.DUEDATE.EMPTY":"Sem data de vencimento", + "PROPERTY.DUEDATE.DEFINED":"Data de vencimento definida", + "PROPERTY.DUEDATE.TITLE":"Data de vencimento", + "PROPERTY.DUEDATE.EXPRESSION-LABEL":"Expressões de data de vencimento", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.NO-DUEDATE":"Sem data de vencimento", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.EXPRESSION":"Definição de expressão", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.STATIC":"Duração fixa após a criação da tarefa", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.FIELD":"Com base no campo", + "MODEL.SAVE.TITLE":"Salvar modelo", + "MODEL.VALIDATE.TITLE":"Resultados de validação", + "MODEL.NAME":"Nome", + "MODEL.KEY":"Chave", + "MODEL.DESCRIPTION":"Descrição", + "MODEL.SAVE.NEWVERSION":"Salvar como uma nova versão? Isto significa que você pode sempre voltar para uma versão anterior", + "MODEL.SAVE.COMMENT":"Comentário", + "MODEL.SAVE.SAVING":"Salvando modelo", + "MODEL.LASTMODIFIEDDATE":"Salvo pela última vez em", + "MODEL.SAVE.ERROR":"Erro inesperado: não foi possível salvar o modelo", + "MODEL.VALIDATIONERRORS":"Observe que o modelo contem erros de validação. Isto significa que o modelo não pode ser implantado no motor Flowable em seu estado atual.", + "MODEL.CONFLICT.WRITE":"Não foi possível salvar modelo: '{{userFullName}}' há mudanças para este modelo", + "MODEL.CONFLICT.WRITE.OPTIONS":"Selecione uma opção para resolver este conflito:", + "MODEL.CONFLICT.WRITE.OPTION.OVERWRITE":"Substituir outro modelo", + "MODEL.CONFLICT.WRITE.OPTION.DISCARDCHANGES":"Descartar minhas alterações", + "MODEL.CONFLICT.WRITE.OPTION.SAVEAS":"Salvar como novo modelo", + "MODEL.CONFLICT.WRITE.OPTION.NEWVERSION":"Criar uma nova versão", + "MODEL.CONFLICT.SAVEAS":"Salvar como:", + "EVENT_TYPE.ACTIVITY.COMPENSATE.TOOLTIP":"Uma atividade está prestes a ser executado como uma compensação para outra atividade. O evento destina-se a atividade que está prestes a ser executado para compensação", + "EVENT_TYPE.ACTIVITY.COMPLETED.TOOLTIP":"Uma atividade foi concluída com sucesso", + "EVENT_TYPE.ACTIVITY.ERROR.RECEIVED.TOOLTIP":"Uma atividade recebeu um evento de erro. Expedido antes que o erro real tenha sido recebido pela atividade", + "EVENT_TYPE.MEMBERSHIP.CREATED.TOOLTIP":"Um nova subscrição foi criada", + "EVENT_TYPE.MEMBERSHIP.DELETED.TOOLTIP":"Um único subscrição foi removida", + "EVENT_TYPE.MEMBERSHIPS.DELETED.TOOLTIP":"Todas as subscrições no grupo relacionado foram excluídas. Nenhum evento individual será despachados por razões de desempenho", + "EVENT_TYPE.TASK.ASSIGNED.TOOLTIP":"Uma tarefa foi atribuída. Isto é lançado como um evento ENTITY_UPDATED", + "EVENT_TYPE.TASK.COMPLETED.TOOLTIP":"Uma tarefa foi concluída. Expedida antes da entidade tarefa ser excluída", + "EVENT_TYPE.UNCAUGHT.BPMNERROR.TOOLTIP":"Quando um erro de BPMN foi acionado, mas não foi detectado dentro do processo", + "EVENT_TYPE.VARIABLE.CREATED.TOOLTIP":"Foi criada uma nova variável", + "EVENT_TYPE.VARIABLE.DELETED.TOOLTIP":"Uma variável existente foi excluída", + "EVENT_TYPE.VARIABLE.UPDATED.TOOLTIP":"Uma variável existente foi atualizada", + "PROPERTY.DECISIONTABLEREFERENCE.EMPTY":"Nenhuma referência selecionada", + "PROPERTY.DECISIONTABLEREFERENCE.TITLE":"Referência de tabela de decisão", + "PROPERTY.DECISIONTABLEREFERENCE.ERROR.FORM":"Houve um erro ao carregar as tabelas de decisão. Tente novamente mais tarde", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.LOADING":"Carregando tabelas de decisão...", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.EMPTY":"Esta pasta não contém tabelas de decisão" +} diff --git a/snow-flowable/src/main/resources/static/i18n/zh-CN.json b/snow-flowable/src/main/resources/static/i18n/zh-CN.json new file mode 100644 index 0000000..0429461 --- /dev/null +++ b/snow-flowable/src/main/resources/static/i18n/zh-CN.json @@ -0,0 +1,1004 @@ +{ + "GENERAL" : { + "MAIN-TITLE": "Flowable编辑器", + "NAVIGATION" : { + "PROCESSES": "流程", + "CASEMODELS": "案例模型", + "FORMS": "表单", + "DECISION-TABLES": "决策表", + "APPS": "应用程序" + }, + "TITLE": { + "SELECT-GROUP" :"选择组", + "MATCHING-GROUPS": "匹配组", + "FILTER": "过滤", + "HISTORY": "历史" + }, + "ACTION": { + "LOGOUT": "退出", + "RETURN-TO-LIST": "显示所有定义", + "CANCEL": "取消", + "CLOSE": "关闭", + "EDIT": "编辑", + "SAVE": "保存", + "OPEN": "打开", + "OK": "Ok", + "CONFIRM": "确认", + "CONFIRM-AND-CLOSE": "确认并且关闭", + "NEW-FORM": "新表单", + "CREATE-FORM": "创建表单", + "NEW-DECISION-TABLE": "新决策表", + "CREATE-DECISION-TABLE": "创建决策表" + }, + "MESSAGE": { + "SELECT-GROUP-HELP": "使用 ↑ 和 ↓ 选择并按回车确认", + "PEOPLE-NO-MATCHING-RESULTS": "没有找到匹配的用户", + "GROUP-NO-MATCHING-RESULTS": "没有找到匹配的组", + "GROUP-SOURCE-TYPE": "组源", + "GROUP-SOURCE-SEARCH-OPTION": "组搜索", + "GROUP-SOURCE-FIELD-OPTION": "表单字段" + } + }, + + "EDITOR": { + "POPUP": { + "UNSAVED-CHANGES": { + "TITLE": "您有未保存的更改", + "DESCRIPTION": "您想如何处理未保存的更改?", + "ACTION": { + "SAVE": "保存更改", + "DISCARD": "放弃更改", + "CONTINUE": "继续编辑" + } + } + } + }, + + "PROCESS-LIST" : { + "TITLE" : "业务流程模型", + "SEARCH-PLACEHOLDER": "搜索", + "ACTION" : { + "CREATE": "创建流程", + "IMPORT": "导入流程" + }, + + "FILTER" : { + "PROCESSES": "流程模型", + "PROCESSES-COUNT": "一共有 {{total}}个流程模型", + "PROCESSES-ONE": "有一个流程模型", + "PROCESSES-EMPTY": "目前还没有创建流程模型。您可以设计流程模型、用户表单,然后将它们捆绑到app中。第一步是创建流程模型:", + "PROCESSES-BPMN-HINT": "使用BPMN可视化编辑器创建BPMN模型.", + "PROCESSES-BPMN-IMPORT-HINT": "还可以导入现有的BPMN模型。", + "FILTER-TEXT": ", 匹配 \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "没有匹配到流程模型 \"{{filterText}}\"", + "RECENT": "最近", + "RECENT-COUNT": "{{total}} 最近使用的模型", + "RECENT-ONE": "最近使用的模型", + "RECENT-EMPTY": "最近没有使用模型" + }, + + "SORT": { + "MODIFIED-ASC": "按照修改时间升序", + "MODIFIED-DESC": "按照修改时间降序", + "NAME-ASC": "按照名称升序", + "NAME-DESC": "按照名称降序" + } + }, + + "CASE-LIST" : { + "TITLE" : "案例模型", + "SEARCH-PLACEHOLDER": "搜索", + "ACTION" : { + "CREATE": "创建案例", + "IMPORT": "导入案例" + }, + + "FILTER" : { + "CASES": "案例模型", + "CASES-COUNT": "一共有 {{total}}个案例模型", + "CASES-ONE": "有一个case模型", + "CASES-EMPTY": "目前还没有创建案例模型。您可以设计实例模型、用户表单,然后将它们捆绑到app应用程序定义中。第一步是创建一个案例模型。:", + "CASES-CMMN-HINT": "使用CMMN可视化编辑器创建CMMN模型.", + "CASES-CMMN-IMPORT-HINT": "还可以导入现有CMMN模型。", + "FILTER-TEXT": ", 匹配 \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "没有匹配到case模型 \"{{filterText}}\"", + "RECENT": "最近", + "RECENT-COUNT": "{{total}} 最近使用的模型", + "RECENT-ONE": "最近使用的模型", + "RECENT-EMPTY": "最近没有使用模型" + }, + + "SORT": { + "MODIFIED-ASC": "按照修改时间升序", + "MODIFIED-DESC": "按照修改时间降序", + "NAME-ASC": "按照名称升序", + "NAME-DESC": "按照名称降序" + } + }, + + "FORMS-LIST" : { + "TITLE" : "表单", + "SEARCH-PLACEHOLDER": "搜索", + "ACTION" : { + "CREATE": "创建表单", + "CREATE-INLINE": "现在创建一个新表单!", + "SHOW-MORE": "显示更多..." + }, + + "FILTER" : { + "FORMS": "表单", + "FORMS-COUNT": "一共有{{total}} 个表单", + "FORMS-ONE": "有一个表单", + "FORMS-EMPTY": "没有表单。若要添加一个,请单击创建表单 ", + "FILTER-TEXT": ", 匹配 \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "没有匹配到表单 \"{{filterText}}\"" + }, + + "SORT": { + "MODIFIED-ASC": "按照修改时间升序", + "MODIFIED-DESC": "按照修改时间降序", + "NAME-ASC": "按照名称升序", + "NAME-DESC": "按照名称降序" + } + }, + + "DECISION-TABLES-LIST": { + "TITLE": "决策表", + "SEARCH-PLACEHOLDER": "搜索", + "ACTION": { + "CREATE": "创建决策表", + "IMPORT": "导入决策表", + "CREATE-INLINE": "现在创建一个新的决策表!", + "SHOW-MORE": "显示更多..." + }, + + "FILTER": { + "DECISION-TABLES": "决策表", + "DECISION-TABLES-COUNT": "一共有 {{total}} 个决策表", + "DECISION-TABLES-ONE": "有一个决策表", + "DECISION-TABLES-EMPTY": "没有决策表。若要添加一个,请单击创建决策表 ", + "FILTER-TEXT": ", 匹配 \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "没有匹配到决策表 \"{{filterText}}\"" + }, + + "SORT": { + "MODIFIED-ASC": "按照修改时间升序", + "MODIFIED-DESC": "按照修改时间降序", + "NAME-ASC": "按照名称升序", + "NAME-DESC": "按照名称降序" + } + }, + + "APPS-LIST" : { + "TITLE" : "应用程序定义", + "SEARCH-PLACEHOLDER": "搜索", + "ACTION" : { + "CREATE": "创建应用程序", + "IMPORT": "导入应用程序", + "SHOW-MORE": "显示更多..." + }, + + "FILTER" : { + "APPS": "应用程序定义", + "APPS-COUNT": "一共有 {{total}}个应用程序定义", + "APPS-ONE": "有一个app定义", + "APPS-EMPTY": "没有应用程序定义。若要添加一个,请单击创建应用程序定义", + "FILTER-TEXT": ", 匹配 \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "没有匹配到应用程序定义 \"{{filterText}}\"", + + "NO-APPS": " 您可以通过发布一批流程模型来创建应用程序定义", + "NO-APPS-CALL-TO-ACTION": "现在可以创建一个应用程序定义 ", + "NO-APPS-NOTE": "当你准备好使用它时,记得要发布它。" + }, + + "SORT": { + "MODIFIED-ASC": "按照修改时间升序", + "MODIFIED-DESC": "按照修改时间降序", + "NAME-ASC": "按照名称升序", + "NAME-DESC": "按照名称降序" + } + }, + "PROCESS": { + "NAME": "模型名称", + "KEY": "模型key", + "DESCRIPTION": "描述", + "VERSION-COMMENT": "版本注释", + "ACTION": { + "DETAILS": "显示详细信息", + "EDIT": "修改模型属性", + "DUPLICATE": "复制这个模型", + "EXPORT_BPMN20": "导出到BPMN2", + "DELETE": "删除这个模型", + "CREATE-CONFIRM": "创建新模型", + "DUPLICATE-CONFIRM": "复制这个模型", + "OPEN-IN-EDITOR": "可视化编辑器", + "EDIT-CONFIRM": "保存", + "DELETE-CONFIRM": "删除流程模型", + "USE-AS-NEW-VERSION": "作为新版本使用", + "FAVORITE": "喜欢这个模型" + + }, + "DETAILS": { + "HISTORY-TITLE": "历史", + "LAST-UPDATED-BY": "最后被{{lastUpdatedBy}} - {{lastUpdated | dateformat}}更新", + "CREATED-BY": "被{{createdBy}}创建", + "NO-DESCRIPTION": "这个模型没有描述信息,可以通过修改模型来添加一个描述" + }, + + "POPUP": { + "CREATE-TITLE": "创建一个新的业务流程模型", + "DUPLICATE-TITLE": "复制这个业务流程模型", + "CREATE-DESCRIPTION": "您需要为新模型命名,并且您可以在这个操作中添加描述信息。", + "DUPLICATE-DESCRIPTION": "您可以更改新模型的名称,并且此时您可以更改描述信息。", + "EDIT-DESCRIPTION": "更改下面的任何模型属性,然后按下保存去更新模型。", + "DELETE-DESCRIPTION": "确实要删除进程模型吗? \"{{name}}\"?", + "EDIT-TITLE":"编辑模型详细信息", + "DELETE-TITLE": "删除模型", + "DELETE-LOADING-RELATIONS": "检查模型使用...", + "DELETE-RELATIONS-DESCRIPTION-SINGLE": "无法删除此模型,因为另一个模型正在使用它:", + "DELETE-RELATIONS-DESCRIPTION": "无法删除此模型,因为另一个模型正在使用它:", + "DELETE-PROCESS-RELATION": "流程模型", + "DELETE-FORM-RELATION": "表单模型", + "DELETE-APP-RELATION": "App模型", + "IMPORT-DESCRIPTION": "请浏览或拖拽.bpmn或.bpmn20.xml扩展名的BPMN XML定义", + "IMPORT-TITLE": "导入一个流程模型", + "USE-AS-NEW-TITLE": "作为一个新版本使用", + "USE-AS-NEW-DESCRIPTION": "您确定要使用 {{version}}版本 去创建一个关于 \"{{name}}\"的新版本?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "无法完全恢复app模型到所选择的版本:由于一些引用的模型过去被删除而丢失。请相应地更新app模型。缺失模型:", + "USE-AS-NEW-UNRESOLVED-MODEL": "模型 '{{name}}' 内部id {{id}}, 被 {{createdBy}}创建", + "SHARED-WITH": "分享", + "PERMISSION": "许可", + "ACTIONS": "动作", + "IMPORT": { + "DROPZONE": "拖拽一个 .bpmn 或者 .bpmn20.xml BPMN XML 文件", + "CANCEL-UPLOAD": "取消上传", + "ERROR": "处理BPMN XML文件时出错", + "NO-DROP": "不支持拖放" + } + }, + "ALERT": { + "EDIT-CONFIRM": "模型被更新" + }, + "ERROR": { + "NOT-FOUND": "所请求的模型不存在" + } + }, + + "SUBPROCESS": { + "NAME": "子流程名称", + "DESCRIPTION": "描述信息", + "ACTION": { + "CREATE-CONFIRM": "创建一个子流程" + }, + "POPUP": { + "CREATE-TITLE": "创建一个新的子流程", + "CREATE-DESCRIPTION": "您需要为新的子流程命名,并且您可能希望同时添加描述。" + } + }, + + "CASE": { + "NAME": "模型名称", + "KEY": "模型key", + "DESCRIPTION": "描述信息", + "VERSION-COMMENT": "版本注释", + "ACTION": { + "DETAILS": "显示详细信息", + "EDIT": "修改模型属性", + "DUPLICATE": "复制这个模型", + "EXPORT_CMMN": "导出到CMMN1.1", + "DELETE": "删除这个模型", + "CREATE-CONFIRM": "创建新模型", + "DUPLICATE-CONFIRM": "复制这个模型", + "OPEN-IN-EDITOR": "可视化编辑器", + "EDIT-CONFIRM": "保存", + "DELETE-CONFIRM": "删除case模型", + "USE-AS-NEW-VERSION": "作为新版本使用", + "FAVORITE": "喜欢这个模型" + }, + "DETAILS": { + "HISTORY-TITLE": "历史", + "LAST-UPDATED-BY": "最后被 {{lastUpdatedBy}} - {{lastUpdated | dateformat}}更新", + "CREATED-BY": "被{{createdBy}}创建", + "NO-DESCRIPTION": "这个模型没有描述信息,可以通过修改模型来添加一个描述" + }, + "POPUP": { + "CREATE-TITLE": "创建一个新的案例模型", + "DUPLICATE-TITLE": "复制这个案例模型", + "CREATE-DESCRIPTION": "您需要为新模型命名,并且您可以在这个操作中添加描述信息。", + "DUPLICATE-DESCRIPTION": "您可以更改新模型的名称,并且此时您可以更改描述信息。", + "EDIT-DESCRIPTION": "更改下面的任何模型属性,然后按下保存去更新模型。", + "DELETE-DESCRIPTION": "确实要删除进程流程吗 \"{{name}}\"?", + "EDIT-TITLE":"编辑模型详细信", + "DELETE-TITLE": "删除模型", + "DELETE-LOADING-RELATIONS": "检查模型使用...", + "DELETE-RELATIONS-DESCRIPTION-SINGLE": "无法删除此模型,因为另一个模型正在使用它:", + "DELETE-RELATIONS-DESCRIPTION": "无法删除此模型,因为另一个模型正在使用它:", + "DELETE-PROCESS-RELATION": "案例模型", + "DELETE-FORM-RELATION": "表单模型", + "DELETE-APP-RELATION": "应用程序模型", + "IMPORT-DESCRIPTION": "请浏览或拖拽.cmmn 或者.cmmn.xml 扩展名的CMMN XML", + "IMPORT-TITLE": "导入一个案例模型", + "USE-AS-NEW-TITLE": "作为一个新版本使用", + "USE-AS-NEW-DESCRIPTION": "您确定要使用 {{version}}版本 去创建一个关于 \"{{name}}\"的新版本?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "无法完全恢复app模型到所选择的版本:由于一些引用的模型过去被删除而丢失。请相应地更新应用程序模型。缺失模型:", + "USE-AS-NEW-UNRESOLVED-MODEL": "模型 '{{name}}' 内部id {{id}}, 被 {{createdBy}}创建", + "SHARED-WITH": "分享", + "PERMISSION": "许可", + "ACTIONS": "动作", + "IMPORT": { + "DROPZONE": "拖拽一个 .cmmn or .cmmn.xml CMMN XML文件", + "CANCEL-UPLOAD": "取消上传", + "ERROR": "处理CMMN XML文件时出错", + "NO-DROP": "不支持拖放" + } + }, + "ALERT": { + "EDIT-CONFIRM": "模型被更新" + }, + "ERROR": { + "NOT-FOUND": "所请求的模型不存在" + } + }, + + "FORM": { + "NAME": "表单名称", + "KEY": "表单key", + "DESCRIPTION": "描述", + "ACTION": { + "DETAILS": "显示详细信息", + "EDIT": "修改模型属性", + "DELETE": "复制这个表单", + "CREATE-CONFIRM": "创建新表单", + "DUPLICATE": "复制这个表单", + "DUPLICATE-CONFIRM": "复制这个表单", + "OPEN-IN-EDITOR": "表单编辑器", + "EDIT-CONFIRM": "保存", + "DELETE-CONFIRM": "删除表单", + "USE-AS-NEW-VERSION": "作为新版本使用" + + }, + "DETAILS": { + "HISTORY-TITLE": "历史", + "LAST-UPDATED-BY": "最后被{{lastUpdatedBy}} - {{lastUpdated | dateformat}}更新", + "CREATED-BY": "被{{createdBy}}创建" + }, + + "POPUP": { + "CREATE-TITLE": "创建一个新的表单", + "DUPLICATE-TITLE": "复制这个表单", + "CREATE-DESCRIPTION": "您需要为新表单命名,并且您可以在这个操作中添加描述信息。", + "DUPLICATE-DESCRIPTION": "您需要为新表单命名,并且您可以在这个操作中添加描述信息。", + "SAVE-FORM-TITLE": "保存表单", + "EDIT-DESCRIPTION": "更改下面的任何模型属性,然后按下保存去更新表单。", + "DELETE-DESCRIPTION": "确实要删除表单 \"{{name}}\"?", + "EDIT-TITLE":"编辑表单详细信息", + "DELETE-TITLE": "删除表单", + "USE-AS-NEW-TITLE": "作为一个新版本使用", + "USE-AS-NEW-VERSION": "作为一个新版本使用", + "USE-AS-NEW-DESCRIPTION": "您确定要使用 {{version}}版本 去创建一个关于 \"{{name}}\"的新版本?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "无法完全恢复app模型到所选择的版本:由于一些引用的模型过去被删除而丢失。请相应地更新app模型。缺失模型:", + "USE-AS-NEW-UNRESOLVED-MODEL": "模型 '{{name}}' 内部id {{id}}, 被 {{createdBy}}创建" + } + }, + + "DECISION-TABLE": { + "NAME": "决策表 名称", + "KEY": "决策表 key", + "DESCRIPTION": "描述", + "VERSION-COMMENT": "版本注释", + "HIT-POLICY": "命中策略:", + "ACTION": { + "DETAILS": "显示详细信息", + "EDIT": "修改模型属性", + "SHARE": "分享决策表", + "DELETE": "删除决策表", + "ADD-COMMENT": "+ 添加评论", + "CREATE-CONFIRM": "创建新的决策表", + "OPEN-IN-EDITOR": "决策表编辑器", + "EXPORT": "Export 决策表", + "DELETE-CONFIRM": "删除决策表", + "USE-AS-NEW-VERSION": "作为新版本使用", + "FAVORITE": "喜欢这个决策表", + "DUPLICATE": "复制这个决策表" + }, + "DETAILS": { + "HISTORY-TITLE": "历史", + "COMMENTS-TITLE": "评论", + "LAST-UPDATED-BY": "最后被{{lastUpdatedBy}} - {{lastUpdated | dateformat}}更新", + "CREATED-BY": "被{{createdBy}}创建" + }, + "HIT-POLICIES": { + "FIRST": "First", + "ANY": "Any", + "UNIQUE": "Unique", + "PRIORITY": "Priority", + "RULE ORDER": "Rule Order", + "OUTPUT ORDER": "Output Order", + "COLLECT": "Collect" + }, + "COLLECT-OPERATORS": { + "SUM": "和", + "MIN": "最小", + "MAX": "最大", + "COUNT": "总数" + }, + "POPUP": { + "CREATE-TITLE": "创建一个新的决策表", + "CREATE-DESCRIPTION": "您需要为新决策表命名,并且您可以在这个操作中添加描述信息。", + "SAVE-DESCRIPTION": "您可以更改新决策表的名称,并且此时您可以更改描述信息。", + "DUPLICATE-TITLE": "复制决策表", + "DUPLICATE-DESCRIPTION": "您需要为新决策表命名,并且您可以在这个操作中添加描述信息。", + "DELETE-TITLE": "删除决策表", + "DELETE-DESCRIPTION": "确实要删除决策表 \"{{name}}\"?", + "SAVE-DECISION-TABLE-TITLE": "保存决策表", + "IMPORT-DESCRIPTION": "请浏览或拖拽.dmn or .dmn.xml扩展名的的 DMN XML文件", + "IMPORT-TITLE": "导入DMN模型", + "IMPORT": { + "DROPZONE": "拖拽一个 .dmn or .dmn.xml DMN XML文件", + "CANCEL-UPLOAD": "取消上传", + "ERROR": "处理DMN XML文件时出错", + "NO-DROP": "不支持拖放" + }, + "USE-AS-NEW-TITLE": "作为一个新版本使用", + "USE-AS-NEW-VERSION": "作为一个新版本使用", + "USE-AS-NEW-DESCRIPTION": "您确定要使用 {{version}}版本 去创建一个关于 \"{{name}}\"的新版本?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "无法完全恢复app模型到所选择的版本:由于一些引用的模型过去被删除而丢失。请相应地更新app模型。缺失模型:", + "USE-AS-NEW-UNRESOLVED-MODEL": "模型 '{{name}}' 内部id {{id}}, 被 {{createdBy}}创建" + }, + "ALERT": { + "FAVORITE-CONFIRM": "喜欢这个决策表", + "UN-FAVORITE-CONFIRM": "这个决策表不再流行了" + } + }, + + "APP": { + "NAME": "应用程序定义名称", + "KEY": "应用程序定义key", + "DESCRIPTION": "描述", + "ICON": "图标", + "THEME": "主题", + "GROUPS-ACCESS": "组访问,用逗号分隔", + "USERS-ACCESS": "用户访问,用逗号分隔", + "ACTION": { + "DETAILS": "显示详细信息", + "EDIT": "修改应用程序定义属性", + "DUPLICATE": "复制这个应用", + "SHARE": "分享应用程序定义", + "DELETE": "删除应用程序定义", + "CREATE-CONFIRM": "创建新的应用程序定义", + "DUPLICATE-CONFIRM": "复制这个应用程序定义", + "DELETE-CONFIRM": "删除应用程序定义", + "USE-AS-NEW-VERSION": "作为新版本使用", + "OPEN-IN-EDITOR": "应用程序编辑器", + "PUBLISH": "发布", + "PUBLISH-CONFIRM": "发布应用程序定义", + "SELECT-ICON": "修改图标...", + "SELECT-THEME": "修改主题...", + "EDIT-MODELS": "编辑包含的模型", + "EXPORT-ZIP": "将app定义导出为zip文件", + "EXPORT-BAR": "将app定义导出为可部署的bar文件" + + }, + "DETAILS": { + "TITLE": "App定义详细信息: {{name}}", + "HISTORY-TITLE": "历史", + "MODELS-TITLE": "app定义中包含的模型", + "LAST-UPDATED-BY": "最后被{{lastUpdatedBy}} - {{lastUpdated | dateformat}}更新", + "CREATED-BY": "被{{createdBy}}创建", + "NO-DESCRIPTION": "这个应用程序定义没有描述信息,可以通过修改应用程序定义来添加一个描述", + "NO-MODELS-SELECTED": "没有为这个应用程序选择模型" + }, + "TITLE": { + "SELECT-ICON": "选择应用图标", + "SELECT-THEME": "选择应用主题", + "PREVIEW": "预览" + + }, + "POPUP": { + "CREATE-TITLE": "创建新的应用程序定义", + "DUPLICATE-TITLE": "复制一个应用程序定义", + "SAVE-APP-TITLE": "保存应用程序定义", + "SAVE-APP-SAVE-SUCCESS": "保存的应用程序定义", + "CREATE-DESCRIPTION": "您需要为新的应用程序定义命名,并且您可以在这个操作中添加描述信息。", + "DUPLICATE-DESCRIPTION": "您需要为新的应用程序定义命名,并且您可以在这个操作中添加描述信息。", + "PUBLISH-TITLE": "发布应用程序定义", + "PUBLISH-DESCRIPTION": "您确定要发布应用程序定义 \"{{name}}\"? 注意这个应用程序定义将版本化,如果已经存在,则将更新工作流应用程序。", + "PUBLISH-FIELD": "发布?请注意,如果启用了发布,则将版本化此应用程序定义,如果已经存在,则将更新工作流应用程序。", + "PUBLISH-ERROR-PROCDEF-KEY-CONFLICT": "你的流程模型 \"{{modelInAppName}}\"具有相同的标识符\"{{processDefinitionKey}}\"作为已经存在的部署流程\"{{conflictingModelName}}\" ,关于这个应用程序 \"{{conflictingAppName}}\". 请修改这个 \"id\"流程模型的属性。", + "PUBLISH-ERROR-PROCESS-ALREADY-USED": "下面的流程模型已经在另一个应用程序中使用了。这样行吗?", + "PUBLISH-ERROR-PROCESS-ALREADY-USED-APP": "应用程序", + "PUBLISH-ERROR-PROCDEF-DUPLICATE-KEYS": "无效的应用程序: 找到重复的流程标识符 (修改这个非法的流程模型 \"id\"属性):", + "DELETE-TITLE": "删除应用程序定义", + "DELETE-DESCRIPTION": "确实要删除应用程序定义 \"{{name}}\"?", + "DELETE-DESCRIPTION-WITH-RUNTIME": "确实要删应用程序定义 \"{{name}}\"? 注意,这个应用程序定义已经部署到任务landing页面,并且通过确认,该应用程序将从任务应用程序landing页面中删除。", + "DELETE-CASCADE-FALSE": "只删除当前版本的应用程序定义 (v{{version}})", + "DELETE-CASCADE-TRUE": "也删除所有以前的版本应用程序定义", + "HAS-CUSTOM-STENCILITEM" : "模型 \"{{modelName}}\" 使用带有自定义模板项目的模板. 在这个模型中使用这个模型是不可能的.", + "HAS-VALIDATIONERROR" : "模型 \"{{modelName}}\" 有验证错误,不能添加到应用程序定义.在编辑器中打开模型以查看关于验证错误的更多细节。", + "IMPORT-DESCRIPTION":"请使用.zip扩展的应用程序定义浏览或拖拽一个", + "IMPORT-TITLE":"导入应用程序定义模型", + "IMPORT": { + "DROPZONE": "扩拽一个.zip 应用程序定义文件", + "CANCEL-UPLOAD": "取消上传", + "RENEWIDM-IDS": "Renew the user and group identifiers when importing step and BPMN models. This is often required when importing the 应用程序定义 into a different Flowable environment. It will try to link the human steps and user tasks to the right user and group in this target environment.", + "ERROR": "处理应用程序定义文件时出错", + "NO-DROP": "不支持拖放" + }, + "INCLUDE-MODELS-TITLE": "包含在应用程序定义中的模型" + }, + "ALERT": { + "DELETE-CONFIRM": "应用程序定义删除了", + "PUBLISH-CONFIRM": "应用程序定义已经被发布了", + "PUBLISH-ERROR": "不能发布应用程序定义. 请检查引用的流程模型的有效性。" + } + }, + + "SHARE-INFO": { + "ACTION": { + "ADD": "添加另一个人" + } + }, + + "FORM-BUILDER": { + "PALLETTE": { + "TEXT": "文本", + "MULTILINE-TEXT": "多行文本", + "PASSWORD": "密码", + "NUMBER": "数字", + "CHECKBOX": "多选", + "DATE": "日期", + "DROPDOWN": "下拉", + "RADIO": "单选按钮", + "PEOPLE": "选择人", + "GROUP-OF-PEOPLE": "选择组", + "UPLOAD": "上传文件", + "EXPRESSION": "表达式", + "DECIMAL": "小数", + "HYPERLINK": "超链接", + "SPACER": "垫片", + "HORIZONTAL-LINE": "横线", + "HEADLINE": "标题", + "HEADLINE-WITH-LINE":"标题和线" + }, + "TABS": { + "GENERAL": "一般", + "OPTIONS": "选项", + "UPLOAD-OPTIONS": "上传选项", + "ADVANCED-OPTIONS":"高级" + }, + "VERSION": "版本 {{version}}", + "LAST-UPDATED": "最后更新的 {{lastUpdatedBy}}, {{lastUpdated | dateformat}}", + "TITLE": { + "DESIGN": "设计", + "OUTCOME": "结果" + }, + "POPUP": { + "EDIT-TITLE": "编辑字段 '{{name}}'", + "EXPRESSION-TITLE": "编辑表达式" + }, + "MESSAGE": { + "EMPTY-EXPRESSION": "(没有表达值)", + "EXPRESSION-HELP": "您还可以使用如下的符号来引用先前以任何形式提交的值,作为文本的一部分 ${myFieldId}.", + "OPTIONS-EXPRESSION-HELP": "可以使用表达式来动态填充选项,例如通过引用这样的变量 ${optionsVariable}. 这个表达式需要产生一个java对象(java.util)。带有选项对象的列表)或其json表示。" + }, + "LABEL" : { + "FUNCTIONAL-GROUP": "选择组..", + "PERSON": "选择人.." + }, + "COMPONENT": { + "LABEL": "标签:", + "OVERRIDEID": "覆盖id?", + "ID": "Id:", + "PLACEHOLDER": "默认值:", + "OPTIONS": "选项", + "RADIO-BUTTON-DEFAULT": "选项 1", + "DROPDOWN-DEFAULT-EMPTY-SELECTION": "请选择一个...", + "DROPDOWN-EMPTY-VALUE-HELP": " 这是‘空值’选项。在运行时选择它意味着‘没有值’或’空’。这允许用于可选字段,但不允许用于必需字段。", + "OPTIONS-EXPRESSION": "选择表达:", + "OPTIONS-EXPRESSION-ENABLED": "启用选项表达", + "REQUIRED": "必填", + "READONLY": "只读", + "EXPRESSION": "表达式", + "ADD-OPTION": "+ 添加一个新选项", + "UPLOAD-ALLOW-MULTIPLE": "允许上传多个文件", + "SIZE": "大小", + "MAX-LENGTH":"最大长度:", + "MIN-LENGTH":"最小长度:", + "PASSWORD-UNMASK-OPTION": "密码屏蔽/揭露选项", + "HYPERLINK-URL": "超链接地址", + "REGEX-PATTERN":"正则表达式的标准", + "MASK":{ + "TITLE":"输入掩码", + "EXAMPLES":{ + "TITLE":"例子:", + "NUMBER":"任何数字", + "LETTER":"任何字母", + "NUMBERORLETTER":"任何字母或数字", + "OPTIONAL":"使蒙版可选(无效)", + "PHONE":"电话" + } + } + }, + "OUTCOMES": { + "DESCRIPTION": "您可以为这个任务定义多个结果。在完成一个任务时,用户选择一个可用的结果,可以在eg中使用。在这个过程中进一步的条件。", + "NO-OUTCOMES-OPTION": "不要使用自定义结果,只显示'完成'按钮。", + "OUTCOMES-OPTION": "使用此表单的定制结果。", + "POSSIBLE-OUTCOMES": "可能的出线", + "NEW-OUTCOME-PLACEHOLDER": "输入新的出线", + "ADD": "添加出线", + "REMOVE": "移除" + } + }, + + "DECISION-TABLE-EDITOR": { + "EMPTY-MESSAGES": { + "NO-VARIABLE-SELECTED": "未定义" + }, + "POPUP": { + "EXPRESSION-EDITOR": { + "INPUT-TITLE": "编辑输入列", + "INPUT-DESCRIPTION": "选择输入变量作为列的输入", + "OUTPUT-TITLE": "编辑输出列", + "OUTPUT-DESCRIPTION": "选择一个现有的输出变量或创建一个新的变量", + "EXPRESSION-LABEL": "列标签:", + "EXPRESSION-PLACEHOLDER": "输入可选标签", + "EXPRESSION-VARIABLE-NAME": "变量名称:", + "EXPRESSION-VARIABLE-TYPE": "变量类型:", + "EXPRESSION-VARIABLE-NAME-PLACEHOLDER": "输入变量名", + "OUTPUT-NEW-VARIABLE-ID": "变量ID:", + "OUTPUT-NEW-VARIABLE-TYPE": "变量类型:", + "COMPLEX-EXPRESSION-LABEL": "复杂表达式:", + "ALLOWED-VALUES": "允许值(可选):", + "OUTPUT-VALUES": "输出值", + "OUTPUT-VALUES-OPTIONAL": "(可选):", + "OUTPUT-VALUES-NOT-OPTIONAL": "(为优先级/输出顺序拖动行):" + } + }, + "BUTTON-ACTIONS-LABEL": "动作", + "BUTTON-ADD-INPUT-LABEL": "添加输入", + "BUTTON-ADD-OUTPUT-LABEL": "添加输出", + "BUTTON-ADD-RULE-LABEL": "添加规则", + "BUTTON-MOVE-RULE-UPWARDS-LABEL": "向上移动", + "BUTTON-MOVE-RULE-DOWNWARDS-LABEL": "向下移动", + "BUTTON-REMOVE-RULE-LABEL": "移除规则", + "ALERT": { + "EXPRESSION-VARIABLE-REQUIRED-ERROR": "所有输入和输出表达式都必须引用表单字段或变量。", + "SAVE-CONFIRM": "保存决策表'{{name}}'" + } + }, + + "TOUR": { + "WELCOME-TITLE": "欢迎, {{userName}}", + "WELCOME-CONTENT": "这是一个短暂的flowable编辑器. 接下来的几个步骤将指导您通过应用程序的不同部分来启动。按ESC键随时停止。" , + "PALETTE-TITLE": "调色板", + "PALETTE-CONTENT": "在这里可以找到创建业务流程的所有可用构成。它们是按逻辑组排列的。只需点击它就可以打开一组:", + "CANVAS-TITLE": "画布", + "CANVAS-CONTENT": "这是创建业务流程的工作空间。从左侧的调色板中拖动元素,并将它们放在画布上以开始建模", + "DRAGDROP-TITLE": "拖放示例", + "DRAGDROP-CONTENT": "下面是一个如何开始建模的例子:", + "PROPERTIES-TITLE": "属性", + "PROPERTIES-CONTENT": "在这里您可以配置业务流程构造的属性。只需选择画布上的项目,它的属性就会显示出来。如果要编辑该属性,请单击该属性。", + "TOOLBAR-TITLE": "工具栏", + "TOOLBAR-CONTENT": "可以在这里找到所有的动作:保存或验证模型, 复制和粘贴一个流程的部分, 等等. 在按钮上悬停以此获得对动作的描述信息.", + "END-TITLE": "终点", + "END-CONTENT": "就是这样!现在可以开始建模过程。如果你有任何问题,可以问他们。 Flowable论坛 " + }, + + "FEATURE-TOUR" : { + "BENDPOINT" : { + "TITLE": "教程", + "DESCRIPTION" : "当使用连线流将流程按照步骤彼此连接的时候,您可能会发现,这些连线彼此交叉,或者您希望以不同的方式排列它们。这样做, 可以向连线添加或移除一个弯曲点。

如下图所示,你首先应该点击 '添加弯曲点' 然后单击连线添加它。注意,连线将在绿色中显示一个微妙的指示,以显示可以在那里添加弯曲点。

删除一个弯曲点再次遵循类似的模式: 点击 '移除弯曲点' 按钮 ,然后点击弯曲点再次移除。" + } + }, + + "ACTION.OK" : "Ok", + "ACTION.SAVE" : "保存", + "ACTION.SAVE-AND-CLOSE" : "保存和关闭编辑器", + "ACTION.SEND" : "发送", + "ACTION.CANCEL" : "取消", + "ACTION.SELECT" : "选择", + "ACTION.ADD" : "添加", + "ACTION.REMOVE" : "移除", + "ACTION.MOVE.UP" : "移动入口", + "ACTION.MOVE.DOWN" : "向下移动", + + "TOOLBAR.ACTION.CLOSE" : "关闭编辑器并返回到概览页面", + "TOOLBAR.ACTION.SAVE" : "保存模型", + "TOOLBAR.ACTION.VALIDATE" : "验证模型", + "TOOLBAR.ACTION.CUT" : "剪切 (在业务流程中选择一个或多个元素)", + "TOOLBAR.ACTION.COPY" : "拷贝 (在业务流程中选择一个或多个元素)", + "TOOLBAR.ACTION.PASTE" : "粘贴", + "TOOLBAR.ACTION.DELETE" : "删除选定元素", + "TOOLBAR.ACTION.UNDO" : "撤消", + "TOOLBAR.ACTION.REDO" : "重做", + "TOOLBAR.ACTION.ZOOMIN" : "放大", + "TOOLBAR.ACTION.ZOOMOUT" : "缩小", + "TOOLBAR.ACTION.ZOOMACTUAL" : "缩放到实际尺寸", + "TOOLBAR.ACTION.ZOOMFIT" : "缩放到适当大小", + "TOOLBAR.ACTION.BENDPOINT.ADD" : "向选定的连线添加弯曲点", + "TOOLBAR.ACTION.BENDPOINT.REMOVE" : "向选定的连线移除弯曲点", + "TOOLBAR.ACTION.ALIGNHORIZONTAL" : "水平对齐", + "TOOLBAR.ACTION.ALIGNVERTICAL" : "垂直对齐", + "TOOLBAR.ACTION.SAMESIZE" : "相同大小", + "TOOLBAR.ACTION.HELP": "开始导游", + "TOOLBAR.ACTION.FEEDBACK": "提供反馈", + + "FORM_TOOLBAR.ACTION.SAVE" : "保存模型", + + "APP_DEFINITION_TOOLBAR.ACTION.SAVE" : "保存应用程序定义", + + "BUTTON.ACTION.DELETE.TOOLTIP": "从模型中删除元素", + "BUTTON.ACTION.MORPH.TOOLTIP": "更改元素类型", + + "ELEMENT.AUTHOR" : "作者", + "ELEMENT.DATE_CREATED" : "创建日期", + + "PROPERTY.REMOVED" : "移除", + "PROPERTY.EMPTY" : "空值", + "PROPERTY.PROPERTY.EDIT.TITLE" : "更改值为", + + "PROPERTY.FEEDBACK.TITLE" : "请填写您的反馈意见", + + "PROPERTY.ASSIGNMENT.TITLE" : "分配", + "PROPERTY.ASSIGNMENT.TYPE" : "类型", + "PROPERTY.ASSIGNMENT.TYPE.IDENTITYSTORE" : "身份存储", + "PROPERTY.ASSIGNMENT.TYPE.STATIC" : "固定值", + "PROPERTY.ASSIGNMENT.ASSIGNEE" : "分配", + "PROPERTY.ASSIGNMENT.MATCHING" : "使用 ↑ 和 ↓选择并按Enter确认或使用鼠标", + "PROPERTY.ASSIGNMENT.ASSIGNEE_PLACEHOLDER" : "输入分配人", + "PROPERTY.ASSIGNMENT.EMPTY" : "没有选择分配人", + "PROPERTY.ASSIGNMENT.NONE" : "未分配经办人", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHUSER": "搜索用户", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHGROUP": "搜索组", + "PROPERTY.ASSIGNMENT.SEARCH": "搜索: ", + "PROPERTY.ASSIGNMENT.ASSIGNEE_DISPLAY" : "分配人 {{assignee}}", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY" : "{{length}} 候选用户", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS" : "候选用户", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY" : "{{length}} 候选组", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS" : "候选组", + "PROPERTY.ASSIGNMENT.USER_IDM_DISPLAY": "用户 {{firstName}} {{lastName}}", + "PROPERTY.ASSIGNMENT.USER_IDM_EMAIL_DISPLAY": "用户 {{email}}", + "PROPERTY.ASSIGNMENT.USER_IDM_FIELD_DISPLAY": "字段 {{name}}", + "PROPERTY.ASSIGNMENT.IDM_EMPTY" : "流程发起人", + "PROPERTY.ASSIGNMENT.IDM.TYPE" : "分配", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_USERS" : "没有选择候选人...", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_GROUPS" : "没有选择候选组...", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.INITIATOR" : "分配给流程发起人", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USER" : "分配给单个用户", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USERS" : "候选用户", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.GROUPS" : "候选组", + "PROPERTY.ASSIGNMENT.INITIATOR-CAN-COMPLETE" : "允许流程发起人完成任务", + "PROPERTY.EXECUTIONLISTENERS.DISPLAY" : "{{length}} 执行监听器", + "PROPERTY.EXECUTIONLISTENERS.EMPTY" : "没有配置执行监听器", + "PROPERTY.EXECUTIONLISTENERS.EVENT" : "事件", + "PROPERTY.EXECUTIONLISTENERS.CLASS" : "类", + "PROPERTY.EXECUTIONLISTENERS.CLASS.PLACEHOLDER" : "输入一个类名", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION" : "表达式", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION" : "委托表达式", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "输入一个委托表达式", + "PROPERTY.EXECUTIONLISTENERS.UNSELECTED" : "没有选择执行监听器", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME" : "名称", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME.PLACEHOLDER" : "输入一个名称", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION" : "表达式", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE" : "字符串值", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "输入一个字符串值", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING" : "字符串", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING.PLACEHOLDER" : "输入一个字符串", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.IMPLEMENTATION" : "实现", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EMPTY" : "未选择字段", + + "PROPERTY.FIELDS" : "{{length}} 字段", + "PROPERTY.FIELDS.EMPTY" : "未选择字段", + "PROPERTY.FIELDS.NAME" : "名称", + "PROPERTY.FIELDS.NAME.PLACEHOLDER" : "输入一个名称", + "PROPERTY.FIELDS.EXPRESSION" : "表达式", + "PROPERTY.FIELDS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.FIELDS.STRINGVALUE" : "字符串值", + "PROPERTY.FIELDS.STRINGVALUE.PLACEHOLDER" : "输入一个字符串值", + "PROPERTY.FIELDS.STRING" : "字符串", + "PROPERTY.FIELDS.STRING.PLACEHOLDER" : "输入一个字符串", + "PROPERTY.FIELDS.IMPLEMENTATION" : "实现", + + "PROPERTY.DATAPROPERTIES.VALUES" : "{{length}} data objects", + "PROPERTY.DATAPROPERTIES.EMPTY" : "没有配置data objects", + "PROPERTY.DATAPROPERTIES.ID" : "Id", + "PROPERTY.DATAPROPERTIES.ID.PLACEHOLDER" : "输入一个id", + "PROPERTY.DATAPROPERTIES.NAME" : "名称", + "PROPERTY.DATAPROPERTIES.NAME.PLACEHOLDER" : "输入一个名称", + "PROPERTY.DATAPROPERTIES.TYPE" : "类型", + "PROPERTY.DATAPROPERTIES.VALUE.PLACEHOLDER" : "输入一个值 (可选)", + "PROPERTY.DATAPROPERTIES.VALUE" : "默认值", + + "PROPERTY.FORMPROPERTIES.VALUE" : "{{length}} 表单属性", + "PROPERTY.FORMPROPERTIES.EMPTY" : "没有选择表单属性", + "PROPERTY.FORMPROPERTIES.ID" : "Id", + "PROPERTY.FORMPROPERTIES.ID.PLACEHOLDER" : "输入一个id", + "PROPERTY.FORMPROPERTIES.NAME" : "名称", + "PROPERTY.FORMPROPERTIES.NAME.PLACEHOLDER" : "输入一个名称", + "PROPERTY.FORMPROPERTIES.TYPE" : "类型", + "PROPERTY.FORMPROPERTIES.DATEPATTERN" : "日期格式", + "PROPERTY.FORMPROPERTIES.DATEPATTERN.PLACEHOLDER" : "输入日期格式", + "PROPERTY.FORMPROPERTIES.VALUES" : "值", + "PROPERTY.FORMPROPERTIES.ENUMVALUES.EMPTY" : "未选择枚举值", + "PROPERTY.FORMPROPERTIES.VALUES.ID" : "Id", + "PROPERTY.FORMPROPERTIES.VALUES.NAME" : "名称", + "PROPERTY.FORMPROPERTIES.VALUES.ID.PLACEHOLDER" : "输入id值", + "PROPERTY.FORMPROPERTIES.VALUES.NAME.PLACEHOLDER" : "输入名称值", + "PROPERTY.FORMPROPERTIES.EXPRESSION" : "表达式", + "PROPERTY.FORMPROPERTIES.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.FORMPROPERTIES.VARIABLE" : "变量", + "PROPERTY.FORMPROPERTIES.VARIABLE.PLACEHOLDER" : "输入一个变量", + "PROPERTY.FORMPROPERTIES.DEFAULT" : "默认值", + "PROPERTY.FORMPROPERTIES.DEFAULT.PLACEHOLDER" : "输入一个默认值", + "PROPERTY.FORMPROPERTIES.REQUIRED" : "必须的", + "PROPERTY.FORMPROPERTIES.READABLE" : "可读的", + "PROPERTY.FORMPROPERTIES.WRITABLE" : "可写的", + + "PROPERTY.INPARAMETERS.VALUE" : "{{length}} in-parameters", + "PROPERTY.INPARAMETERS.EMPTY" : "没有配置in-parameters ", + + "PROPERTY.OUTPARAMETERS.VALUE" : "{{length}} out-parameters", + "PROPERTY.OUTPARAMETERS.EMPTY" : "没有配置out-parameters", + + "PROPERTY.PARAMETER.SOURCE" : "源", + "PROPERTY.PARAMETER.SOURCE.PLACEHOLDER" : "输入一个源", + "PROPERTY.PARAMETER.SOURCEEXPRESSION" : "源表达式", + "PROPERTY.PARAMETER.SOURCEEXPRESSION.PLACEHOLDER" : "输入一个源表达式", + "PROPERTY.PARAMETER.TARGET" : "目标", + "PROPERTY.PARAMETER.TARGET.PLACEHOLDER" : "输入一个目标", + "PROPERTY.PARAMETER.EMPTY" : "没有选择参数", + + "PROPERTY.PROCESSREFERENCE.EMPTY" : "没有选择引用", + "PROPERTY.PROCESSREFERENCE.TITLE" : "流程参考", + "PROPERTY.PROCESSREFERENCE.ERROR.PROCESS" : "加载流程出错。稍后再试一次", + "PROPERTY.PROCESSREFERENCE.PROCESS.LOADING" : "加载流程...", + "PROPERTY.PROCESSREFERENCE.PROCESS.EMPTY" : "此文件夹不包含流程", + + "PROPERTY.FORMREFERENCE.EMPTY" : "没有选择参考", + "PROPERTY.FORMREFERENCE.TITLE" : "表单引用", + "PROPERTY.FORMREFERENCE.DESCRIPTION" : "引用表单", + "PROPERTY.FORMREFERENCE.ERROR.FORM" : "加载表单出错。稍后再试一次", + "PROPERTY.FORMREFERENCE.FORM.LOADING" : "加载表单...", + "PROPERTY.FORMREFERENCE.FORM.EMPTY" : "此文件夹不包含表单", + + "PROPERTY.TASKLISTENERS.VALUE" : "{{length}}任务监听器", + "PROPERTY.TASKLISTENERS.EMPTY" : "没有配置任务监听器", + "PROPERTY.TASKLISTENERS.EVENT" : "事件", + "PROPERTY.TASKLISTENERS.CLASS" : "类", + "PROPERTY.TASKLISTENERS.CLASS.PLACEHOLDER" : "输入一个类名", + "PROPERTY.TASKLISTENERS.EXPRESSION" : "表达式", + "PROPERTY.TASKLISTENERS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION" : "委托表达式", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "输入一个委托表达式", + "PROPERTY.TASKLISTENERS.UNSELECTED" : "没有选择任务监听器", + "PROPERTY.TASKLISTENERS.FIELDS.NAME" : "名称", + "PROPERTY.TASKLISTENERS.FIELDS.NAME.PLACEHOLDER" : "输入一个名称", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION" : "表达式", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE" : "字符串值", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "输入一个字符串值", + "PROPERTY.TASKLISTENERS.FIELDS.STRING" : "字符串", + "PROPERTY.TASKLISTENERS.FIELDS.STRING.PLACEHOLDER" : "输入一个字符串", + "PROPERTY.TASKLISTENERS.FIELDS.IMPLEMENTATION" : "实现", + "PROPERTY.TASKLISTENERS.FIELDS.EMPTY" : "没有选择字段", + + "PROPERTY.EVENTLISTENERS.DISPLAY" : "{{length}} 事件监听器", + "PROPERTY.EVENTLISTENERS.EMPTY" : "没有配置事件监听器", + "PROPERTY.EVENTLISTENERS.EVENTS": "事件", + "PROPERTY.EVENTLISTENERS.RETHROW": "Rethrow event?", + "PROPERTY.EVENTLISTENERS.CLASS" : "类", + "PROPERTY.EVENTLISTENERS.CLASS.PLACEHOLDER" : "输入一个类名", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION" : "委托表达式", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "输入一个委托表达式", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE" : "实体类型", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE.PLACEHOLDER" : "输入一个实体类型", + "PROPERTY.EVENTLISTENERS.RETHROWTYPE": "Rethrow event type", + "PROPERTY.EVENTLISTENERS.ERRORCODE" : "错误码", + "PROPERTY.EVENTLISTENERS.ERRORCODE.PLACEHOLDER" : "输入一个错误码", + "PROPERTY.EVENTLISTENERS.MESSAGENAME" : "消息名称", + "PROPERTY.EVENTLISTENERS.MESSAGENAME.PLACEHOLDER" : "输入一个消息名称", + "PROPERTY.EVENTLISTENERS.SIGNALNAME" : "信号名称", + "PROPERTY.EVENTLISTENERS.SIGNALNAME.PLACEHOLDER" : "输入信号名称", + "PROPERTY.EVENTLISTENERS.UNSELECTED" : "没有选择事件监听器", + + "PROPERTY.PLANITEMLIFECYCLELISTENERS.VALUE" : "{{length}} lifecycle listeners", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EMPTY" : "No lifecycle listeners configured", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EVENT" : "Event", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.SOURCE_STATE" : "Source state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.TARGET_STATE" : "Target state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS" : "Class", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.UNSELECTED" : "No task listener selected", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME" : "Name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING" : "String", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.IMPLEMENTATION" : "Implementation", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EMPTY" : "No Field selected", + + "PROPERTY.SIGNALDEFINITIONS.DISPLAY" : "{{length}} 信号定义", + "PROPERTY.SIGNALDEFINITIONS.EMPTY" : "没有配置信号定义", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-GLOBAL": "全局", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-PROCESSINSTANCE": "流程实例", + "PROPERTY.SIGNALDEFINITIONS.ID" : "Id", + "PROPERTY.SIGNALDEFINITIONS.NAME" : "名称", + "PROPERTY.SIGNALDEFINITIONS.SCOPE" : "Scope", + + "PROPERTY.MESSAGEDEFINITIONS.DISPLAY" : "{{length}} 消息定义", + "PROPERTY.MESSAGEDEFINITIONS.EMPTY" : "没有配置消息定义", + "PROPERTY.MESSAGEDEFINITIONS.ID" : "Id", + "PROPERTY.MESSAGEDEFINITIONS.NAME" : "名称", + + "PROPERTY.SEQUENCEFLOW.ORDER.EMPTY" : "没有确定连线的顺序", + "PROPERTY.SEQUENCEFLOW.ORDER.NOT.EMPTY" : "设置连线的顺序", + "PROPERTY.SEQUENCEFLOW.ORDER.NO.OUTGOING.SEQUENCEFLOW.FOUND" : "没有发现流出连线.", + "PROPERTY.SEQUENCEFLOW.ORDER.DESCRIPTION" : "设置需要评估连线的顺序:", + "PROPERTY.SEQUENCEFLOW.ORDER.SEQUENCEFLOW.VALUE" : "连线到 {{targetType}} {{targetTitle}}", + + "PROPERTY.SEQUENCEFLOW.CONDITION.TITLE" : "连线条件", + "PROPERTY.SEQUENCEFLOW.CONDITION.STATIC" : "条件表达式", + "PROPERTY.SEQUENCEFLOW.CONDITION.NO-CONDITION-DISPLAY": "没有设置条件", + + "PROPERTY.DUEDATE.EMPTY" : "没有到期", + "PROPERTY.DUEDATE.DEFINED" : "定义到期日", + "PROPERTY.DUEDATE.TITLE" : "到期日", + "PROPERTY.DUEDATE.EXPRESSION-LABEL" : "到期日表达式", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.NO-DUEDATE" : "没有到期日", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.EXPRESSION" : "表达式定义", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.STATIC" : "任务创建后的固定持续时间", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.FIELD" : "基于字段", + + "MODEL.SAVE.TITLE" : "保存模型", + "MODEL.VALIDATE.TITLE" : "验证结果", + "MODEL.NAME" : "名称", + "MODEL.KEY" : "Key", + "MODEL.DESCRIPTION" : "描述", + "MODEL.SAVE.NEWVERSION" : "将此保存为新版本?这意味着你可以回到以前的版本。", + "MODEL.SAVE.COMMENT" : "评论", + "MODEL.SAVE.SAVING" : "正在保存模型", + "MODEL.LASTMODIFIEDDATE" : "最后保存", + "MODEL.SAVE.ERROR": "Unexpected error: 不能保存模型", + "MODEL.VALIDATIONERRORS": " 注意,模型包含验证错误。这意味着该模型在当前状态下不能部署在Flowable引擎上。", + "MODEL.CONFLICT.WRITE": "不能保存模型: '{{userFullName}}'对该模型进行了更改", + "MODEL.CONFLICT.WRITE.OPTIONS": "选择一个选项来解决此冲突:", + "MODEL.CONFLICT.WRITE.OPTION.OVERWRITE": "覆盖其他模型", + "MODEL.CONFLICT.WRITE.OPTION.DISCARDCHANGES": "放弃我的改变", + "MODEL.CONFLICT.WRITE.OPTION.SAVEAS": "保存为新模型", + "MODEL.CONFLICT.WRITE.OPTION.NEWVERSION": "创建新版本", + "MODEL.CONFLICT.SAVEAS" : "另存为:", + + "EVENT_TYPE.ACTIVITY.COMPENSATE.TOOLTIP": "一项活动将作为对另一活动的补偿而被执行。事件针对即将执行的活动进行补偿。", + "EVENT_TYPE.ACTIVITY.COMPLETED.TOOLTIP": "一项活动已圆满完成。", + "EVENT_TYPE.ACTIVITY.ERROR.RECEIVED.TOOLTIP": "活动已接收到错误事件。在活动接收到实际错误之前发送", + "EVENT_TYPE.MEMBERSHIP.CREATED.TOOLTIP": "创建了新的membership", + "EVENT_TYPE.MEMBERSHIP.DELETED.TOOLTIP": "单个membership已被删除", + "EVENT_TYPE.MEMBERSHIPS.DELETED.TOOLTIP": "相关组中的所有成员已被删除。由于可能的原因,个别事件不会被派遣。", + "EVENT_TYPE.TASK.ASSIGNED.TOOLTIP": "一个任务已经被分配人了。这将抛出一个实体更新事件", + "EVENT_TYPE.TASK.COMPLETED.TOOLTIP": "一个任务已经被完成。在删除任务实体之前调度", + "EVENT_TYPE.UNCAUGHT.BPMNERROR.TOOLTIP": "当BPMN错误被抛出,但未在流程中捕获时", + "EVENT_TYPE.VARIABLE.CREATED.TOOLTIP": "已经创建了一个新的变量", + "EVENT_TYPE.VARIABLE.DELETED.TOOLTIP": "已删除现有变量", + "EVENT_TYPE.VARIABLE.UPDATED.TOOLTIP": "已更新现有变量", + + "PROPERTY.DECISIONTABLEREFERENCE.EMPTY" : "没有选择引用", + "PROPERTY.DECISIONTABLEREFERENCE.TITLE" : "决策表引用", + "PROPERTY.DECISIONTABLEREFERENCE.ERROR.FORM" : "加载决策表出现错误. 稍后再试一次", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.LOADING" : "加载决策表...", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.EMPTY" : "此文件夹不包含任何决策表", + + "PROPERTY.CASEREFERENCE.EMPTY" : "没有选择引用", + "PROPERTY.CASEREFERENCE.TITLE" : "案例型引用", + "PROPERTY.CASEREFERENCE.ERROR.FORM" : "加载案例模型时出错。稍后再试一次", + "PROPERTY.CASEREFERENCE.CASE.LOADING" : "加载案例模型...", + "PROPERTY.CASEREFERENCE.CASE.EMPTY" : "此文件夹不包含任何案例模型" +} diff --git a/snow-flowable/src/main/resources/static/images/android-chrome-192x192.png b/snow-flowable/src/main/resources/static/images/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..c1a85b6e756d6c8930b96b377f3d289b23159609 GIT binary patch literal 4310 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 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/images/favicon-32x32.png b/snow-flowable/src/main/resources/static/images/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..dc5e2cd3d5fcf27d8b569deabc8a4a3aa8dd5922 GIT binary patch literal 996 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-G$+Qd;gjJKpuOE zr>`sfLuN)%Mk{TtZ&5(`PEQxd5RccnkXq?r6k6lBrNA)@)M#7BQ!3 zx>3VZlli{f>%12~;cR+vEH(N4v98NE7&$Ka@^AJmOGxM5zcVAJK%G5T=H}d37Ke_i zch$#t&zKeemPsgLTCh%Q-Q#x;46fz(Uc7d%>$JD3*rb`q_}C`?{Cs)R%y5C;+JrOC z?me?uY)c*ozFVy`>*@nrc3p9H@5mXMPtyWJg3mpBTPt31XiX-&)Mg&#&QF@0*FIh- z{CsKptpbI%xfh)3)_t}qbXL1NZR1t59aZOE^o70q;mm8IDyvz&Nx3m0?&K}abFQjP zxBevbi-^^5dS)*^cfG!st?8m4f53zw_FXTOE@@?7c@^e&$@^lG?2IylL&kPODm}-| zMONo6ZL9XtJJ&KPVTx7dLqT)nh!@L`vc#X;uNs-LXsP=uNu#66AMPAc(eQqw`bRHz zho&P3Q{lzhJHCA8svLSfc?qgZW-RC}vyXqgXp@MHju0Pn?wn7&aj^?3zuw+5S@N#; zv`1Gr^4d%-+nmF5`uSF+nFiBOHvC|BUA%MAtLg7|Yu);ruqACT2{eHrWbAldc19!@#PXr?)FK#IZ0 zz|dURz*yJ7FvQ5v%D~Xd)Iu9b8W=E%s~<9nO2EgL$TNVYM_Sjs*s41pu}>8 zf};Gi%$!t(lFEWqh0KDIWCn(cIgdZ_a1@4VXq@stea7=?5CgL^w_Y;0u(GiCWD#az z1(ybs!zs+ln?n>%-?(z($eANDN7zp{cr5VJV|XPlSn|oqbSlsa22WQ%mvv4FO#t&t Bn&1Ec literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/images/flowable-logo.png b/snow-flowable/src/main/resources/static/images/flowable-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..cf49ee74068e34a945478f47e9de7b011e8d7dfa GIT binary patch literal 11874 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 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/images/flowable-logo@2x.png b/snow-flowable/src/main/resources/static/images/flowable-logo@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..13938c0edba10919ca89817038c7203ac731389d GIT binary patch literal 25782 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 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/images/form-builder/amountfield-icon.png b/snow-flowable/src/main/resources/static/images/form-builder/amountfield-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1f4b7c7d3cb2bf67ca81e920055d32f2c220c06c GIT binary patch literal 3174 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 M07*qoM6N<$f^@3i#Q*>R literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/images/form-builder/booleanfield-icon.png b/snow-flowable/src/main/resources/static/images/form-builder/booleanfield-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8933752fb4ac3206945e15fa1bec78374fa0c0a1 GIT binary patch literal 694 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 M07*qoM6N<$f^@3i#Q*>R literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/images/form-builder/dropdownfield-icon.png b/snow-flowable/src/main/resources/static/images/form-builder/dropdownfield-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c76a2413062b0e4b7cc71cd50c497cd45dd39637 GIT binary patch literal 492 zcmV8b&mn&ZguBcAevtdPJ4Qrs8Sa$c z2>b^DQNF}+yytmdAHa@f=5wCsgYkI$1OTkvZi`l{H2{!U23Ipo)3h(5D3V09X*d8R zVHi#X5uFwdhKOXAWjE95^xX!r)9HvX3{Mzi*8n(U?2Jh%b1WC*o!0v3Cle{9&H+Gc zeYuW^QtB4KAppbiQ3)?A%yCdW>!xIJ=VjOkh-yQx*E=@GY}XCuoWG4mqlr}kB6=;# zWUJCOC!+3O!hxD!ptXJg&;>C63lpi<;HsXMd|v6mX?o9TAa1k)hNzWqeoAIqrAuN-s-2O6p{cHcp{{{th@pv;f_?Qgd=aTm@r2V~9>bV(99f^K%P|Qj3d0>P?~Qk;Tx}2c;J0=ahns56#Ogu`_~dK@&#T6^W3yGl%Ix z7DU$&flULlAd&`9G+2SdDZ(W)H#HCJ7h|9;SS8RkI_Kx)7X=q2CZ~eJ3#-F2kp2@7ah=JU|>4z>Eaj?!TEHWb@miT zk+$!Xdc{Tdxa2U2X--*iu_FQqHO$0bZHoNEc&+J&vdahdh~460xvqlTH?>+T+_||A zI&o(8G#x7~uf6whw!Zr5GkT0SS&Ry17{9N4KIikrPvgk_)-c$=`)_L#L zb3AtAgf$`B$2@D6nr?U$e86?`yVf~3uboe;42v&hD*N>RLN3$GO)WB;zszO%FT5#w z_QPWsjGHv7d`|0biugTMO+;w;SSCX9l z*TDY%w@jVc4XQl8@xh!+(v3g;%zY@c^=QZ4TQcUynEjJ??p<(T9;2MYvtK^9+I;ON z#S4DdW7+X5_jaSk$)62(ovS+Hf>yN0Y%Hi*S6H)-S?)`Z-Cic1EUznnOWZoniy9|I br+=`ou)FwXk&DGeP&MP}>gTe~DWM4fljxl6 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/images/form-builder/group-icon.png b/snow-flowable/src/main/resources/static/images/form-builder/group-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..31703862797b8b9b5de4a02f4e7e9b6685feea9d GIT binary patch literal 305 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmSQK*5Dp-y;YjHK@;M7UB8wRq zgi1h|@m`vI1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWIZto-U3d z5v^~h9~3-fz{BD%^{T5^z_!HZ$@IGIi+Asw=o$L( z=Z#QX28NhziqGeCW^5D)y}EPjH9iIg>S~nz0ZyX_d5yo>?ihcFcQIG0ieTtCA$`EoNrHh&P;Ay u(b047cNIfNwZc2b_2U1T%DL}2|6pZ#m1x|1?0YBB-YWr^}8>&oDE+S@lj&>O&?}irp0^`r3~CNf4x#t zQhIfP_5a`B=2EOB-AqATi!N$Nlpa{Y%(k7`?VyGPD>EO%6*nmr7qcsjKsy;cUHx3v IIVCg!0QB%h5&!@I literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/images/form-builder/headline-with-line-icon.png b/snow-flowable/src/main/resources/static/images/form-builder/headline-with-line-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce7e9b68d1d3ea4f27cb09b4347f60249845da83 GIT binary patch literal 229 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v_d#0*}aI z1_r*vAk26?e?l#Bv_ewBsv2{1O*Fw z8XFxMJy&EN?GiPAlHvH@o)s}l~G&^&FbHWwI#e4~h!SS&!E-tdW z9_+9G@3y!hFVMlu(L{=MF`q=~fd^#=G$ekQCAzpA*?cj^;8jDQ0T-JP14ECmjP!IS Re|ezo44$rjF6*2UngH4ANnrp0 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/images/form-builder/horizontal-line-icon.png b/snow-flowable/src/main/resources/static/images/form-builder/horizontal-line-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..910a352ee6fbe3d3daf398a255e9976722c58625 GIT binary patch literal 161 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v_d#0*}aI z1_r*vAk26?e?o&hR9%K%h0c@&*Q-&({Zm z6t7V61UA9P8x;xAU?egSL4k2-44E1PLUT~EPa1_yf^cXtbQX$(fi5agvTwN=4uvdA z*wGj$!N(us3NR@UTi7<3H597>fk4nqaujMe&V3n|jWE!IY&HW0hbJT?z!H!!fO!Cp zaBy&dTid{GY^-DoD;Af|CULCjER&^4KFououp*gM2Ac}dA@X@i5kMRp1BJ>1{r4=d zlg9Wj5S_K0l`KCvhs1y*VAk+YL2PQ&$L0MGCHH(5qj0F7!Q`GLY_S+iYedT`it+)- z)F>{F#HL_vtP!?W)(9(W2RvdM${K+}*rMU9G#@iuq+OX55*uLR0U!qJPvuZzX!0Qh z2}3TCEBz}_c@`)?CY2&9ue^v@1RDN-w$*x9fW}}_SS-0-wy;J0O51AvZVC&CiIYzs zM5nT`Hp|E=^J<)Tr1_U`zuFIU3fArj2ng8AWWLrtefqSm?^P)#uU$|i5X8NX&=1&Pxb{F< zb+!F=ELN0dtK~XY(2f!W#F9zLI6 zp`xmKHJJG{+xX>dVtGkP$)Selt_@w?ewCm)KF!m|2V;Xq8xba(Odb3Q1bqw=DOCUo zt&J=O^A}FGY2BS)W1g9jt8Hj_nC9#2>zACoP-EKL{cyc`swCk`aq+nFc+!JrLbTJ- zhgG+3O@pd0TtD7omT|U2EUv?q?i_*)fZMG)wVw2n7c-u8118lO|G?hgqG>8uQEVO&gPBwNhA(CUuYiut-C!v^qR;7s%qco zyEZ>XR9H`okAM5DxVU&ry0@@zLKJA*2+GOHA>U74Tiem?bNfP>=*WTZ<|;U$p?#tH zf7|c7s`l!8b#--3OFUM|FvF-w8cihraI%P(^^eaklMDyWnbtu`z9Fuo z2h(*_qvX&Tyx`18g-a50-Cm*Trsq1ky6fL6W`d{hSAgfjx7yeCniTx3XKdVm^qz4C zQa!<-;c#Z_UAx=B@gBXx>Bxu(bNg(|7MI2aat!=&TzjK{(YzV26Pw|q&&zaBnTsB} zQC(eq`EhM<;o}#TQXv=~KK^B7)U#6FoBY{8ixgx$NhdfsxV-3B4T9stvjL8c#6AA~ zNz(W8T_%rodR~KH?t=<08ZgSMs_+eYp^zSugBF4X!a>l|&8<#Z!{ z+BnkOocG52y;}eF9mfC>^SIGQl7AM>4LBeqR_0$YMwOP9MsRvBQ9S;vE1B?6quDl- z&-L&7E^Kb+31l}IL@mvHTUE`DA1Wq#US_@N0d@$ zboq4h#G6bV|7Ki$ASN}qP;0wRZ+k%1*JPr3ie0v%Ie}!?mr__*2mos-Syc6>F=+n0V$akMlFd~^L|T927mt;bIc&7rhA zjHU?%RkBxd#ZXghXGncuOS;k;H?8*0>({RuU7j%y@wnJNrE8b%(DXnVNR{D9F(^xzcTnK3-!`_&z`)bngt+QC#4>IYIvsa T7g5hH`Ok`%n=h{1CH&aGD(=7g literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/images/form-builder/multi-line-textfield-icon.png b/snow-flowable/src/main/resources/static/images/form-builder/multi-line-textfield-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..76e992a591368313bedb0b4f69ff5a4c514e5f15 GIT binary patch literal 489 zcmV->$%v|wrGiY;a{wR& zh~v1Vs#ib@sCdqN0d7R(y3^^rNfbpTRUH6j&%x_@6_Hw)oV*O6s$-xhBJVyDRW$@o zMPwf+tLjzA=e47%;GCQI2v1e7*Y}FW;wXV=g?!h%=bW2FQS{?uu-3{p0i1Ia zV@wY?2P$7(kY2m0MnE6vCw}W%E%8PhcDvm!Fak!2_o~eQfgE51z!+nIIWSMWSB2{v zB4StkCE)cTZUAh%?|;+ZdjmN@4v+(60WeMc(GGLdtZ4|`0~bIwj^kV4VYys-8JB_} z5a0}`0*J_+7-MR{BfBrh5;zI0wF96540jkl1RB=bfvgUv&1Um>u~;1XOfD1(&+T^m fDP7CIpN>BOJT-dt-h8S$00000NkvXXu0mjf-CW1V literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/images/form-builder/numberfield-icon.png b/snow-flowable/src/main/resources/static/images/form-builder/numberfield-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8edac39865cecd4fae3ea5bba8826b0c171bfc13 GIT binary patch literal 521 zcmV+k0`~ohP)DqY)ai6&v)LQ~h-)S;VmP1A`?A$)DQ4a_IRL~_ z6x~T?zHkpLGpjUBZzq$dUSMVo078g2Ywg~qXQ5O;k|f^>jn;aj0=%cd zyMUDxEaiOmQ$Vrb?FH?;y>2y>04zRdA_P`*Uc@i`Rri1#p|h5hQjY*m;9)xk@I+ec zn3-?tAS?qj$3Yl|&y7ao5Ww-4`G;wmUQ>QE@^&cQUCnj^d<*yhEZ(mhM9LnY00000 LNkvXXu0mjfr25pb literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/images/form-builder/password-icon.png b/snow-flowable/src/main/resources/static/images/form-builder/password-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a8d098186e4ea607345fa7705a5203f0bb72beae GIT binary patch literal 1021 zcmV|VJRM@UvO>^Jj%^M1eYee=DYk1!a>T6-M8tg04N zb)1=1MD8-PFCwK{t#)&ug#8lp`TXH1ioPMDd=gJY766>8)oQ=>lb8D;<#M@~L}Vcr z{|mrJQ4~GDxw*MN48t@LJqO@J0Dm&`G&5I>F~|DJ-LnGueEx7et1$pqUDrM1`~G?- z?&Rd;zH~bM6%m~Ta9>1T=v9eSFN1N}#{gUng5V7RYOS47)eA&4B_a+pFRJRLYPEU| zz^pL_M0Apw=KvIv1QM6PT6?@%cGq>!08nGhMG?73M3-FGJs3sN0TKC3RX?%TehNU- z>GW9XZ0ElSH zb=_Ot_!}D=w?t$L06foI1psCqAKCyjKL!9RD=YWoTVvgJK$FMJPXNID{QTeXZFgt` z4+H-j*wqOqCMMiWCi6LfHvwcvAtEAmBKo#oufMmpw$^Bk?dk)u_&cKzZi1OT0Ovf< z1Az012Cy@80GJMfpfU;r#+Yd$x=loHwHxU44rBpfRN??otyUM}VWvIy$X~)oZlKqn zQCH-0xmN*PVP*yJb`S*Dhsm>-3S4340|1@`@a3>c_F|y5$3Oni4KQ=LITjIrlm@nd zosO9FpsHSLx%@tfTPzmS@vzYz+hssR?gBtIn|&rJ>Gt+^NmcKt>K)g0zf0nVVR$GW z{?Q)WwF{Wp2k^9roB;4^x1`I<%MSqLl7yRZ9OspISZ#P0G<+&au5VRw-dTGqEi4W0A9D&s^d6k zE0s!p5M^s^MpfsC=rs{pPo+|)J38!^z!-Ckh<*UDPekq!(PdS=;d$O_%lF=YP%IYH zVHh5Y*Ze$oX1?w?&WWX^rTKvj06;F6dp17Z97*DJgNT$e2W!yIYTFU}vk90hBtec{~0ArSNh9q3m>400000NkvXXu0mjf@fFN2eu~3mkcyGc& z(85B&pF%9fLP0A{ZD|lB7>EdBAp{bWoxp-!P|`>WjiOd+AP|3IklkVCSm-W`zWGUZ zWi33_@a}o{etYk{d908`E9JDb`hS3b0iZ3-;CWsjfJ-C~h)5^Nj{qhd#~GcPnwn4A ztF@jGkwYY3O;1nv**u9IFvi>@`IO{I0J}+U0k99iwJ3__wALq*_KQddfK4LO8Rv-w z&|04Za5*7=yNEn6#vDt6NK@w)k4E3p8%T&}&Vt7~tTUmzj}tIy?f`LFEWaY%z4#0LjMy7OLwaatgo>081o?>(*pM`DG3Ek*J2Bykh#W2!i_a1OQk4ks3*sGs zU6#;Y-}lcqQXI&38-BMfk_;Lx4y1ITzrTNf6h+Tt!rxri-99-v`Lz*%*be0L`Hm=x zhU4M@I>Io#WsKR-bO5dOQKeJ~fb|Zq(-{DBp67WYB5MJtjbLza(3zQ;IZpB_fZQ5# zy&*XghT&+bRC>Q^0AtJz0N2-0_;-aQi>~XAEG{mN&(6*!zO3~laGOvZ09+9%L{app zySw{fnzRs@+)$)HvEeH4kZ1m=E TKN}{t00000NkvXXu0mjfE_G7m literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/images/form-builder/readonly-icon.png b/snow-flowable/src/main/resources/static/images/form-builder/readonly-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0b11705b1c777bbefa74087d39215a456e0fd874 GIT binary patch literal 497 zcmV4-jijhOzBgB zNe~E!NvTwt3xc2u%p}Zwj^p^S(P%sZNTE;&bGh6hu$3@)G>$r*PBqNu^V)l#HXL9p zilVE~d%rU%IPbmgcDv`zX7eoxVzF2ZqbS-Ckz+uK$gXIuWBQlz##+0U1b8%zG1tH< z;1nN|@R|mEgrzbc!^{Q3?~2BlJz(XJS+~~OgVEw-?!dtGi*0HG#+YMZbIe{R)>{21 z0wS{SoVysOky7eqT=jkT0aj9kO~Ma0YAx^W}2+2)K04 zCGu2ON(rzI%mawXsc5a2fIHGZ4hJkNYi*nU%s-?Ee*iYEwQc$QF{xB4i*X#!CP@y0 n;Hg%t-4E9?{TWRK{=L9E##w9VEe&ln00000NkvXXu0mjfE3?*# literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/images/form-builder/readonly-text-icon.png b/snow-flowable/src/main/resources/static/images/form-builder/readonly-text-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1cc9f19c8943a973407285677e9e9c2d427efb38 GIT binary patch literal 301 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmSQK*5Dp-y;YjHK@;M7UB8wRq zgi1h|@m`vI1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWIZNo-U3d z5v^~hALKo(z~lOM{ke;dMjS!nOSGCNSYC2`6DQOeHzDbg5bJ(n^&cI}^AE1_vUR+E z*|vdQVbSev9Ex`seWv-ks4Smy&zF(G=ggliIZO{6U6wICuVfND`P#QkS?Q)!!*;ct z!UIeVs>dwkA2qOs)(T#%;bqrhh}g&UXHt~^pQDXY{yh&J)~fRr9!PiOPCnOkX{O%h q1trg<_}(lnY5SZ0gt3kP1LNO6i2@pe2VVnS&EVVGd000McNliru;sg;2D+U<(TbTd=0bfZ( zK~z}7?bbg}R6!I4@E>p4EX0Jw2t=W=vD?BgVBwe0X=vzWTTA^6w6r9**UsLCb_)^% z2_&vc!ygH(ECideA}E-Pr3x*|*|EoI&eUgABLZ=oMy1&8>JUPK%Xi*y*)F^{LX#_Ry@95!)+<81oX zeXrnSZn;Jls1G@B4v#Z$WfV2Ajkh?!#U1!P{J?5n?`I$)F7Oj?(8&UW#J}SmenrHe zkxjysQXPxQVTl~aWa;FK{nCIUGX`a=;2!y z-;0QDne%F84Yb?st7fwaU-25}_<(j<@e0+myfRQd%O3>(0we!Y(h}oIX8-^I07*qo IM6N<$f&(nW(EtDd literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/images/form-builder/textfield-icon.png b/snow-flowable/src/main/resources/static/images/form-builder/textfield-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..92526b2f2e7b1f14f1f9a432b81c083c85541763 GIT binary patch literal 434 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 Ux2a*LX7{U#G`wn1p=Tfd4=mNw)Bpeg literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/images/line.png b/snow-flowable/src/main/resources/static/images/line.png new file mode 100644 index 0000000000000000000000000000000000000000..31a2b968c2d0ce5cffdfdd6059ba4fc0db0acb12 GIT binary patch literal 147 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 + + + +Created by potrace 1.11, written by Peter Selinger 2001-2013 + + + + + diff --git a/snow-flowable/src/main/resources/static/images/tour/open-group.gif b/snow-flowable/src/main/resources/static/images/tour/open-group.gif new file mode 100644 index 0000000000000000000000000000000000000000..e78b4966713c73ca2dbc00a1cf97519d82c99ee8 GIT binary patch literal 44216 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 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/images/tour/sequenceflow-bendpoint.gif b/snow-flowable/src/main/resources/static/images/tour/sequenceflow-bendpoint.gif new file mode 100644 index 0000000000000000000000000000000000000000..b088c86e47c0893e82cd751ce3d184414bd6ace8 GIT binary patch literal 74199 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 literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/images/tour/tour-dnd.gif b/snow-flowable/src/main/resources/static/images/tour/tour-dnd.gif new file mode 100644 index 0000000000000000000000000000000000000000..24fb73bf11bd5c59a604409f20db749d38bd3610 GIT binary patch literal 81854 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 Ofd9Li^>HFWoBj>oAb literal 0 HcmV?d00001 diff --git a/snow-flowable/src/main/resources/static/index.html b/snow-flowable/src/main/resources/static/index.html new file mode 100644 index 0000000..849ad97 --- /dev/null +++ b/snow-flowable/src/main/resources/static/index.html @@ -0,0 +1,277 @@ + + + + + + + + + + Flowable Modeler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ * + * ### CSS Staggering Animations + * A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a + * curtain-like effect. The ngAnimate module (versions >=1.2) supports staggering animations and the stagger effect can be + * performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for + * the animation. The style property expected within the stagger class can either be a **transition-delay** or an + * **animation-delay** property (or both if your animation contains both transitions and keyframe animations). + * + * ```css + * .my-animation.ng-enter { + * /* standard transition code */ + * -webkit-transition: 1s linear all; + * transition: 1s linear all; + * opacity:0; + * } + * .my-animation.ng-enter-stagger { + * /* this will have a 100ms delay between each successive leave animation */ + * -webkit-transition-delay: 0.1s; + * transition-delay: 0.1s; + * + * /* in case the stagger doesn't work then these two values + * must be set to 0 to avoid an accidental CSS inheritance */ + * -webkit-transition-duration: 0s; + * transition-duration: 0s; + * } + * .my-animation.ng-enter.ng-enter-active { + * /* standard transition styles */ + * opacity:1; + * } + * ``` + * + * Staggering animations work by default in ngRepeat (so long as the CSS class is defined). Outside of ngRepeat, to use staggering animations + * on your own, they can be triggered by firing multiple calls to the same event on $animate. However, the restrictions surrounding this + * are that each of the elements must have the same CSS className value as well as the same parent element. A stagger operation + * will also be reset if more than 10ms has passed after the last animation has been fired. + * + * The following code will issue the **ng-leave-stagger** event on the element provided: + * + * ```js + * var kids = parent.children(); + * + * $animate.leave(kids[0]); //stagger index=0 + * $animate.leave(kids[1]); //stagger index=1 + * $animate.leave(kids[2]); //stagger index=2 + * $animate.leave(kids[3]); //stagger index=3 + * $animate.leave(kids[4]); //stagger index=4 + * + * $timeout(function() { + * //stagger has reset itself + * $animate.leave(kids[5]); //stagger index=0 + * $animate.leave(kids[6]); //stagger index=1 + * }, 100, false); + * ``` + * + * Stagger animations are currently only supported within CSS-defined animations. + * + * ## JavaScript-defined Animations + * In the event that you do not want to use CSS3 transitions or CSS3 animations or if you wish to offer animations on browsers that do not + * yet support CSS transitions/animations, then you can make use of JavaScript animations defined inside of your AngularJS module. + * + * ```js + * //!annotate="YourApp" Your AngularJS Module|Replace this or ngModule with the module that you used to define your application. + * var ngModule = angular.module('YourApp', ['ngAnimate']); + * ngModule.animation('.my-crazy-animation', function() { + * return { + * enter: function(element, done) { + * //run the animation here and call done when the animation is complete + * return function(cancelled) { + * //this (optional) function will be called when the animation + * //completes or when the animation is cancelled (the cancelled + * //flag will be set to true if cancelled). + * }; + * }, + * leave: function(element, done) { }, + * move: function(element, done) { }, + * + * //animation that can be triggered before the class is added + * beforeAddClass: function(element, className, done) { }, + * + * //animation that can be triggered after the class is added + * addClass: function(element, className, done) { }, + * + * //animation that can be triggered before the class is removed + * beforeRemoveClass: function(element, className, done) { }, + * + * //animation that can be triggered after the class is removed + * removeClass: function(element, className, done) { } + * }; + * }); + * ``` + * + * JavaScript-defined animations are created with a CSS-like class selector and a collection of events which are set to run + * a javascript callback function. When an animation is triggered, $animate will look for a matching animation which fits + * the element's CSS class attribute value and then run the matching animation event function (if found). + * In other words, if the CSS classes present on the animated element match any of the JavaScript animations then the callback function will + * be executed. It should be also noted that only simple, single class selectors are allowed (compound class selectors are not supported). + * + * Within a JavaScript animation, an object containing various event callback animation functions is expected to be returned. + * As explained above, these callbacks are triggered based on the animation event. Therefore if an enter animation is run, + * and the JavaScript animation is found, then the enter callback will handle that animation (in addition to the CSS keyframe animation + * or transition code that is defined via a stylesheet). + * + * + * ### Applying Directive-specific Styles to an Animation + * In some cases a directive or service may want to provide `$animate` with extra details that the animation will + * include into its animation. Let's say for example we wanted to render an animation that animates an element + * towards the mouse coordinates as to where the user clicked last. By collecting the X/Y coordinates of the click + * (via the event parameter) we can set the `top` and `left` styles into an object and pass that into our function + * call to `$animate.addClass`. + * + * ```js + * canvas.on('click', function(e) { + * $animate.addClass(element, 'on', { + * to: { + * left : e.client.x + 'px', + * top : e.client.y + 'px' + * } + * }): + * }); + * ``` + * + * Now when the animation runs, and a transition or keyframe animation is picked up, then the animation itself will + * also include and transition the styling of the `left` and `top` properties into its running animation. If we want + * to provide some starting animation values then we can do so by placing the starting animations styles into an object + * called `from` in the same object as the `to` animations. + * + * ```js + * canvas.on('click', function(e) { + * $animate.addClass(element, 'on', { + * from: { + * position: 'absolute', + * left: '0px', + * top: '0px' + * }, + * to: { + * left : e.client.x + 'px', + * top : e.client.y + 'px' + * } + * }): + * }); + * ``` + * + * Once the animation is complete or cancelled then the union of both the before and after styles are applied to the + * element. If `ngAnimate` is not present then the styles will be applied immediately. + * + */ + +angular.module('ngAnimate', ['ng']) + + /** + * @ngdoc provider + * @name $animateProvider + * @description + * + * The `$animateProvider` allows developers to register JavaScript animation event handlers directly inside of a module. + * When an animation is triggered, the $animate service will query the $animate service to find any animations that match + * the provided name value. + * + * Requires the {@link ngAnimate `ngAnimate`} module to be installed. + * + * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application. + * + */ + .directive('ngAnimateChildren', function() { + var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren'; + return function(scope, element, attrs) { + var val = attrs.ngAnimateChildren; + if (angular.isString(val) && val.length === 0) { //empty attribute + element.data(NG_ANIMATE_CHILDREN, true); + } else { + scope.$watch(val, function(value) { + element.data(NG_ANIMATE_CHILDREN, !!value); + }); + } + }; + }) + + //this private service is only used within CSS-enabled animations + //IE8 + IE9 do not support rAF natively, but that is fine since they + //also don't support transitions and keyframes which means that the code + //below will never be used by the two browsers. + .factory('$$animateReflow', ['$$rAF', '$document', function($$rAF, $document) { + var bod = $document[0].body; + return function(fn) { + //the returned function acts as the cancellation function + return $$rAF(function() { + //the line below will force the browser to perform a repaint + //so that all the animated elements within the animation frame + //will be properly updated and drawn on screen. This is + //required to perform multi-class CSS based animations with + //Firefox. DO NOT REMOVE THIS LINE. + var a = bod.offsetWidth + 1; + fn(); + }); + }; + }]) + + .config(['$provide', '$animateProvider', function($provide, $animateProvider) { + var noop = angular.noop; + var forEach = angular.forEach; + var selectors = $animateProvider.$$selectors; + var isArray = angular.isArray; + var isString = angular.isString; + var isObject = angular.isObject; + + var ELEMENT_NODE = 1; + var NG_ANIMATE_STATE = '$$ngAnimateState'; + var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren'; + var NG_ANIMATE_CLASS_NAME = 'ng-animate'; + var rootAnimateState = {running: true}; + + function extractElementNode(element) { + for (var i = 0; i < element.length; i++) { + var elm = element[i]; + if (elm.nodeType == ELEMENT_NODE) { + return elm; + } + } + } + + function prepareElement(element) { + return element && angular.element(element); + } + + function stripCommentsFromElement(element) { + return angular.element(extractElementNode(element)); + } + + function isMatchingElement(elm1, elm2) { + return extractElementNode(elm1) == extractElementNode(elm2); + } + var $$jqLite; + $provide.decorator('$animate', + ['$delegate', '$$q', '$injector', '$sniffer', '$rootElement', '$$asyncCallback', '$rootScope', '$document', '$templateRequest', '$$jqLite', + function($delegate, $$q, $injector, $sniffer, $rootElement, $$asyncCallback, $rootScope, $document, $templateRequest, $$$jqLite) { + + $$jqLite = $$$jqLite; + $rootElement.data(NG_ANIMATE_STATE, rootAnimateState); + + // Wait until all directive and route-related templates are downloaded and + // compiled. The $templateRequest.totalPendingRequests variable keeps track of + // all of the remote templates being currently downloaded. If there are no + // templates currently downloading then the watcher will still fire anyway. + var deregisterWatch = $rootScope.$watch( + function() { return $templateRequest.totalPendingRequests; }, + function(val, oldVal) { + if (val !== 0) return; + deregisterWatch(); + + // Now that all templates have been downloaded, $animate will wait until + // the post digest queue is empty before enabling animations. By having two + // calls to $postDigest calls we can ensure that the flag is enabled at the + // very end of the post digest queue. Since all of the animations in $animate + // use $postDigest, it's important that the code below executes at the end. + // This basically means that the page is fully downloaded and compiled before + // any animations are triggered. + $rootScope.$$postDigest(function() { + $rootScope.$$postDigest(function() { + rootAnimateState.running = false; + }); + }); + } + ); + + var globalAnimationCounter = 0; + var classNameFilter = $animateProvider.classNameFilter(); + var isAnimatableClassName = !classNameFilter + ? function() { return true; } + : function(className) { + return classNameFilter.test(className); + }; + + function classBasedAnimationsBlocked(element, setter) { + var data = element.data(NG_ANIMATE_STATE) || {}; + if (setter) { + data.running = true; + data.structural = true; + element.data(NG_ANIMATE_STATE, data); + } + return data.disabled || (data.running && data.structural); + } + + function runAnimationPostDigest(fn) { + var cancelFn, defer = $$q.defer(); + defer.promise.$$cancelFn = function() { + cancelFn && cancelFn(); + }; + $rootScope.$$postDigest(function() { + cancelFn = fn(function() { + defer.resolve(); + }); + }); + return defer.promise; + } + + function parseAnimateOptions(options) { + // some plugin code may still be passing in the callback + // function as the last param for the $animate methods so + // it's best to only allow string or array values for now + if (isObject(options)) { + if (options.tempClasses && isString(options.tempClasses)) { + options.tempClasses = options.tempClasses.split(/\s+/); + } + return options; + } + } + + function resolveElementClasses(element, cache, runningAnimations) { + runningAnimations = runningAnimations || {}; + + var lookup = {}; + forEach(runningAnimations, function(data, selector) { + forEach(selector.split(' '), function(s) { + lookup[s]=data; + }); + }); + + var hasClasses = Object.create(null); + forEach((element.attr('class') || '').split(/\s+/), function(className) { + hasClasses[className] = true; + }); + + var toAdd = [], toRemove = []; + forEach((cache && cache.classes) || [], function(status, className) { + var hasClass = hasClasses[className]; + var matchingAnimation = lookup[className] || {}; + + // When addClass and removeClass is called then $animate will check to + // see if addClass and removeClass cancel each other out. When there are + // more calls to removeClass than addClass then the count falls below 0 + // and then the removeClass animation will be allowed. Otherwise if the + // count is above 0 then that means an addClass animation will commence. + // Once an animation is allowed then the code will also check to see if + // there exists any on-going animation that is already adding or remvoing + // the matching CSS class. + if (status === false) { + //does it have the class or will it have the class + if (hasClass || matchingAnimation.event == 'addClass') { + toRemove.push(className); + } + } else if (status === true) { + //is the class missing or will it be removed? + if (!hasClass || matchingAnimation.event == 'removeClass') { + toAdd.push(className); + } + } + }); + + return (toAdd.length + toRemove.length) > 0 && [toAdd.join(' '), toRemove.join(' ')]; + } + + function lookup(name) { + if (name) { + var matches = [], + flagMap = {}, + classes = name.substr(1).split('.'); + + //the empty string value is the default animation + //operation which performs CSS transition and keyframe + //animations sniffing. This is always included for each + //element animation procedure if the browser supports + //transitions and/or keyframe animations. The default + //animation is added to the top of the list to prevent + //any previous animations from affecting the element styling + //prior to the element being animated. + if ($sniffer.transitions || $sniffer.animations) { + matches.push($injector.get(selectors[''])); + } + + for (var i=0; i < classes.length; i++) { + var klass = classes[i], + selectorFactoryName = selectors[klass]; + if (selectorFactoryName && !flagMap[klass]) { + matches.push($injector.get(selectorFactoryName)); + flagMap[klass] = true; + } + } + return matches; + } + } + + function animationRunner(element, animationEvent, className, options) { + //transcluded directives may sometimes fire an animation using only comment nodes + //best to catch this early on to prevent any animation operations from occurring + var node = element[0]; + if (!node) { + return; + } + + if (options) { + options.to = options.to || {}; + options.from = options.from || {}; + } + + var classNameAdd; + var classNameRemove; + if (isArray(className)) { + classNameAdd = className[0]; + classNameRemove = className[1]; + if (!classNameAdd) { + className = classNameRemove; + animationEvent = 'removeClass'; + } else if (!classNameRemove) { + className = classNameAdd; + animationEvent = 'addClass'; + } else { + className = classNameAdd + ' ' + classNameRemove; + } + } + + var isSetClassOperation = animationEvent == 'setClass'; + var isClassBased = isSetClassOperation + || animationEvent == 'addClass' + || animationEvent == 'removeClass' + || animationEvent == 'animate'; + + var currentClassName = element.attr('class'); + var classes = currentClassName + ' ' + className; + if (!isAnimatableClassName(classes)) { + return; + } + + var beforeComplete = noop, + beforeCancel = [], + before = [], + afterComplete = noop, + afterCancel = [], + after = []; + + var animationLookup = (' ' + classes).replace(/\s+/g,'.'); + forEach(lookup(animationLookup), function(animationFactory) { + var created = registerAnimation(animationFactory, animationEvent); + if (!created && isSetClassOperation) { + registerAnimation(animationFactory, 'addClass'); + registerAnimation(animationFactory, 'removeClass'); + } + }); + + function registerAnimation(animationFactory, event) { + var afterFn = animationFactory[event]; + var beforeFn = animationFactory['before' + event.charAt(0).toUpperCase() + event.substr(1)]; + if (afterFn || beforeFn) { + if (event == 'leave') { + beforeFn = afterFn; + //when set as null then animation knows to skip this phase + afterFn = null; + } + after.push({ + event: event, fn: afterFn + }); + before.push({ + event: event, fn: beforeFn + }); + return true; + } + } + + function run(fns, cancellations, allCompleteFn) { + var animations = []; + forEach(fns, function(animation) { + animation.fn && animations.push(animation); + }); + + var count = 0; + function afterAnimationComplete(index) { + if (cancellations) { + (cancellations[index] || noop)(); + if (++count < animations.length) return; + cancellations = null; + } + allCompleteFn(); + } + + //The code below adds directly to the array in order to work with + //both sync and async animations. Sync animations are when the done() + //operation is called right away. DO NOT REFACTOR! + forEach(animations, function(animation, index) { + var progress = function() { + afterAnimationComplete(index); + }; + switch (animation.event) { + case 'setClass': + cancellations.push(animation.fn(element, classNameAdd, classNameRemove, progress, options)); + break; + case 'animate': + cancellations.push(animation.fn(element, className, options.from, options.to, progress)); + break; + case 'addClass': + cancellations.push(animation.fn(element, classNameAdd || className, progress, options)); + break; + case 'removeClass': + cancellations.push(animation.fn(element, classNameRemove || className, progress, options)); + break; + default: + cancellations.push(animation.fn(element, progress, options)); + break; + } + }); + + if (cancellations && cancellations.length === 0) { + allCompleteFn(); + } + } + + return { + node: node, + event: animationEvent, + className: className, + isClassBased: isClassBased, + isSetClassOperation: isSetClassOperation, + applyStyles: function() { + if (options) { + element.css(angular.extend(options.from || {}, options.to || {})); + } + }, + before: function(allCompleteFn) { + beforeComplete = allCompleteFn; + run(before, beforeCancel, function() { + beforeComplete = noop; + allCompleteFn(); + }); + }, + after: function(allCompleteFn) { + afterComplete = allCompleteFn; + run(after, afterCancel, function() { + afterComplete = noop; + allCompleteFn(); + }); + }, + cancel: function() { + if (beforeCancel) { + forEach(beforeCancel, function(cancelFn) { + (cancelFn || noop)(true); + }); + beforeComplete(true); + } + if (afterCancel) { + forEach(afterCancel, function(cancelFn) { + (cancelFn || noop)(true); + }); + afterComplete(true); + } + } + }; + } + + /** + * @ngdoc service + * @name $animate + * @kind object + * + * @description + * The `$animate` service provides animation detection support while performing DOM operations (enter, leave and move) as well as during addClass and removeClass operations. + * When any of these operations are run, the $animate service + * will examine any JavaScript-defined animations (which are defined by using the $animateProvider provider object) + * as well as any CSS-defined animations against the CSS classes present on the element once the DOM operation is run. + * + * The `$animate` service is used behind the scenes with pre-existing directives and animation with these directives + * will work out of the box without any extra configuration. + * + * Requires the {@link ngAnimate `ngAnimate`} module to be installed. + * + * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application. + * ## Callback Promises + * With AngularJS 1.3, each of the animation methods, on the `$animate` service, return a promise when called. The + * promise itself is then resolved once the animation has completed itself, has been cancelled or has been + * skipped due to animations being disabled. (Note that even if the animation is cancelled it will still + * call the resolve function of the animation.) + * + * ```js + * $animate.enter(element, container).then(function() { + * //...this is called once the animation is complete... + * }); + * ``` + * + * Also note that, due to the nature of the callback promise, if any Angular-specific code (like changing the scope, + * location of the page, etc...) is executed within the callback promise then be sure to wrap the code using + * `$scope.$apply(...)`; + * + * ```js + * $animate.leave(element).then(function() { + * $scope.$apply(function() { + * $location.path('/new-page'); + * }); + * }); + * ``` + * + * An animation can also be cancelled by calling the `$animate.cancel(promise)` method with the provided + * promise that was returned when the animation was started. + * + * ```js + * var promise = $animate.addClass(element, 'super-long-animation'); + * promise.then(function() { + * //this will still be called even if cancelled + * }); + * + * element.on('click', function() { + * //tooo lazy to wait for the animation to end + * $animate.cancel(promise); + * }); + * ``` + * + * (Keep in mind that the promise cancellation is unique to `$animate` since promises in + * general cannot be cancelled.) + * + */ + return { + /** + * @ngdoc method + * @name $animate#animate + * @kind function + * + * @description + * Performs an inline animation on the element which applies the provided `to` and `from` CSS styles to the element. + * If any detected CSS transition, keyframe or JavaScript matches the provided `className` value then the animation + * will take on the provided styles. For example, if a transition animation is set for the given className then the + * provided `from` and `to` styles will be applied alongside the given transition. If a JavaScript animation is + * detected then the provided styles will be given in as function paramters. + * + * ```js + * ngModule.animation('.my-inline-animation', function() { + * return { + * animate : function(element, className, from, to, done) { + * //styles + * } + * } + * }); + * ``` + * + * Below is a breakdown of each step that occurs during the `animate` animation: + * + * | Animation Step | What the element class attribute looks like | + * |-----------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------| + * | 1. `$animate.animate(...)` is called | `class="my-animation"` | + * | 2. `$animate` waits for the next digest to start the animation | `class="my-animation ng-animate"` | + * | 3. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation ng-animate"` | + * | 4. the `className` class value is added to the element | `class="my-animation ng-animate className"` | + * | 5. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate className"` | + * | 6. `$animate` blocks all CSS transitions on the element to ensure the `.className` class styling is applied right away| `class="my-animation ng-animate className"` | + * | 7. `$animate` applies the provided collection of `from` CSS styles to the element | `class="my-animation ng-animate className"` | + * | 8. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation ng-animate className"` | + * | 9. `$animate` removes the CSS transition block placed on the element | `class="my-animation ng-animate className"` | + * | 10. the `className-active` class is added (this triggers the CSS transition/animation) | `class="my-animation ng-animate className className-active"` | + * | 11. `$animate` applies the collection of `to` CSS styles to the element which are then handled by the transition | `class="my-animation ng-animate className className-active"` | + * | 12. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate className className-active"` | + * | 13. The animation ends and all generated CSS classes are removed from the element | `class="my-animation"` | + * | 14. The returned promise is resolved. | `class="my-animation"` | + * + * @param {DOMElement} element the element that will be the focus of the enter animation + * @param {object} from a collection of CSS styles that will be applied to the element at the start of the animation + * @param {object} to a collection of CSS styles that the element will animate towards + * @param {string=} className an optional CSS class that will be added to the element for the duration of the animation (the default class is `ng-inline-animate`) + * @param {object=} options an optional collection of options that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + animate: function(element, from, to, className, options) { + className = className || 'ng-inline-animate'; + options = parseAnimateOptions(options) || {}; + options.from = to ? from : null; + options.to = to ? to : from; + + return runAnimationPostDigest(function(done) { + return performAnimation('animate', className, stripCommentsFromElement(element), null, null, noop, options, done); + }); + }, + + /** + * @ngdoc method + * @name $animate#enter + * @kind function + * + * @description + * Appends the element to the parentElement element that resides in the document and then runs the enter animation. Once + * the animation is started, the following CSS classes will be present on the element for the duration of the animation: + * + * Below is a breakdown of each step that occurs during enter animation: + * + * | Animation Step | What the element class attribute looks like | + * |-----------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------| + * | 1. `$animate.enter(...)` is called | `class="my-animation"` | + * | 2. element is inserted into the `parentElement` element or beside the `afterElement` element | `class="my-animation"` | + * | 3. `$animate` waits for the next digest to start the animation | `class="my-animation ng-animate"` | + * | 4. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation ng-animate"` | + * | 5. the `.ng-enter` class is added to the element | `class="my-animation ng-animate ng-enter"` | + * | 6. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate ng-enter"` | + * | 7. `$animate` blocks all CSS transitions on the element to ensure the `.ng-enter` class styling is applied right away | `class="my-animation ng-animate ng-enter"` | + * | 8. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation ng-animate ng-enter"` | + * | 9. `$animate` removes the CSS transition block placed on the element | `class="my-animation ng-animate ng-enter"` | + * | 10. the `.ng-enter-active` class is added (this triggers the CSS transition/animation) | `class="my-animation ng-animate ng-enter ng-enter-active"` | + * | 11. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate ng-enter ng-enter-active"` | + * | 12. The animation ends and all generated CSS classes are removed from the element | `class="my-animation"` | + * | 13. The returned promise is resolved. | `class="my-animation"` | + * + * @param {DOMElement} element the element that will be the focus of the enter animation + * @param {DOMElement} parentElement the parent element of the element that will be the focus of the enter animation + * @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the enter animation + * @param {object=} options an optional collection of options that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + enter: function(element, parentElement, afterElement, options) { + options = parseAnimateOptions(options); + element = angular.element(element); + parentElement = prepareElement(parentElement); + afterElement = prepareElement(afterElement); + + classBasedAnimationsBlocked(element, true); + $delegate.enter(element, parentElement, afterElement); + return runAnimationPostDigest(function(done) { + return performAnimation('enter', 'ng-enter', stripCommentsFromElement(element), parentElement, afterElement, noop, options, done); + }); + }, + + /** + * @ngdoc method + * @name $animate#leave + * @kind function + * + * @description + * Runs the leave animation operation and, upon completion, removes the element from the DOM. Once + * the animation is started, the following CSS classes will be added for the duration of the animation: + * + * Below is a breakdown of each step that occurs during leave animation: + * + * | Animation Step | What the element class attribute looks like | + * |-----------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------| + * | 1. `$animate.leave(...)` is called | `class="my-animation"` | + * | 2. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation ng-animate"` | + * | 3. `$animate` waits for the next digest to start the animation | `class="my-animation ng-animate"` | + * | 4. the `.ng-leave` class is added to the element | `class="my-animation ng-animate ng-leave"` | + * | 5. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate ng-leave"` | + * | 6. `$animate` blocks all CSS transitions on the element to ensure the `.ng-leave` class styling is applied right away | `class="my-animation ng-animate ng-leave"` | + * | 7. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation ng-animate ng-leave"` | + * | 8. `$animate` removes the CSS transition block placed on the element | `class="my-animation ng-animate ng-leave"` | + * | 9. the `.ng-leave-active` class is added (this triggers the CSS transition/animation) | `class="my-animation ng-animate ng-leave ng-leave-active"` | + * | 10. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate ng-leave ng-leave-active"` | + * | 11. The animation ends and all generated CSS classes are removed from the element | `class="my-animation"` | + * | 12. The element is removed from the DOM | ... | + * | 13. The returned promise is resolved. | ... | + * + * @param {DOMElement} element the element that will be the focus of the leave animation + * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + leave: function(element, options) { + options = parseAnimateOptions(options); + element = angular.element(element); + + cancelChildAnimations(element); + classBasedAnimationsBlocked(element, true); + return runAnimationPostDigest(function(done) { + return performAnimation('leave', 'ng-leave', stripCommentsFromElement(element), null, null, function() { + $delegate.leave(element); + }, options, done); + }); + }, + + /** + * @ngdoc method + * @name $animate#move + * @kind function + * + * @description + * Fires the move DOM operation. Just before the animation starts, the animate service will either append it into the parentElement container or + * add the element directly after the afterElement element if present. Then the move animation will be run. Once + * the animation is started, the following CSS classes will be added for the duration of the animation: + * + * Below is a breakdown of each step that occurs during move animation: + * + * | Animation Step | What the element class attribute looks like | + * |----------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------| + * | 1. `$animate.move(...)` is called | `class="my-animation"` | + * | 2. element is moved into the parentElement element or beside the afterElement element | `class="my-animation"` | + * | 3. `$animate` waits for the next digest to start the animation | `class="my-animation ng-animate"` | + * | 4. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation ng-animate"` | + * | 5. the `.ng-move` class is added to the element | `class="my-animation ng-animate ng-move"` | + * | 6. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate ng-move"` | + * | 7. `$animate` blocks all CSS transitions on the element to ensure the `.ng-move` class styling is applied right away | `class="my-animation ng-animate ng-move"` | + * | 8. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation ng-animate ng-move"` | + * | 9. `$animate` removes the CSS transition block placed on the element | `class="my-animation ng-animate ng-move"` | + * | 10. the `.ng-move-active` class is added (this triggers the CSS transition/animation) | `class="my-animation ng-animate ng-move ng-move-active"` | + * | 11. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate ng-move ng-move-active"` | + * | 12. The animation ends and all generated CSS classes are removed from the element | `class="my-animation"` | + * | 13. The returned promise is resolved. | `class="my-animation"` | + * + * @param {DOMElement} element the element that will be the focus of the move animation + * @param {DOMElement} parentElement the parentElement element of the element that will be the focus of the move animation + * @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the move animation + * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + move: function(element, parentElement, afterElement, options) { + options = parseAnimateOptions(options); + element = angular.element(element); + parentElement = prepareElement(parentElement); + afterElement = prepareElement(afterElement); + + cancelChildAnimations(element); + classBasedAnimationsBlocked(element, true); + $delegate.move(element, parentElement, afterElement); + return runAnimationPostDigest(function(done) { + return performAnimation('move', 'ng-move', stripCommentsFromElement(element), parentElement, afterElement, noop, options, done); + }); + }, + + /** + * @ngdoc method + * @name $animate#addClass + * + * @description + * Triggers a custom animation event based off the className variable and then attaches the className value to the element as a CSS class. + * Unlike the other animation methods, the animate service will suffix the className value with {@type -add} in order to provide + * the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if no CSS transitions + * or keyframes are defined on the -add-active or base CSS class). + * + * Below is a breakdown of each step that occurs during addClass animation: + * + * | Animation Step | What the element class attribute looks like | + * |--------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------| + * | 1. `$animate.addClass(element, 'super')` is called | `class="my-animation"` | + * | 2. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation ng-animate"` | + * | 3. the `.super-add` class is added to the element | `class="my-animation ng-animate super-add"` | + * | 4. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation ng-animate super-add"` | + * | 5. the `.super` and `.super-add-active` classes are added (this triggers the CSS transition/animation) | `class="my-animation ng-animate super super-add super-add-active"` | + * | 6. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate super super-add super-add-active"` | + * | 7. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate super super-add super-add-active"` | + * | 8. The animation ends and all generated CSS classes are removed from the element | `class="my-animation super"` | + * | 9. The super class is kept on the element | `class="my-animation super"` | + * | 10. The returned promise is resolved. | `class="my-animation super"` | + * + * @param {DOMElement} element the element that will be animated + * @param {string} className the CSS class that will be added to the element and then animated + * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + addClass: function(element, className, options) { + return this.setClass(element, className, [], options); + }, + + /** + * @ngdoc method + * @name $animate#removeClass + * + * @description + * Triggers a custom animation event based off the className variable and then removes the CSS class provided by the className value + * from the element. Unlike the other animation methods, the animate service will suffix the className value with {@type -remove} in + * order to provide the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if + * no CSS transitions or keyframes are defined on the -remove or base CSS classes). + * + * Below is a breakdown of each step that occurs during removeClass animation: + * + * | Animation Step | What the element class attribute looks like | + * |----------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------| + * | 1. `$animate.removeClass(element, 'super')` is called | `class="my-animation super"` | + * | 2. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation super ng-animate"` | + * | 3. the `.super-remove` class is added to the element | `class="my-animation super ng-animate super-remove"` | + * | 4. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation super ng-animate super-remove"` | + * | 5. the `.super-remove-active` classes are added and `.super` is removed (this triggers the CSS transition/animation) | `class="my-animation ng-animate super-remove super-remove-active"` | + * | 6. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate super-remove super-remove-active"` | + * | 7. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate super-remove super-remove-active"` | + * | 8. The animation ends and all generated CSS classes are removed from the element | `class="my-animation"` | + * | 9. The returned promise is resolved. | `class="my-animation"` | + * + * + * @param {DOMElement} element the element that will be animated + * @param {string} className the CSS class that will be animated and then removed from the element + * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + removeClass: function(element, className, options) { + return this.setClass(element, [], className, options); + }, + + /** + * + * @ngdoc method + * @name $animate#setClass + * + * @description Adds and/or removes the given CSS classes to and from the element. + * Once complete, the `done()` callback will be fired (if provided). + * + * | Animation Step | What the element class attribute looks like | + * |----------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------| + * | 1. `$animate.setClass(element, 'on', 'off')` is called | `class="my-animation off"` | + * | 2. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation ng-animate off"` | + * | 3. the `.on-add` and `.off-remove` classes are added to the element | `class="my-animation ng-animate on-add off-remove off"` | + * | 4. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation ng-animate on-add off-remove off"` | + * | 5. the `.on`, `.on-add-active` and `.off-remove-active` classes are added and `.off` is removed (this triggers the CSS transition/animation) | `class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active"` | + * | 6. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active"` | + * | 7. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active"` | + * | 8. The animation ends and all generated CSS classes are removed from the element | `class="my-animation on"` | + * | 9. The returned promise is resolved. | `class="my-animation on"` | + * + * @param {DOMElement} element the element which will have its CSS classes changed + * removed from it + * @param {string} add the CSS classes which will be added to the element + * @param {string} remove the CSS class which will be removed from the element + * CSS classes have been set on the element + * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + setClass: function(element, add, remove, options) { + options = parseAnimateOptions(options); + + var STORAGE_KEY = '$$animateClasses'; + element = angular.element(element); + element = stripCommentsFromElement(element); + + if (classBasedAnimationsBlocked(element)) { + return $delegate.$$setClassImmediately(element, add, remove, options); + } + + // we're using a combined array for both the add and remove + // operations since the ORDER OF addClass and removeClass matters + var classes, cache = element.data(STORAGE_KEY); + var hasCache = !!cache; + if (!cache) { + cache = {}; + cache.classes = {}; + } + classes = cache.classes; + + add = isArray(add) ? add : add.split(' '); + forEach(add, function(c) { + if (c && c.length) { + classes[c] = true; + } + }); + + remove = isArray(remove) ? remove : remove.split(' '); + forEach(remove, function(c) { + if (c && c.length) { + classes[c] = false; + } + }); + + if (hasCache) { + if (options && cache.options) { + cache.options = angular.extend(cache.options || {}, options); + } + + //the digest cycle will combine all the animations into one function + return cache.promise; + } else { + element.data(STORAGE_KEY, cache = { + classes: classes, + options: options + }); + } + + return cache.promise = runAnimationPostDigest(function(done) { + var parentElement = element.parent(); + var elementNode = extractElementNode(element); + var parentNode = elementNode.parentNode; + // TODO(matsko): move this code into the animationsDisabled() function once #8092 is fixed + if (!parentNode || parentNode['$$NG_REMOVED'] || elementNode['$$NG_REMOVED']) { + done(); + return; + } + + var cache = element.data(STORAGE_KEY); + element.removeData(STORAGE_KEY); + + var state = element.data(NG_ANIMATE_STATE) || {}; + var classes = resolveElementClasses(element, cache, state.active); + return !classes + ? done() + : performAnimation('setClass', classes, element, parentElement, null, function() { + if (classes[0]) $delegate.$$addClassImmediately(element, classes[0]); + if (classes[1]) $delegate.$$removeClassImmediately(element, classes[1]); + }, cache.options, done); + }); + }, + + /** + * @ngdoc method + * @name $animate#cancel + * @kind function + * + * @param {Promise} animationPromise The animation promise that is returned when an animation is started. + * + * @description + * Cancels the provided animation. + */ + cancel: function(promise) { + promise.$$cancelFn(); + }, + + /** + * @ngdoc method + * @name $animate#enabled + * @kind function + * + * @param {boolean=} value If provided then set the animation on or off. + * @param {DOMElement=} element If provided then the element will be used to represent the enable/disable operation + * @return {boolean} Current animation state. + * + * @description + * Globally enables/disables animations. + * + */ + enabled: function(value, element) { + switch (arguments.length) { + case 2: + if (value) { + cleanup(element); + } else { + var data = element.data(NG_ANIMATE_STATE) || {}; + data.disabled = true; + element.data(NG_ANIMATE_STATE, data); + } + break; + + case 1: + rootAnimateState.disabled = !value; + break; + + default: + value = !rootAnimateState.disabled; + break; + } + return !!value; + } + }; + + /* + all animations call this shared animation triggering function internally. + The animationEvent variable refers to the JavaScript animation event that will be triggered + and the className value is the name of the animation that will be applied within the + CSS code. Element, `parentElement` and `afterElement` are provided DOM elements for the animation + and the onComplete callback will be fired once the animation is fully complete. + */ + function performAnimation(animationEvent, className, element, parentElement, afterElement, domOperation, options, doneCallback) { + var noopCancel = noop; + var runner = animationRunner(element, animationEvent, className, options); + if (!runner) { + fireDOMOperation(); + fireBeforeCallbackAsync(); + fireAfterCallbackAsync(); + closeAnimation(); + return noopCancel; + } + + animationEvent = runner.event; + className = runner.className; + var elementEvents = angular.element._data(runner.node); + elementEvents = elementEvents && elementEvents.events; + + if (!parentElement) { + parentElement = afterElement ? afterElement.parent() : element.parent(); + } + + //skip the animation if animations are disabled, a parent is already being animated, + //the element is not currently attached to the document body or then completely close + //the animation if any matching animations are not found at all. + //NOTE: IE8 + IE9 should close properly (run closeAnimation()) in case an animation was found. + if (animationsDisabled(element, parentElement)) { + fireDOMOperation(); + fireBeforeCallbackAsync(); + fireAfterCallbackAsync(); + closeAnimation(); + return noopCancel; + } + + var ngAnimateState = element.data(NG_ANIMATE_STATE) || {}; + var runningAnimations = ngAnimateState.active || {}; + var totalActiveAnimations = ngAnimateState.totalActive || 0; + var lastAnimation = ngAnimateState.last; + var skipAnimation = false; + + if (totalActiveAnimations > 0) { + var animationsToCancel = []; + if (!runner.isClassBased) { + if (animationEvent == 'leave' && runningAnimations['ng-leave']) { + skipAnimation = true; + } else { + //cancel all animations when a structural animation takes place + for (var klass in runningAnimations) { + animationsToCancel.push(runningAnimations[klass]); + } + ngAnimateState = {}; + cleanup(element, true); + } + } else if (lastAnimation.event == 'setClass') { + animationsToCancel.push(lastAnimation); + cleanup(element, className); + } else if (runningAnimations[className]) { + var current = runningAnimations[className]; + if (current.event == animationEvent) { + skipAnimation = true; + } else { + animationsToCancel.push(current); + cleanup(element, className); + } + } + + if (animationsToCancel.length > 0) { + forEach(animationsToCancel, function(operation) { + operation.cancel(); + }); + } + } + + if (runner.isClassBased + && !runner.isSetClassOperation + && animationEvent != 'animate' + && !skipAnimation) { + skipAnimation = (animationEvent == 'addClass') == element.hasClass(className); //opposite of XOR + } + + if (skipAnimation) { + fireDOMOperation(); + fireBeforeCallbackAsync(); + fireAfterCallbackAsync(); + fireDoneCallbackAsync(); + return noopCancel; + } + + runningAnimations = ngAnimateState.active || {}; + totalActiveAnimations = ngAnimateState.totalActive || 0; + + if (animationEvent == 'leave') { + //there's no need to ever remove the listener since the element + //will be removed (destroyed) after the leave animation ends or + //is cancelled midway + element.one('$destroy', function(e) { + var element = angular.element(this); + var state = element.data(NG_ANIMATE_STATE); + if (state) { + var activeLeaveAnimation = state.active['ng-leave']; + if (activeLeaveAnimation) { + activeLeaveAnimation.cancel(); + cleanup(element, 'ng-leave'); + } + } + }); + } + + //the ng-animate class does nothing, but it's here to allow for + //parent animations to find and cancel child animations when needed + $$jqLite.addClass(element, NG_ANIMATE_CLASS_NAME); + if (options && options.tempClasses) { + forEach(options.tempClasses, function(className) { + $$jqLite.addClass(element, className); + }); + } + + var localAnimationCount = globalAnimationCounter++; + totalActiveAnimations++; + runningAnimations[className] = runner; + + element.data(NG_ANIMATE_STATE, { + last: runner, + active: runningAnimations, + index: localAnimationCount, + totalActive: totalActiveAnimations + }); + + //first we run the before animations and when all of those are complete + //then we perform the DOM operation and run the next set of animations + fireBeforeCallbackAsync(); + runner.before(function(cancelled) { + var data = element.data(NG_ANIMATE_STATE); + cancelled = cancelled || + !data || !data.active[className] || + (runner.isClassBased && data.active[className].event != animationEvent); + + fireDOMOperation(); + if (cancelled === true) { + closeAnimation(); + } else { + fireAfterCallbackAsync(); + runner.after(closeAnimation); + } + }); + + return runner.cancel; + + function fireDOMCallback(animationPhase) { + var eventName = '$animate:' + animationPhase; + if (elementEvents && elementEvents[eventName] && elementEvents[eventName].length > 0) { + $$asyncCallback(function() { + element.triggerHandler(eventName, { + event: animationEvent, + className: className + }); + }); + } + } + + function fireBeforeCallbackAsync() { + fireDOMCallback('before'); + } + + function fireAfterCallbackAsync() { + fireDOMCallback('after'); + } + + function fireDoneCallbackAsync() { + fireDOMCallback('close'); + doneCallback(); + } + + //it is less complicated to use a flag than managing and canceling + //timeouts containing multiple callbacks. + function fireDOMOperation() { + if (!fireDOMOperation.hasBeenRun) { + fireDOMOperation.hasBeenRun = true; + domOperation(); + } + } + + function closeAnimation() { + if (!closeAnimation.hasBeenRun) { + if (runner) { //the runner doesn't exist if it fails to instantiate + runner.applyStyles(); + } + + closeAnimation.hasBeenRun = true; + if (options && options.tempClasses) { + forEach(options.tempClasses, function(className) { + $$jqLite.removeClass(element, className); + }); + } + + var data = element.data(NG_ANIMATE_STATE); + if (data) { + + /* only structural animations wait for reflow before removing an + animation, but class-based animations don't. An example of this + failing would be when a parent HTML tag has a ng-class attribute + causing ALL directives below to skip animations during the digest */ + if (runner && runner.isClassBased) { + cleanup(element, className); + } else { + $$asyncCallback(function() { + var data = element.data(NG_ANIMATE_STATE) || {}; + if (localAnimationCount == data.index) { + cleanup(element, className, animationEvent); + } + }); + element.data(NG_ANIMATE_STATE, data); + } + } + fireDoneCallbackAsync(); + } + } + } + + function cancelChildAnimations(element) { + var node = extractElementNode(element); + if (node) { + var nodes = angular.isFunction(node.getElementsByClassName) ? + node.getElementsByClassName(NG_ANIMATE_CLASS_NAME) : + node.querySelectorAll('.' + NG_ANIMATE_CLASS_NAME); + forEach(nodes, function(element) { + element = angular.element(element); + var data = element.data(NG_ANIMATE_STATE); + if (data && data.active) { + forEach(data.active, function(runner) { + runner.cancel(); + }); + } + }); + } + } + + function cleanup(element, className) { + if (isMatchingElement(element, $rootElement)) { + if (!rootAnimateState.disabled) { + rootAnimateState.running = false; + rootAnimateState.structural = false; + } + } else if (className) { + var data = element.data(NG_ANIMATE_STATE) || {}; + + var removeAnimations = className === true; + if (!removeAnimations && data.active && data.active[className]) { + data.totalActive--; + delete data.active[className]; + } + + if (removeAnimations || !data.totalActive) { + $$jqLite.removeClass(element, NG_ANIMATE_CLASS_NAME); + element.removeData(NG_ANIMATE_STATE); + } + } + } + + function animationsDisabled(element, parentElement) { + if (rootAnimateState.disabled) { + return true; + } + + if (isMatchingElement(element, $rootElement)) { + return rootAnimateState.running; + } + + var allowChildAnimations, parentRunningAnimation, hasParent; + do { + //the element did not reach the root element which means that it + //is not apart of the DOM. Therefore there is no reason to do + //any animations on it + if (parentElement.length === 0) break; + + var isRoot = isMatchingElement(parentElement, $rootElement); + var state = isRoot ? rootAnimateState : (parentElement.data(NG_ANIMATE_STATE) || {}); + if (state.disabled) { + return true; + } + + //no matter what, for an animation to work it must reach the root element + //this implies that the element is attached to the DOM when the animation is run + if (isRoot) { + hasParent = true; + } + + //once a flag is found that is strictly false then everything before + //it will be discarded and all child animations will be restricted + if (allowChildAnimations !== false) { + var animateChildrenFlag = parentElement.data(NG_ANIMATE_CHILDREN); + if (angular.isDefined(animateChildrenFlag)) { + allowChildAnimations = animateChildrenFlag; + } + } + + parentRunningAnimation = parentRunningAnimation || + state.running || + (state.last && !state.last.isClassBased); + } + while (parentElement = parentElement.parent()); + + return !hasParent || (!allowChildAnimations && parentRunningAnimation); + } + }]); + + $animateProvider.register('', ['$window', '$sniffer', '$timeout', '$$animateReflow', + function($window, $sniffer, $timeout, $$animateReflow) { + // Detect proper transitionend/animationend event names. + var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT; + + // If unprefixed events are not supported but webkit-prefixed are, use the latter. + // Otherwise, just use W3C names, browsers not supporting them at all will just ignore them. + // Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend` + // but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`. + // Register both events in case `window.onanimationend` is not supported because of that, + // do the same for `transitionend` as Safari is likely to exhibit similar behavior. + // Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit + // therefore there is no reason to test anymore for other vendor prefixes: http://caniuse.com/#search=transition + if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) { + CSS_PREFIX = '-webkit-'; + TRANSITION_PROP = 'WebkitTransition'; + TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend'; + } else { + TRANSITION_PROP = 'transition'; + TRANSITIONEND_EVENT = 'transitionend'; + } + + if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) { + CSS_PREFIX = '-webkit-'; + ANIMATION_PROP = 'WebkitAnimation'; + ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend'; + } else { + ANIMATION_PROP = 'animation'; + ANIMATIONEND_EVENT = 'animationend'; + } + + var DURATION_KEY = 'Duration'; + var PROPERTY_KEY = 'Property'; + var DELAY_KEY = 'Delay'; + var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount'; + var ANIMATION_PLAYSTATE_KEY = 'PlayState'; + var NG_ANIMATE_PARENT_KEY = '$$ngAnimateKey'; + var NG_ANIMATE_CSS_DATA_KEY = '$$ngAnimateCSS3Data'; + var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3; + var CLOSING_TIME_BUFFER = 1.5; + var ONE_SECOND = 1000; + + var lookupCache = {}; + var parentCounter = 0; + var animationReflowQueue = []; + var cancelAnimationReflow; + function clearCacheAfterReflow() { + if (!cancelAnimationReflow) { + cancelAnimationReflow = $$animateReflow(function() { + animationReflowQueue = []; + cancelAnimationReflow = null; + lookupCache = {}; + }); + } + } + + function afterReflow(element, callback) { + if (cancelAnimationReflow) { + cancelAnimationReflow(); + } + animationReflowQueue.push(callback); + cancelAnimationReflow = $$animateReflow(function() { + forEach(animationReflowQueue, function(fn) { + fn(); + }); + + animationReflowQueue = []; + cancelAnimationReflow = null; + lookupCache = {}; + }); + } + + var closingTimer = null; + var closingTimestamp = 0; + var animationElementQueue = []; + function animationCloseHandler(element, totalTime) { + var node = extractElementNode(element); + element = angular.element(node); + + //this item will be garbage collected by the closing + //animation timeout + animationElementQueue.push(element); + + //but it may not need to cancel out the existing timeout + //if the timestamp is less than the previous one + var futureTimestamp = Date.now() + totalTime; + if (futureTimestamp <= closingTimestamp) { + return; + } + + $timeout.cancel(closingTimer); + + closingTimestamp = futureTimestamp; + closingTimer = $timeout(function() { + closeAllAnimations(animationElementQueue); + animationElementQueue = []; + }, totalTime, false); + } + + function closeAllAnimations(elements) { + forEach(elements, function(element) { + var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY); + if (elementData) { + forEach(elementData.closeAnimationFns, function(fn) { + fn(); + }); + } + }); + } + + function getElementAnimationDetails(element, cacheKey) { + var data = cacheKey ? lookupCache[cacheKey] : null; + if (!data) { + var transitionDuration = 0; + var transitionDelay = 0; + var animationDuration = 0; + var animationDelay = 0; + + //we want all the styles defined before and after + forEach(element, function(element) { + if (element.nodeType == ELEMENT_NODE) { + var elementStyles = $window.getComputedStyle(element) || {}; + + var transitionDurationStyle = elementStyles[TRANSITION_PROP + DURATION_KEY]; + transitionDuration = Math.max(parseMaxTime(transitionDurationStyle), transitionDuration); + + var transitionDelayStyle = elementStyles[TRANSITION_PROP + DELAY_KEY]; + transitionDelay = Math.max(parseMaxTime(transitionDelayStyle), transitionDelay); + + var animationDelayStyle = elementStyles[ANIMATION_PROP + DELAY_KEY]; + animationDelay = Math.max(parseMaxTime(elementStyles[ANIMATION_PROP + DELAY_KEY]), animationDelay); + + var aDuration = parseMaxTime(elementStyles[ANIMATION_PROP + DURATION_KEY]); + + if (aDuration > 0) { + aDuration *= parseInt(elementStyles[ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY], 10) || 1; + } + animationDuration = Math.max(aDuration, animationDuration); + } + }); + data = { + total: 0, + transitionDelay: transitionDelay, + transitionDuration: transitionDuration, + animationDelay: animationDelay, + animationDuration: animationDuration + }; + if (cacheKey) { + lookupCache[cacheKey] = data; + } + } + return data; + } + + function parseMaxTime(str) { + var maxValue = 0; + var values = isString(str) ? + str.split(/\s*,\s*/) : + []; + forEach(values, function(value) { + maxValue = Math.max(parseFloat(value) || 0, maxValue); + }); + return maxValue; + } + + function getCacheKey(element) { + var parentElement = element.parent(); + var parentID = parentElement.data(NG_ANIMATE_PARENT_KEY); + if (!parentID) { + parentElement.data(NG_ANIMATE_PARENT_KEY, ++parentCounter); + parentID = parentCounter; + } + return parentID + '-' + extractElementNode(element).getAttribute('class'); + } + + function animateSetup(animationEvent, element, className, styles) { + var structural = ['ng-enter','ng-leave','ng-move'].indexOf(className) >= 0; + + var cacheKey = getCacheKey(element); + var eventCacheKey = cacheKey + ' ' + className; + var itemIndex = lookupCache[eventCacheKey] ? ++lookupCache[eventCacheKey].total : 0; + + var stagger = {}; + if (itemIndex > 0) { + var staggerClassName = className + '-stagger'; + var staggerCacheKey = cacheKey + ' ' + staggerClassName; + var applyClasses = !lookupCache[staggerCacheKey]; + + applyClasses && $$jqLite.addClass(element, staggerClassName); + + stagger = getElementAnimationDetails(element, staggerCacheKey); + + applyClasses && $$jqLite.removeClass(element, staggerClassName); + } + + $$jqLite.addClass(element, className); + + var formerData = element.data(NG_ANIMATE_CSS_DATA_KEY) || {}; + var timings = getElementAnimationDetails(element, eventCacheKey); + var transitionDuration = timings.transitionDuration; + var animationDuration = timings.animationDuration; + + if (structural && transitionDuration === 0 && animationDuration === 0) { + $$jqLite.removeClass(element, className); + return false; + } + + var blockTransition = styles || (structural && transitionDuration > 0); + var blockAnimation = animationDuration > 0 && + stagger.animationDelay > 0 && + stagger.animationDuration === 0; + + var closeAnimationFns = formerData.closeAnimationFns || []; + element.data(NG_ANIMATE_CSS_DATA_KEY, { + stagger: stagger, + cacheKey: eventCacheKey, + running: formerData.running || 0, + itemIndex: itemIndex, + blockTransition: blockTransition, + closeAnimationFns: closeAnimationFns + }); + + var node = extractElementNode(element); + + if (blockTransition) { + blockTransitions(node, true); + if (styles) { + element.css(styles); + } + } + + if (blockAnimation) { + blockAnimations(node, true); + } + + return true; + } + + function animateRun(animationEvent, element, className, activeAnimationComplete, styles) { + var node = extractElementNode(element); + var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY); + if (node.getAttribute('class').indexOf(className) == -1 || !elementData) { + activeAnimationComplete(); + return; + } + + var activeClassName = ''; + var pendingClassName = ''; + forEach(className.split(' '), function(klass, i) { + var prefix = (i > 0 ? ' ' : '') + klass; + activeClassName += prefix + '-active'; + pendingClassName += prefix + '-pending'; + }); + + var style = ''; + var appliedStyles = []; + var itemIndex = elementData.itemIndex; + var stagger = elementData.stagger; + var staggerTime = 0; + if (itemIndex > 0) { + var transitionStaggerDelay = 0; + if (stagger.transitionDelay > 0 && stagger.transitionDuration === 0) { + transitionStaggerDelay = stagger.transitionDelay * itemIndex; + } + + var animationStaggerDelay = 0; + if (stagger.animationDelay > 0 && stagger.animationDuration === 0) { + animationStaggerDelay = stagger.animationDelay * itemIndex; + appliedStyles.push(CSS_PREFIX + 'animation-play-state'); + } + + staggerTime = Math.round(Math.max(transitionStaggerDelay, animationStaggerDelay) * 100) / 100; + } + + if (!staggerTime) { + $$jqLite.addClass(element, activeClassName); + if (elementData.blockTransition) { + blockTransitions(node, false); + } + } + + var eventCacheKey = elementData.cacheKey + ' ' + activeClassName; + var timings = getElementAnimationDetails(element, eventCacheKey); + var maxDuration = Math.max(timings.transitionDuration, timings.animationDuration); + if (maxDuration === 0) { + $$jqLite.removeClass(element, activeClassName); + animateClose(element, className); + activeAnimationComplete(); + return; + } + + if (!staggerTime && styles && Object.keys(styles).length > 0) { + if (!timings.transitionDuration) { + element.css('transition', timings.animationDuration + 's linear all'); + appliedStyles.push('transition'); + } + element.css(styles); + } + + var maxDelay = Math.max(timings.transitionDelay, timings.animationDelay); + var maxDelayTime = maxDelay * ONE_SECOND; + + if (appliedStyles.length > 0) { + //the element being animated may sometimes contain comment nodes in + //the jqLite object, so we're safe to use a single variable to house + //the styles since there is always only one element being animated + var oldStyle = node.getAttribute('style') || ''; + if (oldStyle.charAt(oldStyle.length - 1) !== ';') { + oldStyle += ';'; + } + node.setAttribute('style', oldStyle + ' ' + style); + } + + var startTime = Date.now(); + var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT; + var animationTime = (maxDelay + maxDuration) * CLOSING_TIME_BUFFER; + var totalTime = (staggerTime + animationTime) * ONE_SECOND; + + var staggerTimeout; + if (staggerTime > 0) { + $$jqLite.addClass(element, pendingClassName); + staggerTimeout = $timeout(function() { + staggerTimeout = null; + + if (timings.transitionDuration > 0) { + blockTransitions(node, false); + } + if (timings.animationDuration > 0) { + blockAnimations(node, false); + } + + $$jqLite.addClass(element, activeClassName); + $$jqLite.removeClass(element, pendingClassName); + + if (styles) { + if (timings.transitionDuration === 0) { + element.css('transition', timings.animationDuration + 's linear all'); + } + element.css(styles); + appliedStyles.push('transition'); + } + }, staggerTime * ONE_SECOND, false); + } + + element.on(css3AnimationEvents, onAnimationProgress); + elementData.closeAnimationFns.push(function() { + onEnd(); + activeAnimationComplete(); + }); + + elementData.running++; + animationCloseHandler(element, totalTime); + return onEnd; + + // This will automatically be called by $animate so + // there is no need to attach this internally to the + // timeout done method. + function onEnd() { + element.off(css3AnimationEvents, onAnimationProgress); + $$jqLite.removeClass(element, activeClassName); + $$jqLite.removeClass(element, pendingClassName); + if (staggerTimeout) { + $timeout.cancel(staggerTimeout); + } + animateClose(element, className); + var node = extractElementNode(element); + for (var i in appliedStyles) { + node.style.removeProperty(appliedStyles[i]); + } + } + + function onAnimationProgress(event) { + event.stopPropagation(); + var ev = event.originalEvent || event; + var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now(); + + /* Firefox (or possibly just Gecko) likes to not round values up + * when a ms measurement is used for the animation */ + var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES)); + + /* $manualTimeStamp is a mocked timeStamp value which is set + * within browserTrigger(). This is only here so that tests can + * mock animations properly. Real events fallback to event.timeStamp, + * or, if they don't, then a timeStamp is automatically created for them. + * We're checking to see if the timeStamp surpasses the expected delay, + * but we're using elapsedTime instead of the timeStamp on the 2nd + * pre-condition since animations sometimes close off early */ + if (Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) { + activeAnimationComplete(); + } + } + } + + function blockTransitions(node, bool) { + node.style[TRANSITION_PROP + PROPERTY_KEY] = bool ? 'none' : ''; + } + + function blockAnimations(node, bool) { + node.style[ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY] = bool ? 'paused' : ''; + } + + function animateBefore(animationEvent, element, className, styles) { + if (animateSetup(animationEvent, element, className, styles)) { + return function(cancelled) { + cancelled && animateClose(element, className); + }; + } + } + + function animateAfter(animationEvent, element, className, afterAnimationComplete, styles) { + if (element.data(NG_ANIMATE_CSS_DATA_KEY)) { + return animateRun(animationEvent, element, className, afterAnimationComplete, styles); + } else { + animateClose(element, className); + afterAnimationComplete(); + } + } + + function animate(animationEvent, element, className, animationComplete, options) { + //If the animateSetup function doesn't bother returning a + //cancellation function then it means that there is no animation + //to perform at all + var preReflowCancellation = animateBefore(animationEvent, element, className, options.from); + if (!preReflowCancellation) { + clearCacheAfterReflow(); + animationComplete(); + return; + } + + //There are two cancellation functions: one is before the first + //reflow animation and the second is during the active state + //animation. The first function will take care of removing the + //data from the element which will not make the 2nd animation + //happen in the first place + var cancel = preReflowCancellation; + afterReflow(element, function() { + //once the reflow is complete then we point cancel to + //the new cancellation function which will remove all of the + //animation properties from the active animation + cancel = animateAfter(animationEvent, element, className, animationComplete, options.to); + }); + + return function(cancelled) { + (cancel || noop)(cancelled); + }; + } + + function animateClose(element, className) { + $$jqLite.removeClass(element, className); + var data = element.data(NG_ANIMATE_CSS_DATA_KEY); + if (data) { + if (data.running) { + data.running--; + } + if (!data.running || data.running === 0) { + element.removeData(NG_ANIMATE_CSS_DATA_KEY); + } + } + } + + return { + animate: function(element, className, from, to, animationCompleted, options) { + options = options || {}; + options.from = from; + options.to = to; + return animate('animate', element, className, animationCompleted, options); + }, + + enter: function(element, animationCompleted, options) { + options = options || {}; + return animate('enter', element, 'ng-enter', animationCompleted, options); + }, + + leave: function(element, animationCompleted, options) { + options = options || {}; + return animate('leave', element, 'ng-leave', animationCompleted, options); + }, + + move: function(element, animationCompleted, options) { + options = options || {}; + return animate('move', element, 'ng-move', animationCompleted, options); + }, + + beforeSetClass: function(element, add, remove, animationCompleted, options) { + options = options || {}; + var className = suffixClasses(remove, '-remove') + ' ' + + suffixClasses(add, '-add'); + var cancellationMethod = animateBefore('setClass', element, className, options.from); + if (cancellationMethod) { + afterReflow(element, animationCompleted); + return cancellationMethod; + } + clearCacheAfterReflow(); + animationCompleted(); + }, + + beforeAddClass: function(element, className, animationCompleted, options) { + options = options || {}; + var cancellationMethod = animateBefore('addClass', element, suffixClasses(className, '-add'), options.from); + if (cancellationMethod) { + afterReflow(element, animationCompleted); + return cancellationMethod; + } + clearCacheAfterReflow(); + animationCompleted(); + }, + + beforeRemoveClass: function(element, className, animationCompleted, options) { + options = options || {}; + var cancellationMethod = animateBefore('removeClass', element, suffixClasses(className, '-remove'), options.from); + if (cancellationMethod) { + afterReflow(element, animationCompleted); + return cancellationMethod; + } + clearCacheAfterReflow(); + animationCompleted(); + }, + + setClass: function(element, add, remove, animationCompleted, options) { + options = options || {}; + remove = suffixClasses(remove, '-remove'); + add = suffixClasses(add, '-add'); + var className = remove + ' ' + add; + return animateAfter('setClass', element, className, animationCompleted, options.to); + }, + + addClass: function(element, className, animationCompleted, options) { + options = options || {}; + return animateAfter('addClass', element, suffixClasses(className, '-add'), animationCompleted, options.to); + }, + + removeClass: function(element, className, animationCompleted, options) { + options = options || {}; + return animateAfter('removeClass', element, suffixClasses(className, '-remove'), animationCompleted, options.to); + } + }; + + function suffixClasses(classes, suffix) { + var className = ''; + classes = isArray(classes) ? classes : classes.split(/\s+/); + forEach(classes, function(klass, i) { + if (klass && klass.length > 0) { + className += (i > 0 ? ' ' : '') + klass + suffix; + } + }); + return className; + } + }]); + }]); + + +})(window, window.angular); diff --git a/snow-flowable/src/main/resources/static/libs/angular-animate_1.3.13/angular-animate.min.js b/snow-flowable/src/main/resources/static/libs/angular-animate_1.3.13/angular-animate.min.js new file mode 100644 index 0000000..6ed98ee --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-animate_1.3.13/angular-animate.min.js @@ -0,0 +1,33 @@ +/* + AngularJS v1.3.13 + (c) 2010-2014 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(N,f,W){'use strict';f.module("ngAnimate",["ng"]).directive("ngAnimateChildren",function(){return function(X,C,g){g=g.ngAnimateChildren;f.isString(g)&&0===g.length?C.data("$$ngAnimateChildren",!0):X.$watch(g,function(f){C.data("$$ngAnimateChildren",!!f)})}}).factory("$$animateReflow",["$$rAF","$document",function(f,C){return function(g){return f(function(){g()})}}]).config(["$provide","$animateProvider",function(X,C){function g(f){for(var n=0;n=C&&b>=x&&c()}var m=g(e);a=e.data("$$ngAnimateCSS3Data");if(-1!=m.getAttribute("class").indexOf(b)&&a){var k="",t="";n(b.split(" "),function(a, +b){var e=(0
+ * + * See {@link ngCookies.$cookies `$cookies`} and + * {@link ngCookies.$cookieStore `$cookieStore`} for usage. + */ + + +angular.module('ngCookies', ['ng']). + /** + * @ngdoc service + * @name $cookies + * + * @description + * Provides read/write access to browser's cookies. + * + * Only a simple Object is exposed and by adding or removing properties to/from this object, new + * cookies are created/deleted at the end of current $eval. + * The object's properties can only be strings. + * + * Requires the {@link ngCookies `ngCookies`} module to be installed. + * + * @example + * + * ```js + * angular.module('cookiesExample', ['ngCookies']) + * .controller('ExampleController', ['$cookies', function($cookies) { + * // Retrieving a cookie + * var favoriteCookie = $cookies.myFavorite; + * // Setting a cookie + * $cookies.myFavorite = 'oatmeal'; + * }]); + * ``` + */ + factory('$cookies', ['$rootScope', '$browser', function($rootScope, $browser) { + var cookies = {}, + lastCookies = {}, + lastBrowserCookies, + runEval = false, + copy = angular.copy, + isUndefined = angular.isUndefined; + + //creates a poller fn that copies all cookies from the $browser to service & inits the service + $browser.addPollFn(function() { + var currentCookies = $browser.cookies(); + if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl + lastBrowserCookies = currentCookies; + copy(currentCookies, lastCookies); + copy(currentCookies, cookies); + if (runEval) $rootScope.$apply(); + } + })(); + + runEval = true; + + //at the end of each eval, push cookies + //TODO: this should happen before the "delayed" watches fire, because if some cookies are not + // strings or browser refuses to store some cookies, we update the model in the push fn. + $rootScope.$watch(push); + + return cookies; + + + /** + * Pushes all the cookies from the service to the browser and verifies if all cookies were + * stored. + */ + function push() { + var name, + value, + browserCookies, + updated; + + //delete any cookies deleted in $cookies + for (name in lastCookies) { + if (isUndefined(cookies[name])) { + $browser.cookies(name, undefined); + } + } + + //update all cookies updated in $cookies + for (name in cookies) { + value = cookies[name]; + if (!angular.isString(value)) { + value = '' + value; + cookies[name] = value; + } + if (value !== lastCookies[name]) { + $browser.cookies(name, value); + updated = true; + } + } + + //verify what was actually stored + if (updated) { + updated = false; + browserCookies = $browser.cookies(); + + for (name in cookies) { + if (cookies[name] !== browserCookies[name]) { + //delete or reset all cookies that the browser dropped from $cookies + if (isUndefined(browserCookies[name])) { + delete cookies[name]; + } else { + cookies[name] = browserCookies[name]; + } + updated = true; + } + } + } + } + }]). + + + /** + * @ngdoc service + * @name $cookieStore + * @requires $cookies + * + * @description + * Provides a key-value (string-object) storage, that is backed by session cookies. + * Objects put or retrieved from this storage are automatically serialized or + * deserialized by angular's toJson/fromJson. + * + * Requires the {@link ngCookies `ngCookies`} module to be installed. + * + * @example + * + * ```js + * angular.module('cookieStoreExample', ['ngCookies']) + * .controller('ExampleController', ['$cookieStore', function($cookieStore) { + * // Put cookie + * $cookieStore.put('myFavorite','oatmeal'); + * // Get cookie + * var favoriteCookie = $cookieStore.get('myFavorite'); + * // Removing a cookie + * $cookieStore.remove('myFavorite'); + * }]); + * ``` + */ + factory('$cookieStore', ['$cookies', function($cookies) { + + return { + /** + * @ngdoc method + * @name $cookieStore#get + * + * @description + * Returns the value of given cookie key + * + * @param {string} key Id to use for lookup. + * @returns {Object} Deserialized cookie value. + */ + get: function(key) { + var value = $cookies[key]; + return value ? angular.fromJson(value) : value; + }, + + /** + * @ngdoc method + * @name $cookieStore#put + * + * @description + * Sets a value for given cookie key + * + * @param {string} key Id for the `value`. + * @param {Object} value Value to be stored. + */ + put: function(key, value) { + $cookies[key] = angular.toJson(value); + }, + + /** + * @ngdoc method + * @name $cookieStore#remove + * + * @description + * Remove given cookie + * + * @param {string} key Id of the key-value pair to delete. + */ + remove: function(key) { + delete $cookies[key]; + } + }; + + }]); + + +})(window, window.angular); diff --git a/snow-flowable/src/main/resources/static/libs/angular-cookies_1.3.13/angular-cookies.min.js b/snow-flowable/src/main/resources/static/libs/angular-cookies_1.3.13/angular-cookies.min.js new file mode 100644 index 0000000..2d81fd3 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-cookies_1.3.13/angular-cookies.min.js @@ -0,0 +1,8 @@ +/* + AngularJS v1.3.13 + (c) 2010-2014 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(p,f,n){'use strict';f.module("ngCookies",["ng"]).factory("$cookies",["$rootScope","$browser",function(e,b){var c={},g={},h,k=!1,l=f.copy,m=f.isUndefined;b.addPollFn(function(){var a=b.cookies();h!=a&&(h=a,l(a,g),l(a,c),k&&e.$apply())})();k=!0;e.$watch(function(){var a,d,e;for(a in g)m(c[a])&&b.cookies(a,n);for(a in c)d=c[a],f.isString(d)||(d=""+d,c[a]=d),d!==g[a]&&(b.cookies(a,d),e=!0);if(e)for(a in d=b.cookies(),c)c[a]!==d[a]&&(m(d[a])?delete c[a]:c[a]=d[a])});return c}]).factory("$cookieStore", +["$cookies",function(e){return{get:function(b){return(b=e[b])?f.fromJson(b):b},put:function(b,c){e[b]=f.toJson(c)},remove:function(b){delete e[b]}}}])})(window,window.angular); +//# sourceMappingURL=angular-cookies.min.js.map diff --git a/snow-flowable/src/main/resources/static/libs/angular-cookies_1.3.13/angular-cookies.min.js.map b/snow-flowable/src/main/resources/static/libs/angular-cookies_1.3.13/angular-cookies.min.js.map new file mode 100644 index 0000000..677960c --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-cookies_1.3.13/angular-cookies.min.js.map @@ -0,0 +1,8 @@ +{ +"version":3, +"file":"angular-cookies.min.js", +"lineCount":7, +"mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkBC,CAAlB,CAA6B,CAmBtCD,CAAAE,OAAA,CAAe,WAAf,CAA4B,CAAC,IAAD,CAA5B,CAAAC,QAAA,CA0BW,UA1BX,CA0BuB,CAAC,YAAD,CAAe,UAAf,CAA2B,QAAQ,CAACC,CAAD,CAAaC,CAAb,CAAuB,CAAA,IACvEC,EAAU,EAD6D,CAEvEC,EAAc,EAFyD,CAGvEC,CAHuE,CAIvEC,EAAU,CAAA,CAJ6D,CAKvEC,EAAOV,CAAAU,KALgE,CAMvEC,EAAcX,CAAAW,YAGlBN,EAAAO,UAAA,CAAmB,QAAQ,EAAG,CAC5B,IAAIC,EAAiBR,CAAAC,QAAA,EACjBE,EAAJ,EAA0BK,CAA1B,GACEL,CAGA,CAHqBK,CAGrB,CAFAH,CAAA,CAAKG,CAAL,CAAqBN,CAArB,CAEA,CADAG,CAAA,CAAKG,CAAL,CAAqBP,CAArB,CACA,CAAIG,CAAJ,EAAaL,CAAAU,OAAA,EAJf,CAF4B,CAA9B,CAAA,EAUAL,EAAA,CAAU,CAAA,CAKVL,EAAAW,OAAA,CASAC,QAAa,EAAG,CAAA,IACVC,CADU,CAEVC,CAFU,CAIVC,CAGJ,KAAKF,CAAL,GAAaV,EAAb,CACMI,CAAA,CAAYL,CAAA,CAAQW,CAAR,CAAZ,CAAJ,EACEZ,CAAAC,QAAA,CAAiBW,CAAjB,CAAuBhB,CAAvB,CAKJ,KAAKgB,CAAL,GAAaX,EAAb,CACEY,CAKA,CALQZ,CAAA,CAAQW,CAAR,CAKR,CAJKjB,CAAAoB,SAAA,CAAiBF,CAAjB,CAIL,GAHEA,CACA,CADQ,EACR,CADaA,CACb,CAAAZ,CAAA,CAAQW,CAAR,CAAA,CAAgBC,CAElB,EAAIA,CAAJ,GAAcX,CAAA,CAAYU,CAAZ,CAAd,GACEZ,CAAAC,QAAA,CAAiBW,CAAjB,CAAuBC,CAAvB,CACA,CAAAC,CAAA,CAAU,CAAA,CAFZ,CAOF,IAAIA,CAAJ,CAIE,IAAKF,CAAL,GAFAI,EAEaf,CAFID,CAAAC,QAAA,EAEJA,CAAAA,CAAb,CACMA,CAAA,CAAQW,CAAR,CAAJ,GAAsBI,CAAA,CAAeJ,CAAf,CAAtB,GAEMN,CAAA,CAAYU,CAAA,CAAeJ,CAAf,CAAZ,CAAJ,CACE,OAAOX,CAAA,CAAQW,CAAR,CADT,CAGEX,CAAA,CAAQW,CAAR,CAHF,CAGkBI,CAAA,CAAeJ,CAAf,CALpB,CAhCU,CAThB,CAEA,OAAOX,EA1BoE,CAA1D,CA1BvB,CAAAH,QAAA,CAoIW,cApIX;AAoI2B,CAAC,UAAD,CAAa,QAAQ,CAACmB,CAAD,CAAW,CAErD,MAAO,CAWLC,IAAKA,QAAQ,CAACC,CAAD,CAAM,CAEjB,MAAO,CADHN,CACG,CADKI,CAAA,CAASE,CAAT,CACL,EAAQxB,CAAAyB,SAAA,CAAiBP,CAAjB,CAAR,CAAkCA,CAFxB,CAXd,CA0BLQ,IAAKA,QAAQ,CAACF,CAAD,CAAMN,CAAN,CAAa,CACxBI,CAAA,CAASE,CAAT,CAAA,CAAgBxB,CAAA2B,OAAA,CAAeT,CAAf,CADQ,CA1BrB,CAuCLU,OAAQA,QAAQ,CAACJ,CAAD,CAAM,CACpB,OAAOF,CAAA,CAASE,CAAT,CADa,CAvCjB,CAF8C,CAAhC,CApI3B,CAnBsC,CAArC,CAAD,CAwMGzB,MAxMH,CAwMWA,MAAAC,QAxMX;", +"sources":["angular-cookies.js"], +"names":["window","angular","undefined","module","factory","$rootScope","$browser","cookies","lastCookies","lastBrowserCookies","runEval","copy","isUndefined","addPollFn","currentCookies","$apply","$watch","push","name","value","updated","isString","browserCookies","$cookies","get","key","fromJson","put","toJson","remove"] +} diff --git a/snow-flowable/src/main/resources/static/libs/angular-drag-and-drop-lists_1.2.0/angular-drag-and-drop-lists.js b/snow-flowable/src/main/resources/static/libs/angular-drag-and-drop-lists_1.2.0/angular-drag-and-drop-lists.js new file mode 100644 index 0000000..e496fd4 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-drag-and-drop-lists_1.2.0/angular-drag-and-drop-lists.js @@ -0,0 +1,501 @@ +/** + * angular-drag-and-drop-lists v1.2.0 + * + * Copyright (c) 2014 Marcel Juenemann mail@marcel-junemann.de + * https://github.com/marceljuenemann/angular-drag-and-drop-lists + * + * License: MIT + */ +angular.module('dndLists', []) + + /** + * Use the dnd-draggable attribute to make your element draggable + * + * Attributes: + * - dnd-draggable Required attribute. The value has to be an object that represents the data + * of the element. In case of a drag and drop operation the object will be + * serialized and unserialized on the receiving end. + * - dnd-selected Callback that is invoked when the element was clicked but not dragged. + * The original click event will be provided in the local event variable. + * - dnd-effect-allowed Use this attribute to limit the operations that can be performed. Options: + * - "move": The drag operation will move the element. This is the default. + * - "copy": The drag operation will copy the element. Shows a copy cursor. + * - "copyMove": The user can choose between copy and move by pressing the + * ctrl or shift key. *Not supported in IE:* In Internet Explorer this + * option will be the same as "copy". *Not fully supported in Chrome on + * Windows:* In the Windows version of Chrome the cursor will always be the + * move cursor. However, when the user drops an element and has the ctrl + * key pressed, we will perform a copy anyways. + * - HTML5 also specifies the "link" option, but this library does not + * actively support it yet, so use it at your own risk. + * - dnd-moved Callback that is invoked when the element was moved. Usually you will + * remove your element from the original list in this callback, since the + * directive is not doing that for you automatically. The original dragend + * event will be provided in the local event variable. + * - dnd-copied Same as dnd-moved, just that it is called when the element was copied + * instead of moved. The original dragend event will be provided in the local + * event variable. + * - dnd-dragstart Callback that is invoked when the element was dragged. The original + * dragstart event will be provided in the local event variable. + * - dnd-type Use this attribute if you have different kinds of items in your + * application and you want to limit which items can be dropped into which + * lists. Combine with dnd-allowed-types on the dnd-list(s). This attribute + * should evaluate to a string, although this restriction is not enforced. + * - dnd-disable-if You can use this attribute to dynamically disable the draggability of the + * element. This is useful if you have certain list items that you don't want + * to be draggable, or if you want to disable drag & drop completely without + * having two different code branches (e.g. only allow for admins). + * **Note**: If your element is not draggable, the user is probably able to + * select text or images inside of it. Since a selection is always draggable, + * this breaks your UI. You most likely want to disable user selection via + * CSS (see user-select). + * + * CSS classes: + * - dndDragging This class will be added to the element while the element is being + * dragged. It will affect both the element you see while dragging and the + * source element that stays at it's position. Do not try to hide the source + * element with this class, because that will abort the drag operation. + * - dndDraggingSource This class will be added to the element after the drag operation was + * started, meaning it only affects the original element that is still at + * it's source position, and not the "element" that the user is dragging with + * his mouse pointer. + */ + .directive('dndDraggable', ['$parse', '$timeout', 'dndDropEffectWorkaround', 'dndDragTypeWorkaround', + function($parse, $timeout, dndDropEffectWorkaround, dndDragTypeWorkaround) { + return function(scope, element, attr) { + // Set the HTML5 draggable attribute on the element + element.attr("draggable", "true"); + + // If the dnd-disable-if attribute is set, we have to watch that + if (attr.dndDisableIf) { + scope.$watch(attr.dndDisableIf, function(disabled) { + element.attr("draggable", !disabled); + }); + } + + /** + * When the drag operation is started we have to prepare the dataTransfer object, + * which is the primary way we communicate with the target element + */ + element.on('dragstart', function(event) { + event = event.originalEvent || event; + + // Serialize the data associated with this element. IE only supports the Text drag type + event.dataTransfer.setData("Text", angular.toJson(scope.$eval(attr.dndDraggable))); + + // Only allow actions specified in dnd-effect-allowed attribute + event.dataTransfer.effectAllowed = attr.dndEffectAllowed || "move"; + + // Add CSS classes. See documentation above + element.addClass("dndDragging"); + + // Workarounds for stupid browsers, see description below + dndDropEffectWorkaround.dropEffect = "none"; + dndDragTypeWorkaround.isDragging = true; + + // + // This code was originally placed after element.addClass. + // This timeout is invoked after the 'dragend' event in IE9 (at leats on slooow virtual box) + // and since this class is used to hide elements it seems like the element is gone, + // therefor make sure the dragging still is happening when adding this class + $timeout(function() { + // Flowable This code + if (dndDragTypeWorkaround.isDragging) { + element.addClass("dndDraggingSource"); + } + }, 0); + // + + // Save type of item in global state. Usually, this would go into the dataTransfer + // typename, but we have to use "Text" there to support IE + dndDragTypeWorkaround.dragType = attr.dndType ? scope.$eval(attr.dndType) : undefined; + + // Invoke callback + $parse(attr.dndDragstart)(scope, {event: event}); + + event.stopPropagation(); + }); + + /** + * The dragend event is triggered when the element was dropped or when the drag + * operation was aborted (e.g. hit escape button). Depending on the executed action + * we will invoke the callbacks specified with the dnd-moved or dnd-copied attribute. + */ + element.on('dragend', function(event) { + event = event.originalEvent || event; + + // Invoke callbacks. Usually we would use event.dataTransfer.dropEffect to determine + // the used effect, but Chrome has not implemented that field correctly. On Windows + // it always sets it to 'none', while Chrome on Linux sometimes sets it to something + // else when it's supposed to send 'none' (drag operation aborted). + var dropEffect = dndDropEffectWorkaround.dropEffect; + scope.$apply(function() { + switch (dropEffect) { + case "move": + $parse(attr.dndMoved)(scope, {event: event}); + break; + + case "copy": + $parse(attr.dndCopied)(scope, {event: event}); + break; + } + }); + + // Clean up + element.removeClass("dndDragging"); + element.removeClass("dndDraggingSource"); + dndDragTypeWorkaround.isDragging = false; + event.stopPropagation(); + }); + + /** + * When the element is clicked we invoke the callback function + * specified with the dnd-selected attribute. + */ + element.on('click', function(event) { + event = event.originalEvent || event; + + scope.$apply(function() { + $parse(attr.dndSelected)(scope, {event: event}); + }); + + event.stopPropagation(); + }); + + /** + * Workaround to make element draggable in IE9 + */ + element.on('selectstart', function() { + if (this.dragDrop) this.dragDrop(); + return false; + }); + }; + }]) + + /** + * Use the dnd-list attribute to make your list element a dropzone. Usually you will add a single + * li element as child with the ng-repeat directive. If you don't do that, we will not be able to + * position the dropped element correctly. If you want your list to be sortable, also add the + * dnd-draggable directive to your li element(s). Both the dnd-list and it's direct children must + * have position: relative CSS style, otherwise the positioning algorithm will not be able to + * determine the correct placeholder position in all browsers. + * + * Attributes: + * - dnd-list Required attribute. The value has to be the array in which the data of + * the dropped element should be inserted. + * - dnd-allowed-types Optional array of allowed item types. When used, only items that had a + * matching dnd-type attribute will be dropable. + * - dnd-disable-if Optional boolean expresssion. When it evaluates to true, no dropping + * into the list is possible. Note that this also disables rearranging + * items inside the list. + * - dnd-horizontal-list Optional boolean expresssion. When it evaluates to true, the positioning + * algorithm will use the left and right halfs of the list items instead of + * the upper and lower halfs. + * - dnd-dragover Optional expression that is invoked when an element is dragged over the + * list. If the expression is set, but does not return true, the element is + * not allowed to be dropped. The following variables will be available: + * - event: The original dragover event sent by the browser. + * - index: The position in the list at which the element would be dropped. + * - type: The dnd-type set on the dnd-draggable, or undefined if unset. + * - dnd-drop Optional expression that is invoked when an element is dropped over the + * list. If the expression is set, it must return the object that will be + * inserted into the list. If it returns false, the drop will be aborted + * and the event is propagated. The following variables will be available: + * - event: The original drop event sent by the browser. + * - index: The position in the list at which the element would be dropped. + * - item: The transferred object. + * - type: The dnd-type set on the dnd-draggable, or undefined if unset. + * - dnd-external-sources Optional boolean expression. When it evaluates to true, the list accepts + * drops from sources outside of the current browser tab. This allows to + * drag and drop accross different browser tabs. Note that this will allow + * to drop arbitrary text into the list, thus it is highly recommended to + * implement the dnd-drop callback to check the incoming element for + * sanity. Furthermore, the dnd-type of external sources can not be + * determined, therefore do not rely on restrictions of dnd-allowed-type. + * + * CSS classes: + * - dndPlaceholder When an element is dragged over the list, a new placeholder child + * element will be added. This element is of type li and has the class + * dndPlaceholder set. + * - dndDragover Will be added to the list while an element is dragged over the list. + */ + .directive('dndList', ['$parse', '$timeout', 'dndDropEffectWorkaround', 'dndDragTypeWorkaround', + function($parse, $timeout, dndDropEffectWorkaround, dndDragTypeWorkaround) { + return function(scope, element, attr) { + // While an element is dragged over the list, this placeholder element is inserted + // at the location where the element would be inserted after dropping + var placeholder = angular.element("
  • "); + var placeholderNode = placeholder[0]; + var listNode = element[0]; + + var horizontal = attr.dndHorizontalList && scope.$eval(attr.dndHorizontalList); + var externalSources = attr.dndExternalSources && scope.$eval(attr.dndExternalSources); + + /** + * The dragover event is triggered "every few hundred milliseconds" while an element + * is being dragged over our list, or over an child element. + */ + element.on('dragover', function(event) { + event = event.originalEvent || event; + + if (!isDropAllowed(event)) { + return true; + } + + // First of all, make sure that the placeholder is shown + // This is especially important if the list is empty + if (placeholderNode.parentNode != listNode) { + element.append(placeholder); + } + + if (event.target !== listNode) { + // Try to find the node direct directly below the list node. + var listItemNode = event.target; + while (listItemNode.parentNode !== listNode && listItemNode.parentNode) { + listItemNode = listItemNode.parentNode; + } + + if (listItemNode.parentNode === listNode && listItemNode !== placeholderNode) { + // If the mouse pointer is in the upper half of the child element, + // we place it before the child element, otherwise below it. + if (isMouseInFirstHalf(event, listItemNode)) { + listNode.insertBefore(placeholderNode, listItemNode); + } else { + listNode.insertBefore(placeholderNode, listItemNode.nextSibling); + } + } + } else { + // This branch is reached when we are dragging directly over the list element. + // Usually we wouldn't need to do anything here, but the IE does not fire it's + // events for the child element, only for the list directly. Therefore we repeat + // the positioning algorithm for IE here. + if (isMouseInFirstHalf(event, placeholderNode, true)) { + // Check if we should move the placeholder element one spot towards the top. + // Note that display none elements will have offsetTop and offsetHeight set to + // zero, therefore we need a special check for them. + while (placeholderNode.previousElementSibling + && (isMouseInFirstHalf(event, placeholderNode.previousElementSibling, true) + || placeholderNode.previousElementSibling.offsetHeight === 0)) { + listNode.insertBefore(placeholderNode, placeholderNode.previousElementSibling); + } + } else { + // Check if we should move the placeholder element one spot towards the bottom + while (placeholderNode.nextElementSibling && + !isMouseInFirstHalf(event, placeholderNode.nextElementSibling, true)) { + listNode.insertBefore(placeholderNode, + placeholderNode.nextElementSibling.nextElementSibling); + } + } + } + + // At this point we invoke the callback, which still can disallow the drop. + // We can't do this earlier because we want to pass the index of the placeholder. + if (attr.dndDragover && !invokeCallback(attr.dndDragover, event)) { + return stopDragover(); + } + + element.addClass("dndDragover"); + event.preventDefault(); + event.stopPropagation(); + return false; + }); + + /** + * When the element is dropped, we use the position of the placeholder element as the + * position where we insert the transferred data. This assumes that the list has exactly + * one child element per array element. + */ + element.on('drop', function(event) { + event = event.originalEvent || event; + + if (!isDropAllowed(event)) return true; + + // The default behavior in Firefox is to interpret the dropped element as URL and + // forward to it. We want to prevent that even if our drop is aborted. + event.preventDefault(); + + // Unserialize the data that was serialized in dragstart. According to the HTML5 specs, + // the "Text" drag type will be converted to text/plain, but IE does not do that. + var data = event.dataTransfer.getData("Text") || event.dataTransfer.getData("text/plain"); + var transferredObject; + try { + transferredObject = JSON.parse(data); + } catch(e) { + return stopDragover(); + } + + // Invoke the callback, which can transform the transferredObject and even abort the drop. + if (attr.dndDrop) { + transferredObject = invokeCallback(attr.dndDrop, event, transferredObject); + if (!transferredObject) { + return stopDragover(); + } + } + + // Retrieve the JSON array and insert the transferred object into it. + var targetArray = scope.$eval(attr.dndList); + scope.$apply(function() { + targetArray.splice(getPlaceholderIndex(), 0, transferredObject); + }); + + // Invoke the callback, after the transfered objrct is added to the new container. + if (attr.dndAfterDrop) { + invokeCallback(attr.dndAfterDrop, event, transferredObject); + } + // In Chrome on Windows the dropEffect will always be none... + // We have to determine the actual effect manually from the allowed effects + if (event.dataTransfer.dropEffect === "none") { + if (event.dataTransfer.effectAllowed === "copy" || + event.dataTransfer.effectAllowed === "move") { + dndDropEffectWorkaround.dropEffect = event.dataTransfer.effectAllowed; + } else { + dndDropEffectWorkaround.dropEffect = event.ctrlKey ? "copy" : "move"; + } + } else { + dndDropEffectWorkaround.dropEffect = event.dataTransfer.dropEffect; + } + + // Clean up + stopDragover(); + event.stopPropagation(); + return false; + }); + + /** + * We have to remove the placeholder when the element is no longer dragged over our list. The + * problem is that the dragleave event is not only fired when the element leaves our list, + * but also when it leaves a child element -- so practically it's fired all the time. As a + * workaround we wait a few milliseconds and then check if the dndDragover class was added + * again. If it is there, dragover must have been called in the meantime, i.e. the element + * is still dragging over the list. If you know a better way of doing this, please tell me! + */ + element.on('dragleave', function(event) { + event = event.originalEvent || event; + + element.removeClass("dndDragover"); + $timeout(function() { + if (!element.hasClass("dndDragover")) { + placeholder.remove(); + } + }, 100); + }); + + /** + * Checks whether the mouse pointer is in the first half of the given target element. + * + * In Chrome we can just use offsetY, but in Firefox we have to use layerY, which only + * works if the child element has position relative. In IE the events are only triggered + * on the listNode instead of the listNodeItem, therefore the mouse positions are + * relative to the parent element of targetNode. + */ + function isMouseInFirstHalf(event, targetNode, relativeToParent) { + var mousePointer = horizontal ? (event.offsetX || event.layerX) + : (event.offsetY || event.layerY); + var targetSize = horizontal ? targetNode.offsetWidth : targetNode.offsetHeight; + var targetPosition = horizontal ? targetNode.offsetLeft : targetNode.offsetTop; + targetPosition = relativeToParent ? targetPosition : 0; + return mousePointer < targetPosition + targetSize / 2; + } + + /** + * Flowable-patched version of isMouseInFirstHalf that uses page and bounding client rect + * instead of the offsetX and layerX properties to determine which half of target the mouse pointer is hovering + * this is more natural since th method now actually works like above, but it also adds some mild + * flickering when sorting inside the list, why its still not in use. + */ + function isMouseInFirstHalf_new(event, targetNode, relativeToParent) { + var targetNodeRect = targetNode.getBoundingClientRect(); + if (horizontal) { + return (event.pageX - targetNodeRect.left) < (targetNodeRect.width / 2); + } + else { + return (event.pageY - targetNodeRect.top) < (targetNodeRect.height / 2); + } + } + /** + * We use the position of the placeholder node to determine at which position of the array the + * object needs to be inserted + */ + function getPlaceholderIndex() { + return Array.prototype.indexOf.call(listNode.children, placeholderNode); + } + + /** + * Checks various conditions that must be fulfilled for a drop to be allowed + */ + function isDropAllowed(event) { + // Disallow drop from external source unless it's allowed explicitly. + if (!dndDragTypeWorkaround.isDragging && !externalSources) return false; + + // Check mimetype. Usually we would use a custom drag type instead of Text, but IE doesn't + // support that. + if (!hasTextMimetype(event.dataTransfer.types)) return false; + + // Now check the dnd-allowed-types against the type of the incoming element. For drops from + // external sources we don't know the type, so it will need to be checked via dnd-drop. + if (attr.dndAllowedTypes && dndDragTypeWorkaround.isDragging) { + var allowed = scope.$eval(attr.dndAllowedTypes); + if (angular.isArray(allowed) && allowed.indexOf(dndDragTypeWorkaround.dragType) === -1) { + return false; + } + } + + // Check whether droping is disabled completely + if (attr.dndDisableIf && scope.$eval(attr.dndDisableIf)) return false; + + return true; + } + + /** + * Small helper function that cleans up if we aborted a drop. + */ + function stopDragover() { + placeholder.remove(); + element.removeClass("dndDragover"); + return true; + } + + /** + * Invokes a callback with some interesting parameters and returns the callbacks return value. + */ + function invokeCallback(expression, event, item) { + return $parse(expression)(scope, { + event: event, + index: getPlaceholderIndex(), + item: item || undefined, + external: !dndDragTypeWorkaround.isDragging, + type: dndDragTypeWorkaround.isDragging ? dndDragTypeWorkaround.dragType : undefined + }); + } + + /** + * Check if the dataTransfer object contains a drag type that we can handle. In old versions + * of IE the types collection will not even be there, so we just assume a drop is possible. + */ + function hasTextMimetype(types) { + if (!types) return true; + for (var i = 0; i < types.length; i++) { + if (types[i] === "Text" || types[i] === "text/plain") return true; + } + + return false; + } + }; + }]) + + /** + * This workaround handles the fact that Internet Explorer does not support drag types other than + * "Text" and "URL". That means we can not know whether the data comes from one of our elements or + * is just some other data like a text selection. As a workaround we save the isDragging flag in + * here. When a dropover event occurs, we only allow the drop if we are already dragging, because + * that means the element is ours. + */ + .factory('dndDragTypeWorkaround', function(){ return {} }) + + /** + * Chrome on Windows does not set the dropEffect field, which we need in dragend to determine + * whether a drag operation was successful. Therefore we have to maintain it in this global + * variable. The bug report for that has been open for years: + * https://code.google.com/p/chromium/issues/detail?id=39399 + */ + .factory('dndDropEffectWorkaround', function(){ return {} }); diff --git a/snow-flowable/src/main/resources/static/libs/angular-drag-and-drop-lists_1.2.0/angular-drag-and-drop-lists.min.js b/snow-flowable/src/main/resources/static/libs/angular-drag-and-drop-lists_1.2.0/angular-drag-and-drop-lists.min.js new file mode 100644 index 0000000..d21e062 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-drag-and-drop-lists_1.2.0/angular-drag-and-drop-lists.min.js @@ -0,0 +1 @@ +angular.module("dndLists",[]).directive("dndDraggable",["$parse","$timeout","dndDropEffectWorkaround","dndDragTypeWorkaround",function(e,t,n,r){return function(i,s,o){s.attr("draggable","true");if(o.dndDisableIf){i.$watch(o.dndDisableIf,function(e){s.attr("draggable",!e)})}s.on("dragstart",function(u){u=u.originalEvent||u;u.dataTransfer.setData("Text",angular.toJson(i.$eval(o.dndDraggable)));u.dataTransfer.effectAllowed=o.dndEffectAllowed||"move";s.addClass("dndDragging");t(function(){s.addClass("dndDraggingSource")},0);n.dropEffect="none";r.isDragging=true;r.dragType=o.dndType?i.$eval(o.dndType):undefined;e(o.dndDragstart)(i,{event:u});u.stopPropagation()});s.on("dragend",function(t){t=t.originalEvent||t;var u=n.dropEffect;i.$apply(function(){switch(u){case"move":e(o.dndMoved)(i,{event:t});break;case"copy":e(o.dndCopied)(i,{event:t});break}});s.removeClass("dndDragging");s.removeClass("dndDraggingSource");r.isDragging=false;t.stopPropagation()});s.on("click",function(t){t=t.originalEvent||t;i.$apply(function(){e(o.dndSelected)(i,{event:t})});t.stopPropagation()});s.on("selectstart",function(){if(this.dragDrop)this.dragDrop();return false})}}]).directive("dndList",["$parse","$timeout","dndDropEffectWorkaround","dndDragTypeWorkaround",function(e,t,n,r){return function(i,s,o){function h(e,t,n){var r=l?e.offsetX||e.layerX:e.offsetY||e.layerY;var i=l?t.offsetWidth:t.offsetHeight;var s=l?t.offsetLeft:t.offsetTop;s=n?s:0;return r");var a=u[0];var f=s[0];var l=o.dndHorizontalList&&i.$eval(o.dndHorizontalList);var c=o.dndExternalSources&&i.$eval(o.dndExternalSources);s.on("dragover",function(e){e=e.originalEvent||e;if(!d(e))return true;if(a.parentNode!=f){s.append(u)}if(e.target!==f){var t=e.target;while(t.parentNode!==f&&t.parentNode){t=t.parentNode}if(t.parentNode===f&&t!==a){if(h(e,t)){f.insertBefore(a,t)}else{f.insertBefore(a,t.nextSibling)}}}else{if(h(e,a,true)){while(a.previousElementSibling&&(h(e,a.previousElementSibling,true)||a.previousElementSibling.offsetHeight===0)){f.insertBefore(a,a.previousElementSibling)}}else{while(a.nextElementSibling&&!h(e,a.nextElementSibling,true)){f.insertBefore(a,a.nextElementSibling.nextElementSibling)}}}if(o.dndDragover&&!m(o.dndDragover,e)){return v()}s.addClass("dndDragover");e.preventDefault();e.stopPropagation();return false});s.on("drop",function(e){e=e.originalEvent||e;if(!d(e))return true;e.preventDefault();var t=e.dataTransfer.getData("Text")||e.dataTransfer.getData("text/plain");var r;try{r=JSON.parse(t)}catch(s){return v()}if(o.dndDrop){r=m(o.dndDrop,e,r);if(!r){return v()}}var u=i.$eval(o.dndList);i.$apply(function(){u.splice(p(),0,r)});if(e.dataTransfer.dropEffect==="none"){if(e.dataTransfer.effectAllowed==="copy"||e.dataTransfer.effectAllowed==="move"){n.dropEffect=e.dataTransfer.effectAllowed}else{n.dropEffect=e.ctrlKey?"copy":"move"}}else{n.dropEffect=e.dataTransfer.dropEffect}v();e.stopPropagation();return false});s.on("dragleave",function(e){e=e.originalEvent||e;s.removeClass("dndDragover");t(function(){if(!s.hasClass("dndDragover")){u.remove()}},100)})}}]).factory("dndDragTypeWorkaround",function(){return{}}).factory("dndDropEffectWorkaround",function(){return{}}) diff --git a/snow-flowable/src/main/resources/static/libs/angular-dragdrop_1.0.11/angular-dragdrop.js b/snow-flowable/src/main/resources/static/libs/angular-dragdrop_1.0.11/angular-dragdrop.js new file mode 100644 index 0000000..20aee96 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-dragdrop_1.0.11/angular-dragdrop.js @@ -0,0 +1,360 @@ +/** + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** + * Implementing Drag and Drop functionality in AngularJS is easier than ever. + * Demo: http://codef0rmer.github.com/angular-dragdrop/ + * + * @version 1.0.11 + * + * (c) 2013 Amit Gharat a.k.a codef0rmer - amitgharat.wordpress.com + */ + +(function (window, angular, $, undefined) { + 'use strict'; + + var jqyoui = angular.module('ngDragDrop', []).service('ngDragDropService', ['$timeout', '$parse', function($timeout, $parse) { + this.draggableScope = null; + this.droppableScope = null; + + this.callEventCallback = function (scope, callbackName, event, ui) { + if (!callbackName) return; + + var objExtract = extract(callbackName), + callback = objExtract.callback, + constructor = objExtract.constructor, + args = [event, ui].concat(objExtract.args); + + // call either $scoped method i.e. $scope.dropCallback or constructor's method i.e. this.dropCallback. + // Removing scope.$apply call that was performance intensive (especially onDrag) and does not require it + // always. So call it within the callback if needed. + return (scope[callback] || scope[constructor][callback]).apply(scope, args); + + function extract(callbackName) { + var atStartBracket = callbackName.indexOf('(') !== -1 ? callbackName.indexOf('(') : callbackName.length, + atEndBracket = callbackName.lastIndexOf(')') !== -1 ? callbackName.lastIndexOf(')') : callbackName.length, + args = callbackName.substring(atStartBracket + 1, atEndBracket), // matching function arguments inside brackets + constructor = callbackName.match(/^[^.]+.\s*/)[0].slice(0, -1); // matching a string upto a dot to check ctrl as syntax + constructor = scope[constructor] && typeof scope[constructor].constructor === 'function' ? constructor : null; + + return { + callback: callbackName.substring(constructor && constructor.length + 1 || 0, atStartBracket), + args: $.map(args && args.split(',') || [], function(item) { return [$parse(item)(scope)]; }), + constructor: constructor + } + } + }; + + this.invokeDrop = function ($draggable, $droppable, event, ui) { + var dragModel = '', + dropModel = '', + dragSettings = {}, + dropSettings = {}, + jqyoui_pos = null, + dragItem = {}, + dropItem = {}, + dragModelValue, + dropModelValue, + $droppableDraggable = null, + droppableScope = this.droppableScope, + draggableScope = this.draggableScope; + + dragModel = $draggable.ngattr('ng-model'); + dropModel = $droppable.ngattr('ng-model'); + dragModelValue = draggableScope.$eval(dragModel); + dropModelValue = droppableScope.$eval(dropModel); + + $droppableDraggable = $droppable.find('[jqyoui-draggable]:last,[data-jqyoui-draggable]:last'); + dropSettings = droppableScope.$eval($droppable.attr('jqyoui-droppable') || $droppable.attr('data-jqyoui-droppable')) || []; + dragSettings = draggableScope.$eval($draggable.attr('jqyoui-draggable') || $draggable.attr('data-jqyoui-draggable')) || []; + + // Helps pick up the right item + dragSettings.index = this.fixIndex(draggableScope, dragSettings, dragModelValue); + dropSettings.index = this.fixIndex(droppableScope, dropSettings, dropModelValue); + + jqyoui_pos = angular.isArray(dragModelValue) ? dragSettings.index : null; + dragItem = angular.isArray(dragModelValue) ? dragModelValue[jqyoui_pos] : dragModelValue; + + if (dragSettings.deepCopy) { + dragItem = angular.copy(dragItem); + } + + if (angular.isArray(dropModelValue) && dropSettings && dropSettings.index !== undefined) { + dropItem = dropModelValue[dropSettings.index]; + } else if (!angular.isArray(dropModelValue)) { + dropItem = dropModelValue; + } else { + dropItem = {}; + } + + if (dropSettings.deepCopy) { + dropItem = angular.copy(dropItem); + } + + if (dragSettings.animate === true) { + this.move($draggable, $droppableDraggable.length > 0 ? $droppableDraggable : $droppable, null, 'fast', dropSettings, null); + this.move($droppableDraggable.length > 0 && !dropSettings.multiple ? $droppableDraggable : [], $draggable.parent('[jqyoui-droppable],[data-jqyoui-droppable]'), jqyoui.startXY, 'fast', dropSettings, angular.bind(this, function() { + $timeout(angular.bind(this, function() { + // Do not move this into move() to avoid flickering issue + $draggable.css({'position': 'relative', 'left': '', 'top': ''}); + // Angular v1.2 uses ng-hide to hide an element not display property + // so we've to manually remove display:none set in this.move() + $droppableDraggable.css({'position': 'relative', 'left': '', 'top': '', 'display': $droppableDraggable.css('display') === 'none' ? '' : $droppableDraggable.css('display')}); + + this.mutateDraggable(draggableScope, dropSettings, dragSettings, dragModel, dropModel, dropItem, $draggable); + this.mutateDroppable(droppableScope, dropSettings, dragSettings, dropModel, dragItem, jqyoui_pos); + this.callEventCallback(droppableScope, dropSettings.onDrop, event, ui); + })); + })); + } else { + $timeout(angular.bind(this, function() { + this.mutateDraggable(draggableScope, dropSettings, dragSettings, dragModel, dropModel, dropItem, $draggable); + this.mutateDroppable(droppableScope, dropSettings, dragSettings, dropModel, dragItem, jqyoui_pos); + this.callEventCallback(droppableScope, dropSettings.onDrop, event, ui); + })); + } + }; + + this.move = function($fromEl, $toEl, toPos, duration, dropSettings, callback) { + if ($fromEl.length === 0) { + if (callback) { + window.setTimeout(function() { + callback(); + }, 300); + } + return false; + } + + var zIndex = $fromEl.css('z-index'), + fromPos = $fromEl[dropSettings.containment || 'offset'](), + displayProperty = $toEl.css('display'), // sometimes `display` is other than `block` + hadNgHideCls = $toEl.hasClass('ng-hide'); + + if (toPos === null && $toEl.length > 0) { + if (($toEl.attr('jqyoui-draggable') || $toEl.attr('data-jqyoui-draggable')) !== undefined && $toEl.ngattr('ng-model') !== undefined && $toEl.is(':visible') && dropSettings && dropSettings.multiple) { + toPos = $toEl[dropSettings.containment || 'offset'](); + if (dropSettings.stack === false) { + toPos.left+= $toEl.outerWidth(true); + } else { + toPos.top+= $toEl.outerHeight(true); + } + } else { + // Angular v1.2 uses ng-hide to hide an element + // so we've to remove it in order to grab its position + if (hadNgHideCls) $toEl.removeClass('ng-hide'); + toPos = $toEl.css({'visibility': 'hidden', 'display': 'block'})[dropSettings.containment || 'offset'](); + $toEl.css({'visibility': '','display': displayProperty}); + } + } + + $fromEl.css({'position': 'absolute', 'z-index': 9999}) + .css(fromPos) + .animate(toPos, duration, function() { + // Angular v1.2 uses ng-hide to hide an element + // and as we remove it above, we've to put it back to + // hide the element (while swapping) if it was hidden already + // because we remove the display:none in this.invokeDrop() + if (hadNgHideCls) $toEl.addClass('ng-hide'); + $fromEl.css('z-index', zIndex); + if (callback) callback(); + }); + }; + + this.mutateDroppable = function(scope, dropSettings, dragSettings, dropModel, dragItem, jqyoui_pos) { + var dropModelValue = scope.$eval(dropModel); + + scope.dndDragItem = dragItem; + + if (angular.isArray(dropModelValue)) { + if (dropSettings && dropSettings.index >= 0) { + dropModelValue[dropSettings.index] = dragItem; + } else { + dropModelValue.push(dragItem); + } + if (dragSettings && dragSettings.placeholder === true) { + dropModelValue[dropModelValue.length - 1]['jqyoui_pos'] = jqyoui_pos; + } + } else { + $parse(dropModel + ' = dndDragItem')(scope); + if (dragSettings && dragSettings.placeholder === true) { + dropModelValue['jqyoui_pos'] = jqyoui_pos; + } + } + }; + + this.mutateDraggable = function(scope, dropSettings, dragSettings, dragModel, dropModel, dropItem, $draggable) { + var isEmpty = angular.equals(dropItem, {}) || !dropItem, + dragModelValue = scope.$eval(dragModel); + + scope.dndDropItem = dropItem; + + if (dragSettings && dragSettings.placeholder) { + if (dragSettings.placeholder != 'keep'){ + if (angular.isArray(dragModelValue) && dragSettings.index !== undefined) { + dragModelValue[dragSettings.index] = dropItem; + } else { + $parse(dragModel + ' = dndDropItem')(scope); + } + } + } else { + if (angular.isArray(dragModelValue)) { + if (isEmpty) { + if (dragSettings && ( dragSettings.placeholder !== true && dragSettings.placeholder !== 'keep' )) { + dragModelValue.splice(dragSettings.index, 1); + } + } else { + dragModelValue[dragSettings.index] = dropItem; + } + } else { + // Fix: LIST(object) to LIST(array) - model does not get updated using just scope[dragModel] = {...} + // P.S.: Could not figure out why it happened + $parse(dragModel + ' = dndDropItem')(scope); + if (scope.$parent) { + $parse(dragModel + ' = dndDropItem')(scope.$parent); + } + } + } + + $draggable.css({'z-index': '', 'left': '', 'top': ''}); + }; + + this.fixIndex = function(scope, settings, modelValue) { + if (settings.applyFilter && angular.isArray(modelValue) && modelValue.length > 0) { + var dragModelValueFiltered = scope[settings.applyFilter](), + lookup = dragModelValueFiltered[settings.index], + actualIndex = undefined; + + modelValue.forEach(function(item, i) { + if (angular.equals(item, lookup)) { + actualIndex = i; + } + }); + + return actualIndex; + } + + return settings.index; + }; + }]).directive('jqyouiDraggable', ['ngDragDropService', function(ngDragDropService) { + return { + require: '?jqyouiDroppable', + restrict: 'A', + link: function(scope, element, attrs) { + var dragSettings, jqyouiOptions, zIndex; + var updateDraggable = function(newValue, oldValue) { + if (newValue) { + dragSettings = scope.$eval(element.attr('jqyoui-draggable') || element.attr('data-jqyoui-draggable')) || {}; + jqyouiOptions = scope.$eval(attrs.jqyouiOptions) || {}; + element + .draggable({disabled: false}) + .draggable(jqyouiOptions) + .draggable({ + start: function(event, ui) { + ngDragDropService.draggableScope = scope; + zIndex = angular.element(jqyouiOptions.helper ? ui.helper : this).css('z-index'); + angular.element(jqyouiOptions.helper ? ui.helper : this).css('z-index', 9999); + jqyoui.startXY = angular.element(this)[dragSettings.containment || 'offset'](); + ngDragDropService.callEventCallback(scope, dragSettings.onStart, event, ui); + }, + stop: function(event, ui) { + angular.element(jqyouiOptions.helper ? ui.helper : this).css('z-index', zIndex); + ngDragDropService.callEventCallback(scope, dragSettings.onStop, event, ui); + }, + drag: function(event, ui) { + ngDragDropService.callEventCallback(scope, dragSettings.onDrag, event, ui); + } + }); + } else { + element.draggable({disabled: true}); + } + }; + scope.$watch(function() { return scope.$eval(attrs.drag); }, updateDraggable); + updateDraggable(); + + element.on('$destroy', function() { + element.draggable({disabled: true}).draggable('destroy'); + }); + } + }; + }]).directive('jqyouiDroppable', ['ngDragDropService', '$q', function(ngDragDropService, $q) { + return { + restrict: 'A', + priority: 1, + link: function(scope, element, attrs) { + var dropSettings; + var updateDroppable = function(newValue, oldValue) { + if (newValue) { + dropSettings = scope.$eval(angular.element(element).attr('jqyoui-droppable') || angular.element(element).attr('data-jqyoui-droppable')) || {}; + element + .droppable({disabled: false}) + .droppable(scope.$eval(attrs.jqyouiOptions) || {}) + .droppable({ + over: function(event, ui) { + ngDragDropService.callEventCallback(scope, dropSettings.onOver, event, ui); + }, + out: function(event, ui) { + ngDragDropService.callEventCallback(scope, dropSettings.onOut, event, ui); + }, + drop: function(event, ui) { + var beforeDropPromise = null; + + if (dropSettings.beforeDrop) { + beforeDropPromise = ngDragDropService.callEventCallback(scope, dropSettings.beforeDrop, event, ui); + } else { + beforeDropPromise = (function() { + var deferred = $q.defer(); + deferred.resolve(); + return deferred.promise; + })(); + } + + beforeDropPromise.then(angular.bind(this, function() { + if (angular.element(ui.draggable).ngattr('ng-model') && attrs.ngModel) { + ngDragDropService.droppableScope = scope; + ngDragDropService.invokeDrop(angular.element(ui.draggable), angular.element(this), event, ui); + } else { + ngDragDropService.callEventCallback(scope, dropSettings.onDrop, event, ui); + } + }), function() { + ui.draggable.css({left: '', top: ''}); + }); + } + }); + } else { + element.droppable({disabled: true}); + } + }; + + scope.$watch(function() { return scope.$eval(attrs.drop); }, updateDroppable); + updateDroppable(); + + element.on('$destroy', function() { + element.droppable({disabled: true}).droppable('destroy'); + }); + } + }; + }]); + + angular.element.prototype.ngattr = function(name, value) { + var element = angular.element(this).get(0); + + return element.getAttribute(name) || element.getAttribute('data-' + name); + }; +})(window, window.angular, window.jQuery); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/libs/angular-dragdrop_1.0.11/angular-dragdrop.min.js b/snow-flowable/src/main/resources/static/libs/angular-dragdrop_1.0.11/angular-dragdrop.min.js new file mode 100644 index 0000000..bfb1cf8 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-dragdrop_1.0.11/angular-dragdrop.min.js @@ -0,0 +1,29 @@ +/** + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** + * Implementing Drag and Drop functionality in AngularJS is easier than ever. + * Demo: http://codef0rmer.github.com/angular-dragdrop/ + * + * @version 1.0.11 + * + * (c) 2013 Amit Gharat a.k.a codef0rmer - amitgharat.wordpress.com + */ +(function(e,t,n,r){"use strict";var i=t.module("ngDragDrop",[]).service("ngDragDropService",["$timeout","$parse",function(s,o){this.draggableScope=null;this.droppableScope=null;this.callEventCallback=function(e,t,r,i){function l(t){var r=t.indexOf("(")!==-1?t.indexOf("("):t.length,i=t.lastIndexOf(")")!==-1?t.lastIndexOf(")"):t.length,s=t.substring(r+1,i),u=t.match(/^[^.]+.\s*/)[0].slice(0,-1);u=e[u]&&typeof e[u].constructor==="function"?u:null;return{callback:t.substring(u&&u.length+1||0,r),args:n.map(s&&s.split(",")||[],function(t){return[o(t)(e)]}),constructor:u}}if(!t)return;var s=l(t),u=s.callback,a=s.constructor,f=[r,i].concat(s.args);return(e[u]||e[a][u]).apply(e,f)};this.invokeDrop=function(e,n,o,u){var a="",f="",l={},c={},h=null,p={},d={},v,m,g=null,y=this.droppableScope,b=this.draggableScope;a=e.ngattr("ng-model");f=n.ngattr("ng-model");v=b.$eval(a);m=y.$eval(f);g=n.find("[jqyoui-draggable]:last,[data-jqyoui-draggable]:last");c=y.$eval(n.attr("jqyoui-droppable")||n.attr("data-jqyoui-droppable"))||[];l=b.$eval(e.attr("jqyoui-draggable")||e.attr("data-jqyoui-draggable"))||[];l.index=this.fixIndex(b,l,v);c.index=this.fixIndex(y,c,m);h=t.isArray(v)?l.index:null;p=t.isArray(v)?v[h]:v;if(l.deepCopy){p=t.copy(p)}if(t.isArray(m)&&c&&c.index!==r){d=m[c.index]}else if(!t.isArray(m)){d=m}else{d={}}if(c.deepCopy){d=t.copy(d)}if(l.animate===true){this.move(e,g.length>0?g:n,null,"fast",c,null);this.move(g.length>0&&!c.multiple?g:[],e.parent("[jqyoui-droppable],[data-jqyoui-droppable]"),i.startXY,"fast",c,t.bind(this,function(){s(t.bind(this,function(){e.css({position:"relative",left:"",top:""});g.css({position:"relative",left:"",top:"",display:g.css("display")==="none"?"":g.css("display")});this.mutateDraggable(b,c,l,a,f,d,e);this.mutateDroppable(y,c,l,f,p,h);this.callEventCallback(y,c.onDrop,o,u)}))}))}else{s(t.bind(this,function(){this.mutateDraggable(b,c,l,a,f,d,e);this.mutateDroppable(y,c,l,f,p,h);this.callEventCallback(y,c.onDrop,o,u)}))}};this.move=function(t,n,i,s,o,u){if(t.length===0){if(u){e.setTimeout(function(){u()},300)}return false}var a=t.css("z-index"),f=t[o.containment||"offset"](),l=n.css("display"),c=n.hasClass("ng-hide");if(i===null&&n.length>0){if((n.attr("jqyoui-draggable")||n.attr("data-jqyoui-draggable"))!==r&&n.ngattr("ng-model")!==r&&n.is(":visible")&&o&&o.multiple){i=n[o.containment||"offset"]();if(o.stack===false){i.left+=n.outerWidth(true)}else{i.top+=n.outerHeight(true)}}else{if(c)n.removeClass("ng-hide");i=n.css({visibility:"hidden",display:"block"})[o.containment||"offset"]();n.css({visibility:"",display:l})}}t.css({position:"absolute","z-index":9999}).css(f).animate(i,s,function(){if(c)n.addClass("ng-hide");t.css("z-index",a);if(u)u()})};this.mutateDroppable=function(e,n,r,i,s,u){var a=e.$eval(i);e.dndDragItem=s;if(t.isArray(a)){if(n&&n.index>=0){a[n.index]=s}else{a.push(s)}if(r&&r.placeholder===true){a[a.length-1]["jqyoui_pos"]=u}}else{o(i+" = dndDragItem")(e);if(r&&r.placeholder===true){a["jqyoui_pos"]=u}}};this.mutateDraggable=function(e,n,i,s,u,a,f){var l=t.equals(a,{})||!a,c=e.$eval(s);e.dndDropItem=a;if(i&&i.placeholder){if(i.placeholder!="keep"){if(t.isArray(c)&&i.index!==r){c[i.index]=a}else{o(s+" = dndDropItem")(e)}}}else{if(t.isArray(c)){if(l){if(i&&i.placeholder!==true&&i.placeholder!=="keep"){c.splice(i.index,1)}}else{c[i.index]=a}}else{o(s+" = dndDropItem")(e);if(e.$parent){o(s+" = dndDropItem")(e.$parent)}}}f.css({"z-index":"",left:"",top:""})};this.fixIndex=function(e,n,i){if(n.applyFilter&&t.isArray(i)&&i.length>0){var s=e[n.applyFilter](),o=s[n.index],u=r;i.forEach(function(e,n){if(t.equals(e,o)){u=n}});return u}return n.index}}]).directive("jqyouiDraggable",["ngDragDropService",function(e){return{require:"?jqyouiDroppable",restrict:"A",link:function(n,r,s){var o,u,a;var f=function(f,l){if(f){o=n.$eval(r.attr("jqyoui-draggable")||r.attr("data-jqyoui-draggable"))||{};u=n.$eval(s.jqyouiOptions)||{};r.draggable({disabled:false}).draggable(u).draggable({start:function(r,s){e.draggableScope=n;a=t.element(u.helper?s.helper:this).css("z-index");t.element(u.helper?s.helper:this).css("z-index",9999);i.startXY=t.element(this)[o.containment||"offset"]();e.callEventCallback(n,o.onStart,r,s)},stop:function(r,i){t.element(u.helper?i.helper:this).css("z-index",a);e.callEventCallback(n,o.onStop,r,i)},drag:function(t,r){e.callEventCallback(n,o.onDrag,t,r)}})}else{r.draggable({disabled:true})}};n.$watch(function(){return n.$eval(s.drag)},f);f();r.on("$destroy",function(){r.draggable({disabled:true}).draggable("destroy")})}}}]).directive("jqyouiDroppable",["ngDragDropService","$q",function(e,n){return{restrict:"A",priority:1,link:function(r,i,s){var o;var u=function(u,a){if(u){o=r.$eval(t.element(i).attr("jqyoui-droppable")||t.element(i).attr("data-jqyoui-droppable"))||{};i.droppable({disabled:false}).droppable(r.$eval(s.jqyouiOptions)||{}).droppable({over:function(t,n){e.callEventCallback(r,o.onOver,t,n)},out:function(t,n){e.callEventCallback(r,o.onOut,t,n)},drop:function(i,u){var a=null;if(o.beforeDrop){a=e.callEventCallback(r,o.beforeDrop,i,u)}else{a=function(){var e=n.defer();e.resolve();return e.promise}()}a.then(t.bind(this,function(){if(t.element(u.draggable).ngattr("ng-model")&&s.ngModel){e.droppableScope=r;e.invokeDrop(t.element(u.draggable),t.element(this),i,u)}else{e.callEventCallback(r,o.onDrop,i,u)}}),function(){u.draggable.css({left:"",top:""})})}})}else{i.droppable({disabled:true})}};r.$watch(function(){return r.$eval(s.drop)},u);u();i.on("$destroy",function(){i.droppable({disabled:true}).droppable("destroy")})}}}]);t.element.prototype.ngattr=function(e,n){var r=t.element(this).get(0);return r.getAttribute(e)||r.getAttribute("data-"+e)}})(window,window.angular,window.jQuery) \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/libs/angular-gridster_0.11.7/angular-gridster.js b/snow-flowable/src/main/resources/static/libs/angular-gridster_0.11.7/angular-gridster.js new file mode 100644 index 0000000..37b400c --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-gridster_0.11.7/angular-gridster.js @@ -0,0 +1,2109 @@ +(function(angular) { + + 'use strict'; + + angular.module('gridster', []) + + .constant('gridsterConfig', { + columns: 6, // number of columns in the grid + pushing: true, // whether to push other items out of the way + floating: true, // whether to automatically float items up so they stack + swapping: false, // whether or not to have items switch places instead of push down if they are the same size + width: 'auto', // width of the grid. "auto" will expand the grid to its parent container + colWidth: 'auto', // width of grid columns. "auto" will divide the width of the grid evenly among the columns + rowHeight: 'match', // height of grid rows. 'match' will make it the same as the column width, a numeric value will be interpreted as pixels, '/2' is half the column width, '*5' is five times the column width, etc. + margins: [10, 10], // margins in between grid items + outerMargin: true, + isMobile: false, // toggle mobile view + mobileBreakPoint: 600, // width threshold to toggle mobile mode + mobileModeEnabled: true, // whether or not to toggle mobile mode when screen width is less than mobileBreakPoint + minColumns: 1, // minimum amount of columns the grid can scale down to + minRows: 1, // minimum amount of rows to show if the grid is empty + maxRows: 100, // maximum amount of rows in the grid + defaultSizeX: 2, // default width of an item in columns + defaultSizeY: 1, // default height of an item in rows + minSizeX: 1, // minimum column width of an item + maxSizeX: null, // maximum column width of an item + minSizeY: 1, // minumum row height of an item + maxSizeY: null, // maximum row height of an item + saveGridItemCalculatedHeightInMobile: false, // grid item height in mobile display. true- to use the calculated height by sizeY given + resizable: { // options to pass to resizable handler + enabled: true, + handles: ['s', 'e', 'n', 'w', 'se', 'ne', 'sw', 'nw'] + }, + draggable: { // options to pass to draggable handler + enabled: true, + scrollSensitivity: 20, // Distance in pixels from the edge of the viewport after which the viewport should scroll, relative to pointer + scrollSpeed: 15 // Speed at which the window should scroll once the mouse pointer gets within scrollSensitivity distance + } + }) + + .controller('GridsterCtrl', ['gridsterConfig', '$timeout', + function(gridsterConfig, $timeout) { + + var gridster = this; + + /** + * Create options from gridsterConfig constant + */ + angular.extend(this, gridsterConfig); + + this.resizable = angular.extend({}, gridsterConfig.resizable || {}); + this.draggable = angular.extend({}, gridsterConfig.draggable || {}); + + var flag = false; + this.layoutChanged = function() { + if (flag) { + return; + } + flag = true; + $timeout(function() { + flag = false; + if (gridster.loaded) { + gridster.floatItemsUp(); + } + gridster.updateHeight(gridster.movingItem ? gridster.movingItem.sizeY : 0); + }); + }; + + /** + * A positional array of the items in the grid + */ + this.grid = []; + + /** + * Clean up after yourself + */ + this.destroy = function() { + if (this.grid) { + this.grid.length = 0; + this.grid = null; + } + }; + + /** + * Overrides default options + * + * @param {object} options The options to override + */ + this.setOptions = function(options) { + if (!options) { + return; + } + + options = angular.extend({}, options); + + // all this to avoid using jQuery... + if (options.draggable) { + angular.extend(this.draggable, options.draggable); + delete(options.draggable); + } + if (options.resizable) { + angular.extend(this.resizable, options.resizable); + delete(options.resizable); + } + + angular.extend(this, options); + + if (!this.margins || this.margins.length !== 2) { + this.margins = [0, 0]; + } else { + for (var x = 0, l = this.margins.length; x < l; ++x) { + this.margins[x] = parseInt(this.margins[x], 10); + if (isNaN(this.margins[x])) { + this.margins[x] = 0; + } + } + } + }; + + /** + * Check if item can occupy a specified position in the grid + * + * @param {object} item The item in question + * @param {number} row The row index + * @param {number} column The column index + * @returns {boolean} True if if item fits + */ + this.canItemOccupy = function(item, row, column) { + return row > -1 && column > -1 && item.sizeX + column <= this.columns && item.sizeY + row <= this.maxRows; + }; + + /** + * Set the item in the first suitable position + * + * @param {object} item The item to insert + */ + this.autoSetItemPosition = function(item) { + // walk through each row and column looking for a place it will fit + for (var rowIndex = 0; rowIndex < this.maxRows; ++rowIndex) { + for (var colIndex = 0; colIndex < this.columns; ++colIndex) { + // only insert if position is not already taken and it can fit + var items = this.getItems(rowIndex, colIndex, item.sizeX, item.sizeY, item); + if (items.length === 0 && this.canItemOccupy(item, rowIndex, colIndex)) { + this.putItem(item, rowIndex, colIndex); + return; + } + } + } + throw new Error('Unable to place item!'); + }; + + /** + * Gets items at a specific coordinate + * + * @param {number} row + * @param {number} column + * @param {number} sizeX + * @param {number} sizeY + * @param {array} excludeItems An array of items to exclude from selection + * @returns {array} Items that match the criteria + */ + this.getItems = function(row, column, sizeX, sizeY, excludeItems) { + var items = []; + if (!sizeX || !sizeY) { + sizeX = sizeY = 1; + } + if (excludeItems && !(excludeItems instanceof Array)) { + excludeItems = [excludeItems]; + } + for (var h = 0; h < sizeY; ++h) { + for (var w = 0; w < sizeX; ++w) { + var item = this.getItem(row + h, column + w, excludeItems); + if (item && (!excludeItems || excludeItems.indexOf(item) === -1) && items.indexOf(item) === -1) { + items.push(item); + } + } + } + return items; + }; + + this.getBoundingBox = function(items) { + + if (items.length === 0) { + return null; + } + if (items.length === 1) { + return { + row: items[0].row, + col: items[0].col, + sizeY: items[0].sizeY, + sizeX: items[0].sizeX + }; + } + + var maxRow = 0; + var maxCol = 0; + var minRow = 9999; + var minCol = 9999; + + for (var i = 0, l = items.length; i < l; ++i) { + var item = items[i]; + minRow = Math.min(item.row, minRow); + minCol = Math.min(item.col, minCol); + maxRow = Math.max(item.row + item.sizeY, maxRow); + maxCol = Math.max(item.col + item.sizeX, maxCol); + } + + return { + row: minRow, + col: minCol, + sizeY: maxRow - minRow, + sizeX: maxCol - minCol + }; + }; + + + /** + * Removes an item from the grid + * + * @param {object} item + */ + this.removeItem = function(item) { + for (var rowIndex = 0, l = this.grid.length; rowIndex < l; ++rowIndex) { + var columns = this.grid[rowIndex]; + if (!columns) { + continue; + } + var index = columns.indexOf(item); + if (index !== -1) { + columns[index] = null; + break; + } + } + this.layoutChanged(); + }; + + /** + * Returns the item at a specified coordinate + * + * @param {number} row + * @param {number} column + * @param {array} excludeitems Items to exclude from selection + * @returns {object} The matched item or null + */ + this.getItem = function(row, column, excludeItems) { + if (excludeItems && !(excludeItems instanceof Array)) { + excludeItems = [excludeItems]; + } + var sizeY = 1; + while (row > -1) { + var sizeX = 1, + col = column; + while (col > -1) { + var items = this.grid[row]; + if (items) { + var item = items[col]; + if (item && (!excludeItems || excludeItems.indexOf(item) === -1) && item.sizeX >= sizeX && item.sizeY >= sizeY) { + return item; + } + } + ++sizeX; + --col; + } + --row; + ++sizeY; + } + return null; + }; + + /** + * Insert an array of items into the grid + * + * @param {array} items An array of items to insert + */ + this.putItems = function(items) { + for (var i = 0, l = items.length; i < l; ++i) { + this.putItem(items[i]); + } + }; + + /** + * Insert a single item into the grid + * + * @param {object} item The item to insert + * @param {number} row (Optional) Specifies the items row index + * @param {number} column (Optional) Specifies the items column index + * @param {array} ignoreItems + */ + this.putItem = function(item, row, column, ignoreItems) { + if (typeof row === 'undefined' || row === null) { + row = item.row; + column = item.col; + if (typeof row === 'undefined' || row === null) { + this.autoSetItemPosition(item); + return; + } + } + if (!this.canItemOccupy(item, row, column)) { + column = Math.min(this.columns - item.sizeX, Math.max(0, column)); + row = Math.min(this.maxRows - item.sizeY, Math.max(0, row)); + } + + if (item.oldRow !== null && typeof item.oldRow !== 'undefined') { + var samePosition = item.oldRow === row && item.oldColumn === column; + var inGrid = this.grid[row] && this.grid[row][column] === item; + if (samePosition && inGrid) { + item.row = row; + item.col = column; + return; + } else { + // remove from old position + var oldRow = this.grid[item.oldRow]; + if (oldRow && oldRow[item.oldColumn] === item) { + delete oldRow[item.oldColumn]; + } + } + } + + item.oldRow = item.row = row; + item.oldColumn = item.col = column; + + this.moveOverlappingItems(item, ignoreItems); + + if (!this.grid[row]) { + this.grid[row] = []; + } + this.grid[row][column] = item; + + if (this.movingItem === item) { + this.floatItemUp(item); + } + this.layoutChanged(); + }; + + /** + * Trade row and column if item1 with item2 + * + * @param {object} item1 + * @param {object} item2 + */ + this.swapItems = function(item1, item2) { + this.grid[item1.row][item1.col] = item2; + this.grid[item2.row][item2.col] = item1; + + var item1Row = item1.row; + var item1Col = item1.col; + item1.row = item2.row; + item1.col = item2.col; + item2.row = item1Row; + item2.col = item1Col; + }; + + /** + * Prevents items from being overlapped + * + * @param {object} item The item that should remain + * @param {array} ignoreItems + */ + this.moveOverlappingItems = function(item, ignoreItems) { + if (ignoreItems) { + if (ignoreItems.indexOf(item) === -1) { + ignoreItems = ignoreItems.slice(0); + ignoreItems.push(item); + } + } else { + ignoreItems = [item]; + } + var overlappingItems = this.getItems( + item.row, + item.col, + item.sizeX, + item.sizeY, + ignoreItems + ); + this.moveItemsDown(overlappingItems, item.row + item.sizeY, ignoreItems); + }; + + /** + * Moves an array of items to a specified row + * + * @param {array} items The items to move + * @param {number} newRow The target row + * @param {array} ignoreItems + */ + this.moveItemsDown = function(items, newRow, ignoreItems) { + if (!items || items.length === 0) { + return; + } + items.sort(function(a, b) { + return a.row - b.row; + }); + ignoreItems = ignoreItems ? ignoreItems.slice(0) : []; + var topRows = {}, + item, i, l; + // calculate the top rows in each column + for (i = 0, l = items.length; i < l; ++i) { + item = items[i]; + var topRow = topRows[item.col]; + if (typeof topRow === 'undefined' || item.row < topRow) { + topRows[item.col] = item.row; + } + } + // move each item down from the top row in its column to the row + for (i = 0, l = items.length; i < l; ++i) { + item = items[i]; + var rowsToMove = newRow - topRows[item.col]; + this.moveItemDown(item, item.row + rowsToMove, ignoreItems); + ignoreItems.push(item); + } + }; + + this.moveItemDown = function(item, newRow, ignoreItems) { + if (item.row >= newRow) { + return; + } + while (item.row < newRow) { + ++item.row; + this.moveOverlappingItems(item, ignoreItems); + } + this.putItem(item, item.row, item.col, ignoreItems); + }; + + /** + * Moves all items up as much as possible + */ + this.floatItemsUp = function() { + if (this.floating === false) { + return; + } + for (var rowIndex = 0, l = this.grid.length; rowIndex < l; ++rowIndex) { + var columns = this.grid[rowIndex]; + if (!columns) { + continue; + } + for (var colIndex = 0, len = columns.length; colIndex < len; ++colIndex) { + var item = columns[colIndex]; + if (item) { + this.floatItemUp(item); + } + } + } + }; + + /** + * Float an item up to the most suitable row + * + * @param {object} item The item to move + */ + this.floatItemUp = function(item) { + if (this.floating === false) { + return; + } + var colIndex = item.col, + sizeY = item.sizeY, + sizeX = item.sizeX, + bestRow = null, + bestColumn = null, + rowIndex = item.row - 1; + + while (rowIndex > -1) { + var items = this.getItems(rowIndex, colIndex, sizeX, sizeY, item); + if (items.length !== 0) { + break; + } + bestRow = rowIndex; + bestColumn = colIndex; + --rowIndex; + } + if (bestRow !== null) { + this.putItem(item, bestRow, bestColumn); + } + }; + + /** + * Update gridsters height + * + * @param {number} plus (Optional) Additional height to add + */ + this.updateHeight = function(plus) { + var maxHeight = this.minRows; + plus = plus || 0; + for (var rowIndex = this.grid.length; rowIndex >= 0; --rowIndex) { + var columns = this.grid[rowIndex]; + if (!columns) { + continue; + } + for (var colIndex = 0, len = columns.length; colIndex < len; ++colIndex) { + if (columns[colIndex]) { + maxHeight = Math.max(maxHeight, rowIndex + plus + columns[colIndex].sizeY); + } + } + } + this.gridHeight = this.maxRows - maxHeight > 0 ? Math.min(this.maxRows, maxHeight) : Math.max(this.maxRows, maxHeight); + }; + + /** + * Returns the number of rows that will fit in given amount of pixels + * + * @param {number} pixels + * @param {boolean} ceilOrFloor (Optional) Determines rounding method + */ + this.pixelsToRows = function(pixels, ceilOrFloor) { + if (ceilOrFloor === true) { + return Math.ceil(pixels / this.curRowHeight); + } else if (ceilOrFloor === false) { + return Math.floor(pixels / this.curRowHeight); + } + + return Math.round(pixels / this.curRowHeight); + }; + + /** + * Returns the number of columns that will fit in a given amount of pixels + * + * @param {number} pixels + * @param {boolean} ceilOrFloor (Optional) Determines rounding method + * @returns {number} The number of columns + */ + this.pixelsToColumns = function(pixels, ceilOrFloor) { + if (ceilOrFloor === true) { + return Math.ceil(pixels / this.curColWidth); + } else if (ceilOrFloor === false) { + return Math.floor(pixels / this.curColWidth); + } + + return Math.round(pixels / this.curColWidth); + }; + + // unified input handling + // adopted from a msdn blogs sample + this.unifiedInput = function(target, startEvent, moveEvent, endEvent) { + var lastXYById = {}; + + // Opera doesn't have Object.keys so we use this wrapper + var numberOfKeys = function(theObject) { + if (Object.keys) { + return Object.keys(theObject).length; + } + + var n = 0, + key; + for (key in theObject) { + ++n; + } + + return n; + }; + + // this calculates the delta needed to convert pageX/Y to offsetX/Y because offsetX/Y don't exist in the TouchEvent object or in Firefox's MouseEvent object + var computeDocumentToElementDelta = function(theElement) { + var elementLeft = 0; + var elementTop = 0; + var oldIEUserAgent = navigator.userAgent.match(/\bMSIE\b/); + + for (var offsetElement = theElement; offsetElement != null; offsetElement = offsetElement.offsetParent) { + // the following is a major hack for versions of IE less than 8 to avoid an apparent problem on the IEBlog with double-counting the offsets + // this may not be a general solution to IE7's problem with offsetLeft/offsetParent + if (oldIEUserAgent && + (!document.documentMode || document.documentMode < 8) && + offsetElement.currentStyle.position === 'relative' && offsetElement.offsetParent && offsetElement.offsetParent.currentStyle.position === 'relative' && offsetElement.offsetLeft === offsetElement.offsetParent.offsetLeft) { + // add only the top + elementTop += offsetElement.offsetTop; + } else { + elementLeft += offsetElement.offsetLeft; + elementTop += offsetElement.offsetTop; + } + } + + return { + x: elementLeft, + y: elementTop + }; + }; + + // cache the delta from the document to our event target (reinitialized each mousedown/MSPointerDown/touchstart) + var documentToTargetDelta = computeDocumentToElementDelta(target); + + // common event handler for the mouse/pointer/touch models and their down/start, move, up/end, and cancel events + var doEvent = function(theEvtObj) { + + if (theEvtObj.type === 'mousemove' && numberOfKeys(lastXYById) === 0) { + return; + } + + var prevent = true; + + var pointerList = theEvtObj.changedTouches ? theEvtObj.changedTouches : [theEvtObj]; + for (var i = 0; i < pointerList.length; ++i) { + var pointerObj = pointerList[i]; + var pointerId = (typeof pointerObj.identifier !== 'undefined') ? pointerObj.identifier : (typeof pointerObj.pointerId !== 'undefined') ? pointerObj.pointerId : 1; + + // use the pageX/Y coordinates to compute target-relative coordinates when we have them (in ie < 9, we need to do a little work to put them there) + if (typeof pointerObj.pageX === 'undefined') { + // initialize assuming our source element is our target + pointerObj.pageX = pointerObj.offsetX + documentToTargetDelta.x; + pointerObj.pageY = pointerObj.offsetY + documentToTargetDelta.y; + + if (pointerObj.srcElement.offsetParent === target && document.documentMode && document.documentMode === 8 && pointerObj.type === 'mousedown') { + // source element is a child piece of VML, we're in IE8, and we've not called setCapture yet - add the origin of the source element + pointerObj.pageX += pointerObj.srcElement.offsetLeft; + pointerObj.pageY += pointerObj.srcElement.offsetTop; + } else if (pointerObj.srcElement !== target && !document.documentMode || document.documentMode < 8) { + // source element isn't the target (most likely it's a child piece of VML) and we're in a version of IE before IE8 - + // the offsetX/Y values are unpredictable so use the clientX/Y values and adjust by the scroll offsets of its parents + // to get the document-relative coordinates (the same as pageX/Y) + var sx = -2, + sy = -2; // adjust for old IE's 2-pixel border + for (var scrollElement = pointerObj.srcElement; scrollElement !== null; scrollElement = scrollElement.parentNode) { + sx += scrollElement.scrollLeft ? scrollElement.scrollLeft : 0; + sy += scrollElement.scrollTop ? scrollElement.scrollTop : 0; + } + + pointerObj.pageX = pointerObj.clientX + sx; + pointerObj.pageY = pointerObj.clientY + sy; + } + } + + + var pageX = pointerObj.pageX; + var pageY = pointerObj.pageY; + + if (theEvtObj.type.match(/(start|down)$/i)) { + // clause for processing MSPointerDown, touchstart, and mousedown + + // refresh the document-to-target delta on start in case the target has moved relative to document + documentToTargetDelta = computeDocumentToElementDelta(target); + + // protect against failing to get an up or end on this pointerId + if (lastXYById[pointerId]) { + if (endEvent) { + endEvent({ + target: theEvtObj.target, + which: theEvtObj.which, + pointerId: pointerId, + pageX: pageX, + pageY: pageY + }); + } + + delete lastXYById[pointerId]; + } + + if (startEvent) { + if (prevent) { + prevent = startEvent({ + target: theEvtObj.target, + which: theEvtObj.which, + pointerId: pointerId, + pageX: pageX, + pageY: pageY + }); + } + } + + // init last page positions for this pointer + lastXYById[pointerId] = { + x: pageX, + y: pageY + }; + + // IE pointer model + if (target.msSetPointerCapture) { + target.msSetPointerCapture(pointerId); + } else if (theEvtObj.type === 'mousedown' && numberOfKeys(lastXYById) === 1) { + if (useSetReleaseCapture) { + target.setCapture(true); + } else { + document.addEventListener('mousemove', doEvent, false); + document.addEventListener('mouseup', doEvent, false); + } + } + } else if (theEvtObj.type.match(/move$/i)) { + // clause handles mousemove, MSPointerMove, and touchmove + + if (lastXYById[pointerId] && !(lastXYById[pointerId].x === pageX && lastXYById[pointerId].y === pageY)) { + // only extend if the pointer is down and it's not the same as the last point + + if (moveEvent && prevent) { + prevent = moveEvent({ + target: theEvtObj.target, + which: theEvtObj.which, + pointerId: pointerId, + pageX: pageX, + pageY: pageY + }); + } + + // update last page positions for this pointer + lastXYById[pointerId].x = pageX; + lastXYById[pointerId].y = pageY; + } + } else if (lastXYById[pointerId] && theEvtObj.type.match(/(up|end|cancel)$/i)) { + // clause handles up/end/cancel + + if (endEvent && prevent) { + prevent = endEvent({ + target: theEvtObj.target, + which: theEvtObj.which, + pointerId: pointerId, + pageX: pageX, + pageY: pageY + }); + } + + // delete last page positions for this pointer + delete lastXYById[pointerId]; + + // in the Microsoft pointer model, release the capture for this pointer + // in the mouse model, release the capture or remove document-level event handlers if there are no down points + // nothing is required for the iOS touch model because capture is implied on touchstart + if (target.msReleasePointerCapture) { + target.msReleasePointerCapture(pointerId); + } else if (theEvtObj.type === 'mouseup' && numberOfKeys(lastXYById) === 0) { + if (useSetReleaseCapture) { + target.releaseCapture(); + } else { + document.removeEventListener('mousemove', doEvent, false); + document.removeEventListener('mouseup', doEvent, false); + } + } + } + } + + if (prevent) { + if (theEvtObj.preventDefault) { + theEvtObj.preventDefault(); + } + + if (theEvtObj.preventManipulation) { + theEvtObj.preventManipulation(); + } + + if (theEvtObj.preventMouseEvent) { + theEvtObj.preventMouseEvent(); + } + } + }; + + var useSetReleaseCapture = false; + // saving the settings for contentZooming and touchaction before activation + var contentZooming, msTouchAction; + + this.enable = function() { + + if (window.navigator.msPointerEnabled) { + // Microsoft pointer model + target.addEventListener('MSPointerDown', doEvent, false); + target.addEventListener('MSPointerMove', doEvent, false); + target.addEventListener('MSPointerUp', doEvent, false); + target.addEventListener('MSPointerCancel', doEvent, false); + + // css way to prevent panning in our target area + if (typeof target.style.msContentZooming !== 'undefined') { + contentZooming = target.style.msContentZooming; + target.style.msContentZooming = 'none'; + } + + // new in Windows Consumer Preview: css way to prevent all built-in touch actions on our target + // without this, you cannot touch draw on the element because IE will intercept the touch events + if (typeof target.style.msTouchAction !== 'undefined') { + msTouchAction = target.style.msTouchAction; + target.style.msTouchAction = 'none'; + } + } else if (target.addEventListener) { + // iOS touch model + target.addEventListener('touchstart', doEvent, false); + target.addEventListener('touchmove', doEvent, false); + target.addEventListener('touchend', doEvent, false); + target.addEventListener('touchcancel', doEvent, false); + + // mouse model + target.addEventListener('mousedown', doEvent, false); + + // mouse model with capture + // rejecting gecko because, unlike ie, firefox does not send events to target when the mouse is outside target + if (target.setCapture && !window.navigator.userAgent.match(/\bGecko\b/)) { + useSetReleaseCapture = true; + + target.addEventListener('mousemove', doEvent, false); + target.addEventListener('mouseup', doEvent, false); + } + } else if (target.attachEvent && target.setCapture) { + // legacy IE mode - mouse with capture + useSetReleaseCapture = true; + target.attachEvent('onmousedown', function() { + doEvent(window.event); + window.event.returnValue = false; + return false; + }); + target.attachEvent('onmousemove', function() { + doEvent(window.event); + window.event.returnValue = false; + return false; + }); + target.attachEvent('onmouseup', function() { + doEvent(window.event); + window.event.returnValue = false; + return false; + }); + } + }; + + this.disable = function() { + if (window.navigator.msPointerEnabled) { + // Microsoft pointer model + target.removeEventListener('MSPointerDown', doEvent, false); + target.removeEventListener('MSPointerMove', doEvent, false); + target.removeEventListener('MSPointerUp', doEvent, false); + target.removeEventListener('MSPointerCancel', doEvent, false); + + // reset zooming to saved value + if (contentZooming) { + target.style.msContentZooming = contentZooming; + } + + // reset touch action setting + if (msTouchAction) { + target.style.msTouchAction = msTouchAction; + } + } else if (target.removeEventListener) { + // iOS touch model + target.removeEventListener('touchstart', doEvent, false); + target.removeEventListener('touchmove', doEvent, false); + target.removeEventListener('touchend', doEvent, false); + target.removeEventListener('touchcancel', doEvent, false); + + // mouse model + target.removeEventListener('mousedown', doEvent, false); + + // mouse model with capture + // rejecting gecko because, unlike ie, firefox does not send events to target when the mouse is outside target + if (target.setCapture && !window.navigator.userAgent.match(/\bGecko\b/)) { + useSetReleaseCapture = true; + + target.removeEventListener('mousemove', doEvent, false); + target.removeEventListener('mouseup', doEvent, false); + } + } else if (target.detachEvent && target.setCapture) { + // legacy IE mode - mouse with capture + useSetReleaseCapture = true; + target.detachEvent('onmousedown'); + target.detachEvent('onmousemove'); + target.detachEvent('onmouseup'); + } + }; + + return this; + }; + + } + ]) + + /** + * The gridster directive + * + * @param {object} $parse + * @param {object} $timeout + */ + .directive('gridster', ['$timeout', '$rootScope', '$window', + function($timeout, $rootScope, $window) { + return { + restrict: 'EAC', + // without transclude, some child items may lose their parent scope + transclude: true, + replace: true, + template: '
    ', + controller: 'GridsterCtrl', + controllerAs: 'gridster', + scope: { + config: '=?gridster' + }, + compile: function() { + + return function(scope, $elem, attrs, gridster) { + gridster.loaded = false; + + scope.gridsterClass = function() { + return { + gridster: true, + 'gridster-desktop': !gridster.isMobile, + 'gridster-mobile': gridster.isMobile, + 'gridster-loaded': gridster.loaded + }; + }; + + /** + * @returns {Object} style object for preview element + */ + scope.previewStyle = function() { + if (!gridster.movingItem) { + return { + display: 'none' + }; + } + + return { + display: 'block', + height: (gridster.movingItem.sizeY * gridster.curRowHeight - gridster.margins[0]) + 'px', + width: (gridster.movingItem.sizeX * gridster.curColWidth - gridster.margins[1]) + 'px', + top: (gridster.movingItem.row * gridster.curRowHeight + (gridster.outerMargin ? gridster.margins[0] : 0)) + 'px', + left: (gridster.movingItem.col * gridster.curColWidth + (gridster.outerMargin ? gridster.margins[1] : 0)) + 'px' + }; + }; + + var refresh = function() { + gridster.setOptions(scope.config); + + // resolve "auto" & "match" values + if (gridster.width === 'auto') { + gridster.curWidth = $elem[0].offsetWidth || parseInt($elem.css('width'), 10); + } else { + gridster.curWidth = gridster.width; + } + + if (gridster.colWidth === 'auto') { + gridster.curColWidth = (gridster.curWidth + (gridster.outerMargin ? -gridster.margins[1] : gridster.margins[1])) / gridster.columns; + } else { + gridster.curColWidth = gridster.colWidth; + } + + gridster.curRowHeight = gridster.rowHeight; + if (typeof gridster.rowHeight === 'string') { + if (gridster.rowHeight === 'match') { + gridster.curRowHeight = Math.round(gridster.curColWidth); + } else if (gridster.rowHeight.indexOf('*') !== -1) { + gridster.curRowHeight = Math.round(gridster.curColWidth * gridster.rowHeight.replace('*', '').replace(' ', '')); + } else if (gridster.rowHeight.indexOf('/') !== -1) { + gridster.curRowHeight = Math.round(gridster.curColWidth / gridster.rowHeight.replace('/', '').replace(' ', '')); + } + } + + gridster.isMobile = gridster.mobileModeEnabled && gridster.curWidth <= gridster.mobileBreakPoint; + + // loop through all items and reset their CSS + for (var rowIndex = 0, l = gridster.grid.length; rowIndex < l; ++rowIndex) { + var columns = gridster.grid[rowIndex]; + if (!columns) { + continue; + } + + for (var colIndex = 0, len = columns.length; colIndex < len; ++colIndex) { + if (columns[colIndex]) { + var item = columns[colIndex]; + item.setElementPosition(); + item.setElementSizeY(); + item.setElementSizeX(); + } + } + } + + updateHeight(); + }; + + // update grid items on config changes + scope.$watch('config', refresh, true); + + scope.$watch('config.draggable', function() { + $rootScope.$broadcast('gridster-draggable-changed'); + }, true); + + scope.$watch('config.resizable', function() { + $rootScope.$broadcast('gridster-resizable-changed'); + }, true); + + var updateHeight = function() { + $elem.css('height', (gridster.gridHeight * gridster.curRowHeight) + (gridster.outerMargin ? gridster.margins[0] : -gridster.margins[0]) + 'px'); + }; + + scope.$watch('gridster.gridHeight', updateHeight); + + scope.$watch('gridster.movingItem', function() { + gridster.updateHeight(gridster.movingItem ? gridster.movingItem.sizeY : 0); + }); + + var prevWidth = $elem[0].offsetWidth || parseInt($elem.css('width'), 10); + + function resize() { + var width = $elem[0].offsetWidth || parseInt($elem.css('width'), 10); + + if (!width || width === prevWidth || gridster.movingItem) { + return; + } + prevWidth = width; + + if (gridster.loaded) { + $elem.removeClass('gridster-loaded'); + } + + refresh(); + + if (gridster.loaded) { + $elem.addClass('gridster-loaded'); + } + + scope.$parent.$broadcast('gridster-resized', [width, $elem.offsetHeight]); + } + + // track element width changes any way we can + function onResize() { + resize(); + $timeout(function() { + scope.$apply(); + }); + } + if (typeof $elem.resize === 'function') { + $elem.resize(onResize); + } + var $win = angular.element($window); + $win.on('resize', onResize); + + scope.$watch(function() { + return $elem[0].offsetWidth || parseInt($elem.css('width'), 10); + }, resize); + + // be sure to cleanup + scope.$on('$destroy', function() { + gridster.destroy(); + $win.off('resize', onResize); + }); + + // allow a little time to place items before floating up + $timeout(function() { + scope.$watch('gridster.floating', function() { + gridster.floatItemsUp(); + }); + gridster.loaded = true; + }, 100); + + + + // Custom code + + /** + * Callback called when starting to drag from palette to canvas. + */ + $rootScope.startDragCallback = function (event, ui) { + $timeout(function () { + var fieldId = event.target.id; + var fieldType; + + var colspan = 1; + if (fieldId === 'group' || fieldId === 'dynamic-table') { + colspan = 2; + } + + var numberOfRows = 1; + if (fieldId === 'multi-line-text') { + numberOfRows = 2; + } else if (fieldId === 'dynamic-table') { + numberOfRows = 2; + } + + scope.startDragItem = { + type: fieldId, + fieldType: fieldType, + name: 'Label', + required: false, + readOnly: false, + sizeX: colspan, + sizeY: numberOfRows, + row: -1, + col: -1 + }; + + if (fieldId === 'radio-buttons' || fieldId === 'dropdown') { + scope.startDragItem.options = [ + {name: 'Option 1'} + ]; + } + + }, 0); + }; + + /** + * Callback called when stopping to drag from palette to canvas. + */ + $rootScope.dropCallback = function (event, ui) { + $timeout(function () { + gridster.movingItem = null; + var offset = jQuery($elem[0]).offset(); + var row = gridster.pixelsToRows(event.clientY - offset.top, true) - 1; + var column = gridster.pixelsToColumns(event.clientX - offset.left, true) - 1; + if (row >= 0 && column >= 0) { + + scope.startDragItem.row = row; + scope.startDragItem.col = column; + } + }, 0); + }; + + /** + * Callback called during dragging from palette to canvas. + */ + $rootScope.dragCallback = function (event, ui) { + + var offset = jQuery($elem[0]).offset(); + var row = gridster.pixelsToRows(event.clientY - offset.top, true) - 1; + var column = gridster.pixelsToColumns(event.clientX - offset.left, true) - 1; + + if (!scope.startDragItem) { + return; + } + + if (scope.startDragItem.row === row && scope.startDragItem.col === column) { + return; + } + + if ( ((scope.startDragItem.row === -1 || scope.startDragItem.col === -1) && row >= 0 && column >= 0) + || (scope.startDragItem.row >= 0 && scope.startDragItem.col >= 0 && (row < 0 || column < 0)) ) { + $timeout(function () { + if ((scope.startDragItem.row === -1 || scope.startDragItem.col === -1) && row >= 0 && column >= 0) { + scope.$parent.formItems.push(scope.startDragItem); + + gridster.movingItem = scope.startDragItem; + gridster.updateHeight(1); + } + + if (scope.startDragItem.row >= 0 && scope.startDragItem.col >= 0 && (row < 0 || column < 0)) { + scope.$parent.formItems.pop(); + gridster.movingItem = null; + } + + + }, 0); + } + + $timeout(function () { + scope.startDragItem.row = row; + scope.startDragItem.col = column; + }, 0); + + }; + + // END custom code + + + }; + } + }; + } + ]) + + .controller('GridsterItemCtrl', function() { + this.$element = null; + this.gridster = null; + this.row = null; + this.col = null; + this.sizeX = null; + this.sizeY = null; + this.minSizeX = 0; + this.minSizeY = 0; + this.maxSizeX = null; + this.maxSizeY = null; + + this.init = function($element, gridster) { + this.$element = $element; + this.gridster = gridster; + this.sizeX = gridster.defaultSizeX; + this.sizeY = gridster.defaultSizeY; + }; + + this.destroy = function() { + this.gridster = null; + this.$element = null; + }; + + /** + * Returns the items most important attributes + */ + this.toJSON = function() { + return { + row: this.row, + col: this.col, + sizeY: this.sizeY, + sizeX: this.sizeX + }; + }; + + this.isMoving = function() { + return this.gridster.movingItem === this; + }; + + /** + * Set the items position + * + * @param {number} row + * @param {number} column + */ + this.setPosition = function(row, column) { + this.gridster.putItem(this, row, column); + + if (!this.isMoving()) { + this.setElementPosition(); + } + }; + + /** + * Sets a specified size property + * + * @param {string} key Can be either "x" or "y" + * @param {number} value The size amount + */ + this.setSize = function(key, value, preventMove) { + key = key.toUpperCase(); + var camelCase = 'size' + key, + titleCase = 'Size' + key; + if (value === '') { + return; + } + value = parseInt(value, 10); + if (isNaN(value) || value === 0) { + value = this.gridster['default' + titleCase]; + } + var max = key === 'X' ? this.gridster.columns : this.gridster.maxRows; + if (this['max' + titleCase]) { + max = Math.min(this['max' + titleCase], max); + } + if (this.gridster['max' + titleCase]) { + max = Math.min(this.gridster['max' + titleCase], max); + } + if (key === 'X' && this.cols) { + max -= this.cols; + } else if (key === 'Y' && this.rows) { + max -= this.rows; + } + + var min = 0; + if (this['min' + titleCase]) { + min = Math.max(this['min' + titleCase], min); + } + if (this.gridster['min' + titleCase]) { + min = Math.max(this.gridster['min' + titleCase], min); + } + + value = Math.max(Math.min(value, max), min); + + var changed = (this[camelCase] !== value || (this['old' + titleCase] && this['old' + titleCase] !== value)); + this['old' + titleCase] = this[camelCase] = value; + + if (!this.isMoving()) { + this['setElement' + titleCase](); + } + if (!preventMove && changed) { + this.gridster.moveOverlappingItems(this); + this.gridster.layoutChanged(); + } + + return changed; + }; + + /** + * Sets the items sizeY property + * + * @param {number} rows + */ + this.setSizeY = function(rows, preventMove) { + return this.setSize('Y', rows, preventMove); + }; + + /** + * Sets the items sizeX property + * + * @param {number} rows + */ + this.setSizeX = function(columns, preventMove) { + return this.setSize('X', columns, preventMove); + }; + + /** + * Sets an elements position on the page + * + * @param {number} row + * @param {number} column + */ + this.setElementPosition = function() { + if (this.gridster.isMobile) { + this.$element.css({ + marginLeft: this.gridster.margins[0] + 'px', + marginRight: this.gridster.margins[0] + 'px', + marginTop: this.gridster.margins[1] + 'px', + marginBottom: this.gridster.margins[1] + 'px', + top: '', + left: '' + }); + } else { + this.$element.css({ + margin: 0, + top: (this.row * this.gridster.curRowHeight + (this.gridster.outerMargin ? this.gridster.margins[0] : 0)) + 'px', + left: (this.col * this.gridster.curColWidth + (this.gridster.outerMargin ? this.gridster.margins[1] : 0)) + 'px' + }); + } + }; + + /** + * Sets an elements height + */ + this.setElementSizeY = function() { + if (this.gridster.isMobile && !this.gridster.saveGridItemCalculatedHeightInMobile) { + this.$element.css('height', ''); + } else { + this.$element.css('height', (this.sizeY * this.gridster.curRowHeight - this.gridster.margins[0]) + 'px'); + } + }; + + /** + * Sets an elements width + */ + this.setElementSizeX = function() { + if (this.gridster.isMobile) { + this.$element.css('width', ''); + } else { + this.$element.css('width', (this.sizeX * this.gridster.curColWidth - this.gridster.margins[1]) + 'px'); + } + }; + + /** + * Gets an element's width + */ + this.getElementSizeX = function() { + return (this.sizeX * this.gridster.curColWidth - this.gridster.margins[1]); + }; + + /** + * Gets an element's height + */ + this.getElementSizeY = function() { + return (this.sizeY * this.gridster.curRowHeight - this.gridster.margins[0]); + }; + + }) + + .factory('GridsterDraggable', ['$document', '$timeout', '$window', + function($document, $timeout, $window) { + function GridsterDraggable($el, scope, gridster, item, itemOptions) { + + var elmX, elmY, elmW, elmH, + + mouseX = 0, + mouseY = 0, + lastMouseX = 0, + lastMouseY = 0, + mOffX = 0, + mOffY = 0, + + minTop = 0, + maxTop = 9999, + minLeft = 0, + realdocument = $document[0]; + + var originalCol, originalRow; + var inputTags = ['select', 'input', 'textarea', 'button']; + + function mouseDown(e) { + if (inputTags.indexOf(e.target.nodeName.toLowerCase()) !== -1) { + return false; + } + + // exit, if a resize handle was hit + if (angular.element(e.target).hasClass('gridster-item-resizable-handler')) { + return false; + } + + // exit, if the target has it's own click event + if (angular.element(e.target).attr('onclick') || angular.element(e.target).attr('ng-click')) { + return false; + } + + switch (e.which) { + case 1: + // left mouse button + break; + case 2: + case 3: + // right or middle mouse button + return; + } + + lastMouseX = e.pageX; + lastMouseY = e.pageY; + + elmX = parseInt($el.css('left'), 10); + elmY = parseInt($el.css('top'), 10); + elmW = $el[0].offsetWidth; + elmH = $el[0].offsetHeight; + + originalCol = item.col; + originalRow = item.row; + + dragStart(e); + + return true; + } + + function mouseMove(e) { + if (!$el.hasClass('gridster-item-moving') || $el.hasClass('gridster-item-resizing')) { + return false; + } + + var maxLeft = gridster.curWidth - 1; + + // Get the current mouse position. + mouseX = e.pageX; + mouseY = e.pageY; + + // Get the deltas + var diffX = mouseX - lastMouseX + mOffX; + var diffY = mouseY - lastMouseY + mOffY; + mOffX = mOffY = 0; + + // Update last processed mouse positions. + lastMouseX = mouseX; + lastMouseY = mouseY; + + var dX = diffX, + dY = diffY; + if (elmX + dX < minLeft) { + diffX = minLeft - elmX; + mOffX = dX - diffX; + } else if (elmX + elmW + dX > maxLeft) { + diffX = maxLeft - elmX - elmW; + mOffX = dX - diffX; + } + + if (elmY + dY < minTop) { + diffY = minTop - elmY; + mOffY = dY - diffY; + } else if (elmY + elmH + dY > maxTop) { + diffY = maxTop - elmY - elmH; + mOffY = dY - diffY; + } + elmX += diffX; + elmY += diffY; + + // set new position + $el.css({ + 'top': elmY + 'px', + 'left': elmX + 'px' + }); + + drag(e); + + return true; + } + + function mouseUp(e) { + if (!$el.hasClass('gridster-item-moving') || $el.hasClass('gridster-item-resizing')) { + return false; + } + + mOffX = mOffY = 0; + + dragStop(e); + + return true; + } + + function dragStart(event) { + $el.addClass('gridster-item-moving'); + gridster.movingItem = item; + + gridster.updateHeight(item.sizeY); + scope.$apply(function() { + if (gridster.draggable && gridster.draggable.start) { + gridster.draggable.start(event, $el, itemOptions); + } + }); + } + + function drag(event) { + var oldRow = item.row, + oldCol = item.col, + hasCallback = gridster.draggable && gridster.draggable.drag, + scrollSensitivity = gridster.draggable.scrollSensitivity, + scrollSpeed = gridster.draggable.scrollSpeed; + + var row = gridster.pixelsToRows(elmY); + var col = gridster.pixelsToColumns(elmX); + + var itemsInTheWay = gridster.getItems(row, col, item.sizeX, item.sizeY, item); + var hasItemsInTheWay = itemsInTheWay.length !== 0; + + if (gridster.swapping === true && hasItemsInTheWay) { + var boundingBoxItem = gridster.getBoundingBox(itemsInTheWay); + var sameSize = boundingBoxItem.sizeX === item.sizeX && boundingBoxItem.sizeY === item.sizeY; + var sameRow = boundingBoxItem.row === row; + var sameCol = boundingBoxItem.col === col; + var samePosition = sameRow && sameCol; + var inline = sameRow || sameCol; + + if (sameSize && itemsInTheWay.length === 1) { + if (samePosition) { + gridster.swapItems(item, itemsInTheWay[0]); + } else if (inline) { + return; + } + } else if (boundingBoxItem.sizeX <= item.sizeX && boundingBoxItem.sizeY <= item.sizeY && inline) { + var emptyRow = item.row <= row ? item.row : row + item.sizeY; + var emptyCol = item.col <= col ? item.col : col + item.sizeX; + var rowOffset = emptyRow - boundingBoxItem.row; + var colOffset = emptyCol - boundingBoxItem.col; + + for (var i = 0, l = itemsInTheWay.length; i < l; ++i) { + var itemInTheWay = itemsInTheWay[i]; + + var itemsInFreeSpace = gridster.getItems( + itemInTheWay.row + rowOffset, + itemInTheWay.col + colOffset, + itemInTheWay.sizeX, + itemInTheWay.sizeY, + item + ); + + if (itemsInFreeSpace.length === 0) { + gridster.putItem(itemInTheWay, itemInTheWay.row + rowOffset, itemInTheWay.col + colOffset); + } + } + } + } + + if (gridster.pushing !== false || !hasItemsInTheWay) { + item.row = row; + item.col = col; + } + + if (event.pageY - realdocument.body.scrollTop < scrollSensitivity) { + realdocument.body.scrollTop = realdocument.body.scrollTop - scrollSpeed; + } else if ($window.innerHeight - (event.pageY - realdocument.body.scrollTop) < scrollSensitivity) { + realdocument.body.scrollTop = realdocument.body.scrollTop + scrollSpeed; + } + + if (event.pageX - realdocument.body.scrollLeft < scrollSensitivity) { + realdocument.body.scrollLeft = realdocument.body.scrollLeft - scrollSpeed; + } else if ($window.innerWidth - (event.pageX - realdocument.body.scrollLeft) < scrollSensitivity) { + realdocument.body.scrollLeft = realdocument.body.scrollLeft + scrollSpeed; + } + + if (hasCallback || oldRow !== item.row || oldCol !== item.col) { + scope.$apply(function() { + if (hasCallback) { + gridster.draggable.drag(event, $el, itemOptions); + } + }); + } + } + + function dragStop(event) { + $el.removeClass('gridster-item-moving'); + var row = gridster.pixelsToRows(elmY); + var col = gridster.pixelsToColumns(elmX); + if (gridster.pushing !== false || gridster.getItems(row, col, item.sizeX, item.sizeY, item).length === 0) { + item.row = row; + item.col = col; + } + gridster.movingItem = null; + item.setPosition(item.row, item.col); + + scope.$apply(function() { + if (gridster.draggable && gridster.draggable.stop) { + gridster.draggable.stop(event, $el, itemOptions); + } + }); + } + + var enabled = false; + var $dragHandle = null; + var unifiedInput; + + this.enable = function() { + var self = this; + // disable and timeout required for some template rendering + $timeout(function() { + self.disable(); + + if (gridster.draggable && gridster.draggable.handle) { + $dragHandle = angular.element($el[0].querySelector(gridster.draggable.handle)); + if ($dragHandle.length === 0) { + // fall back to element if handle not found... + $dragHandle = $el; + } + } else { + $dragHandle = $el; + } + + unifiedInput = new gridster.unifiedInput($dragHandle[0], mouseDown, mouseMove, mouseUp); + unifiedInput.enable(); + + enabled = true; + }); + }; + + this.disable = function() { + if (!enabled) { + return; + } + + unifiedInput.disable(); + unifiedInput = undefined; + enabled = false; + }; + + this.toggle = function(enabled) { + if (enabled) { + this.enable(); + } else { + this.disable(); + } + }; + + this.destroy = function() { + this.disable(); + }; + } + + return GridsterDraggable; + } + ]) + + .factory('GridsterResizable', [ + function() { + function GridsterResizable($el, scope, gridster, item, itemOptions) { + + function ResizeHandle(handleClass) { + + var hClass = handleClass; + + var elmX, elmY, elmW, elmH, + + mouseX = 0, + mouseY = 0, + lastMouseX = 0, + lastMouseY = 0, + mOffX = 0, + mOffY = 0, + + minTop = 0, + maxTop = 9999, + minLeft = 0; + + var getMinHeight = function() { + return gridster.curRowHeight - gridster.margins[0]; + }; + var getMinWidth = function() { + return gridster.curColWidth - gridster.margins[1]; + }; + + var originalWidth, originalHeight; + var savedDraggable; + + function mouseDown(e) { + switch (e.which) { + case 1: + // left mouse button + break; + case 2: + case 3: + // right or middle mouse button + return; + } + + // save the draggable setting to restore after resize + savedDraggable = gridster.draggable.enabled; + if (savedDraggable) { + gridster.draggable.enabled = false; + scope.$broadcast('gridster-draggable-changed'); + } + + // Get the current mouse position. + lastMouseX = e.pageX; + lastMouseY = e.pageY; + + // Record current widget dimensions + elmX = parseInt($el.css('left'), 10); + elmY = parseInt($el.css('top'), 10); + elmW = $el[0].offsetWidth; + elmH = $el[0].offsetHeight; + + originalWidth = item.sizeX; + originalHeight = item.sizeY; + + resizeStart(e); + + return true; + } + + function resizeStart(e) { + $el.addClass('gridster-item-moving'); + $el.addClass('gridster-item-resizing'); + + gridster.movingItem = item; + + item.setElementSizeX(); + item.setElementSizeY(); + item.setElementPosition(); + gridster.updateHeight(1); + + scope.$apply(function() { + // callback + if (gridster.resizable && gridster.resizable.start) { + gridster.resizable.start(e, $el, itemOptions); // options is the item model + } + }); + } + + function mouseMove(e) { + var maxLeft = gridster.curWidth - 1; + + // Get the current mouse position. + mouseX = e.pageX; + mouseY = e.pageY; + + // Get the deltas + var diffX = mouseX - lastMouseX + mOffX; + var diffY = mouseY - lastMouseY + mOffY; + mOffX = mOffY = 0; + + // Update last processed mouse positions. + lastMouseX = mouseX; + lastMouseY = mouseY; + + var dY = diffY, + dX = diffX; + + if (hClass.indexOf('n') >= 0) { + if (elmH - dY < getMinHeight()) { + diffY = elmH - getMinHeight(); + mOffY = dY - diffY; + } else if (elmY + dY < minTop) { + diffY = minTop - elmY; + mOffY = dY - diffY; + } + elmY += diffY; + elmH -= diffY; + } + if (hClass.indexOf('s') >= 0) { + if (elmH + dY < getMinHeight()) { + diffY = getMinHeight() - elmH; + mOffY = dY - diffY; + } else if (elmY + elmH + dY > maxTop) { + diffY = maxTop - elmY - elmH; + mOffY = dY - diffY; + } + elmH += diffY; + } + if (hClass.indexOf('w') >= 0) { + if (elmW - dX < getMinWidth()) { + diffX = elmW - getMinWidth(); + mOffX = dX - diffX; + } else if (elmX + dX < minLeft) { + diffX = minLeft - elmX; + mOffX = dX - diffX; + } + elmX += diffX; + elmW -= diffX; + } + if (hClass.indexOf('e') >= 0) { + if (elmW + dX < getMinWidth()) { + diffX = getMinWidth() - elmW; + mOffX = dX - diffX; + } else if (elmX + elmW + dX > maxLeft) { + diffX = maxLeft - elmX - elmW; + mOffX = dX - diffX; + } + elmW += diffX; + } + + // set new position + $el.css({ + 'top': elmY + 'px', + 'left': elmX + 'px', + 'width': elmW + 'px', + 'height': elmH + 'px' + }); + + resize(e); + + return true; + } + + function mouseUp(e) { + // restore draggable setting to its original state + if (gridster.draggable.enabled !== savedDraggable) { + gridster.draggable.enabled = savedDraggable; + scope.$broadcast('gridster-draggable-changed'); + } + + mOffX = mOffY = 0; + + resizeStop(e); + + return true; + } + + function resize(e) { + var oldRow = item.row, + oldCol = item.col, + oldSizeX = item.sizeX, + oldSizeY = item.sizeY, + hasCallback = gridster.resizable && gridster.resizable.resize; + + var col = item.col; + // only change column if grabbing left edge + if (['w', 'nw', 'sw'].indexOf(handleClass) !== -1) { + col = gridster.pixelsToColumns(elmX, false); + } + + var row = item.row; + // only change row if grabbing top edge + if (['n', 'ne', 'nw'].indexOf(handleClass) !== -1) { + row = gridster.pixelsToRows(elmY, false); + } + + var sizeX = item.sizeX; + // only change row if grabbing left or right edge + if (['n', 's'].indexOf(handleClass) === -1) { + sizeX = gridster.pixelsToColumns(elmW, true); + } + + var sizeY = item.sizeY; + // only change row if grabbing top or bottom edge + if (['e', 'w'].indexOf(handleClass) === -1) { + sizeY = gridster.pixelsToRows(elmH, true); + } + + if (gridster.pushing !== false || gridster.getItems(row, col, sizeX, sizeY, item).length === 0) { + item.row = row; + item.col = col; + item.sizeX = sizeX; + item.sizeY = sizeY; + } + var isChanged = item.row !== oldRow || item.col !== oldCol || item.sizeX !== oldSizeX || item.sizeY !== oldSizeY; + + if (hasCallback || isChanged) { + scope.$apply(function() { + if (hasCallback) { + gridster.resizable.resize(e, $el, itemOptions); // options is the item model + } + }); + } + } + + function resizeStop(e) { + $el.removeClass('gridster-item-moving'); + $el.removeClass('gridster-item-resizing'); + + gridster.movingItem = null; + + item.setPosition(item.row, item.col); + item.setSizeY(item.sizeY); + item.setSizeX(item.sizeX); + + scope.$apply(function() { + if (gridster.resizable && gridster.resizable.stop) { + gridster.resizable.stop(e, $el, itemOptions); // options is the item model + } + }); + } + + var $dragHandle = null; + var unifiedInput; + + this.enable = function() { + if (!$dragHandle) { + $dragHandle = angular.element('
    '); + $el.append($dragHandle); + } + + unifiedInput = new gridster.unifiedInput($dragHandle[0], mouseDown, mouseMove, mouseUp); + unifiedInput.enable(); + }; + + this.disable = function() { + if ($dragHandle) { + $dragHandle.remove(); + $dragHandle = null; + } + + unifiedInput.disable(); + unifiedInput = undefined; + }; + + this.destroy = function() { + this.disable(); + }; + } + + var handles = []; + var handlesOpts = gridster.resizable.handles; + if (typeof handlesOpts === 'string') { + handlesOpts = gridster.resizable.handles.split(','); + } + var enabled = false; + + for (var c = 0, l = handlesOpts.length; c < l; c++) { + handles.push(new ResizeHandle(handlesOpts[c])); + } + + this.enable = function() { + if (enabled) { + return; + } + for (var c = 0, l = handles.length; c < l; c++) { + handles[c].enable(); + } + enabled = true; + }; + + this.disable = function() { + if (!enabled) { + return; + } + for (var c = 0, l = handles.length; c < l; c++) { + handles[c].disable(); + } + enabled = false; + }; + + this.toggle = function(enabled) { + if (enabled) { + this.enable(); + } else { + this.disable(); + } + }; + + this.destroy = function() { + for (var c = 0, l = handles.length; c < l; c++) { + handles[c].destroy(); + } + }; + } + return GridsterResizable; + } + ]) + + /** + * GridsterItem directive + */ + .directive('gridsterItem', ['$parse', 'GridsterDraggable', 'GridsterResizable', + function($parse, GridsterDraggable, GridsterResizable) { + return { + restrict: 'EA', + controller: 'GridsterItemCtrl', + require: ['^gridster', 'gridsterItem'], + link: function(scope, $el, attrs, controllers) { + var optionsKey = attrs.gridsterItem, + options; + + var gridster = controllers[0], + item = controllers[1]; + + // bind the item's position properties + if (optionsKey) { + var $optionsGetter = $parse(optionsKey); + options = $optionsGetter(scope) || {}; + if (!options && $optionsGetter.assign) { + options = { + row: item.row, + col: item.col, + sizeX: item.sizeX, + sizeY: item.sizeY, + minSizeX: 0, + minSizeY: 0, + maxSizeX: null, + maxSizeY: null + }; + $optionsGetter.assign(scope, options); + } + } else { + options = attrs; + } + + item.init($el, gridster); + + $el.addClass('gridster-item'); + + var aspects = ['minSizeX', 'maxSizeX', 'minSizeY', 'maxSizeY', 'sizeX', 'sizeY', 'row', 'col'], + $getters = {}; + + var aspectFn = function(aspect) { + var key; + if (typeof options[aspect] === 'string') { + key = options[aspect]; + } else if (typeof options[aspect.toLowerCase()] === 'string') { + key = options[aspect.toLowerCase()]; + } else if (optionsKey) { + key = $parse(optionsKey + '.' + aspect); + } else { + return; + } + $getters[aspect] = $parse(key); + + // when the value changes externally, update the internal item object + scope.$watch(key, function(newVal) { + newVal = parseInt(newVal, 10); + if (!isNaN(newVal)) { + item[aspect] = newVal; + } + }); + + // initial set + var val = $getters[aspect](scope); + if (typeof val === 'number') { + item[aspect] = val; + } + }; + + for (var i = 0, l = aspects.length; i < l; ++i) { + aspectFn(aspects[i]); + } + + scope.$broadcast('gridster-item-initialized', [item.sizeY, item.sizeX, item.getElementSizeY(), item.getElementSizeX()]); + + function positionChanged() { + // call setPosition so the element and gridster controller are updated + item.setPosition(item.row, item.col); + + // when internal item position changes, update externally bound values + if ($getters.row && $getters.row.assign) { + $getters.row.assign(scope, item.row); + } + if ($getters.col && $getters.col.assign) { + $getters.col.assign(scope, item.col); + } + } + scope.$watch(function() { + return item.row + ',' + item.col; + }, positionChanged); + + function sizeChanged() { + var changedX = item.setSizeX(item.sizeX, true); + if (changedX && $getters.sizeX && $getters.sizeX.assign) { + $getters.sizeX.assign(scope, item.sizeX); + } + var changedY = item.setSizeY(item.sizeY, true); + if (changedY && $getters.sizeY && $getters.sizeY.assign) { + $getters.sizeY.assign(scope, item.sizeY); + } + + if (changedX || changedY) { + item.gridster.moveOverlappingItems(item); + gridster.layoutChanged(); + } + } + scope.$watch(function() { + return item.sizeY + ',' + item.sizeX + '|' + item.minSizeX + ',' + item.maxSizeX + ',' + item.minSizeY + ',' + item.maxSizeY; + }, sizeChanged); + + var draggable = new GridsterDraggable($el, scope, gridster, item, options); + var resizable = new GridsterResizable($el, scope, gridster, item, options); + + scope.$on('gridster-draggable-changed', function() { + draggable.toggle(!gridster.isMobile && gridster.draggable && gridster.draggable.enabled); + }); + scope.$on('gridster-resizable-changed', function() { + resizable.toggle(!gridster.isMobile && gridster.resizable && gridster.resizable.enabled); + }); + scope.$on('gridster-resized', function() { + resizable.toggle(!gridster.isMobile && gridster.resizable && gridster.resizable.enabled); + }); + scope.$watch(function() { + return gridster.isMobile; + }, function() { + resizable.toggle(!gridster.isMobile && gridster.resizable && gridster.resizable.enabled); + draggable.toggle(!gridster.isMobile && gridster.draggable && gridster.draggable.enabled); + }); + + function whichTransitionEvent() { + var el = document.createElement('div'); + var transitions = { + 'transition': 'transitionend', + 'OTransition': 'oTransitionEnd', + 'MozTransition': 'transitionend', + 'WebkitTransition': 'webkitTransitionEnd' + }; + for (var t in transitions) { + if (el.style[t] !== undefined) { + return transitions[t]; + } + } + } + + $el.on(whichTransitionEvent(), function() { + scope.$apply(function() { + scope.$broadcast('gridster-item-transition-end'); + }); + }); + + return scope.$on('$destroy', function() { + try { + resizable.destroy(); + draggable.destroy(); + } catch (e) {} + + try { + gridster.removeItem(item); + } catch (e) {} + + try { + item.destroy(); + } catch (e) {} + }); + } + }; + } + ]) + + ; + +})(angular); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/libs/angular-gridster_0.11.7/angular-gridster.min.css b/snow-flowable/src/main/resources/static/libs/angular-gridster_0.11.7/angular-gridster.min.css new file mode 100644 index 0000000..3976680 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-gridster_0.11.7/angular-gridster.min.css @@ -0,0 +1 @@ +.gridster{position:relative;margin:auto;height:0}.gridster-content>ul{margin:0;list-style:none;padding:0}.gridster-item{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;list-style:none;z-index:2;position:absolute;display:none}.gridster-loaded{-webkit-transition:height .3s;-moz-transition:height .3s;-o-transition:height .3s;transition:height .3s}.gridster-loaded .gridster-item{display:block;position:absolute;-webkit-transition:opacity .3s, left .3s, top .3s, width .3s, height .3s;-moz-transition:opacity .3s, left .3s, top .3s, width .3s, height .3s;-o-transition:opacity .3s, left .3s, top .3s, width .3s, height .3s;transition:opacity .3s, left .3s, top .3s, width .3s, height .3s}.gridster-mobile{height:auto !important}.gridster-mobile .gridster-item{height:auto;position:static;float:none}.gridster-preview-holder{display:none;z-index:1;position:absolute;background-color:#ddd;border-color:#fff;opacity:0.2}.gridster-item.gridster-item-moving,.gridster-item.gridster-preview-holder{-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.gridster-item.ng-leave.ng-leave-active{opacity:0}.gridster-item.ng-enter{opacity:1}.gridster-item-moving{z-index:3}.gridster-item-resizable-handler{position:absolute;font-size:1px;display:block}.handle-se{cursor:se-resize;width:0;height:0;right:1px;bottom:1px;border-style:solid;border-width:0 0 12px 12px;border-color:transparent}.handle-ne{cursor:ne-resize;width:12px;height:12px;right:1px;top:1px}.handle-nw{cursor:nw-resize;width:12px;height:12px;left:1px;top:1px}.handle-sw{cursor:sw-resize;width:12px;height:12px;left:1px;bottom:1px}.handle-e{cursor:e-resize;width:12px;bottom:0;right:1px;top:0}.handle-s{cursor:s-resize;height:12px;right:0;bottom:1px;left:0}.handle-n{cursor:n-resize;height:12px;right:0;top:1px;left:0}.handle-w{cursor:w-resize;width:12px;left:1px;top:0;bottom:0}.gridster .gridster-item:hover .gridster-box{border:1.5px solid #B3B2B3}.gridster .gridster-item:hover .handle-se{border-color:transparent transparent #ccc} \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/libs/angular-gridster_0.11.7/angular-gridster.min.js b/snow-flowable/src/main/resources/static/libs/angular-gridster_0.11.7/angular-gridster.min.js new file mode 100644 index 0000000..79eb6a6 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-gridster_0.11.7/angular-gridster.min.js @@ -0,0 +1,8 @@ +/* + * angular-gridster + * http://manifestwebdesign.github.io/angular-gridster + * + * @version: 0.11.7 + * @license: MIT + */ +!function(a){"use strict";a.module("gridster",[]).constant("gridsterConfig",{columns:6,pushing:!0,floating:!0,swapping:!1,width:"auto",colWidth:"auto",rowHeight:"match",margins:[10,10],outerMargin:!0,isMobile:!1,mobileBreakPoint:600,mobileModeEnabled:!0,minColumns:1,minRows:1,maxRows:100,defaultSizeX:2,defaultSizeY:1,minSizeX:1,maxSizeX:null,minSizeY:1,maxSizeY:null,saveGridItemCalculatedHeightInMobile:!1,resizable:{enabled:!0,handles:["s","e","n","w","se","ne","sw","nw"]},draggable:{enabled:!0,scrollSensitivity:20,scrollSpeed:15}}).controller("GridsterCtrl",["gridsterConfig","$timeout",function(b,c){var d=this;a.extend(this,b),this.resizable=a.extend({},b.resizable||{}),this.draggable=a.extend({},b.draggable||{});var e=!1;this.layoutChanged=function(){e||(e=!0,c(function(){e=!1,d.loaded&&d.floatItemsUp(),d.updateHeight(d.movingItem?d.movingItem.sizeY:0)}))},this.grid=[],this.destroy=function(){this.grid&&(this.grid.length=0,this.grid=null)},this.setOptions=function(b){if(b)if(b=a.extend({},b),b.draggable&&(a.extend(this.draggable,b.draggable),delete b.draggable),b.resizable&&(a.extend(this.resizable,b.resizable),delete b.resizable),a.extend(this,b),this.margins&&2===this.margins.length)for(var c=0,d=this.margins.length;d>c;++c)this.margins[c]=parseInt(this.margins[c],10),isNaN(this.margins[c])&&(this.margins[c]=0);else this.margins=[0,0]},this.canItemOccupy=function(a,b,c){return b>-1&&c>-1&&a.sizeX+c<=this.columns&&a.sizeY+b<=this.maxRows},this.autoSetItemPosition=function(a){for(var b=0;bg;++g)for(var h=0;c>h;++h){var i=this.getItem(a+g,b+h,e);!i||e&&-1!==e.indexOf(i)||-1!==f.indexOf(i)||f.push(i)}return f},this.getBoundingBox=function(a){if(0===a.length)return null;if(1===a.length)return{row:a[0].row,col:a[0].col,sizeY:a[0].sizeY,sizeX:a[0].sizeX};for(var b=0,c=0,d=9999,e=9999,f=0,g=a.length;g>f;++f){var h=a[f];d=Math.min(h.row,d),e=Math.min(h.col,e),b=Math.max(h.row+h.sizeY,b),c=Math.max(h.col+h.sizeX,c)}return{row:d,col:e,sizeY:b-d,sizeX:c-e}},this.removeItem=function(a){for(var b=0,c=this.grid.length;c>b;++b){var d=this.grid[b];if(d){var e=d.indexOf(a);if(-1!==e){d[e]=null;break}}}this.layoutChanged()},this.getItem=function(a,b,c){!c||c instanceof Array||(c=[c]);for(var d=1;a>-1;){for(var e=1,f=b;f>-1;){var g=this.grid[a];if(g){var h=g[f];if(h&&(!c||-1===c.indexOf(h))&&h.sizeX>=e&&h.sizeY>=d)return h}++e,--f}--a,++d}return null},this.putItems=function(a){for(var b=0,c=a.length;c>b;++b)this.putItem(a[b])},this.putItem=function(a,b,c,d){if(("undefined"==typeof b||null===b)&&(b=a.row,c=a.col,"undefined"==typeof b||null===b))return void this.autoSetItemPosition(a);if(this.canItemOccupy(a,b,c)||(c=Math.min(this.columns-a.sizeX,Math.max(0,c)),b=Math.min(this.maxRows-a.sizeY,Math.max(0,b))),null!==a.oldRow&&"undefined"!=typeof a.oldRow){var e=a.oldRow===b&&a.oldColumn===c,f=this.grid[b]&&this.grid[b][c]===a;if(e&&f)return a.row=b,void(a.col=c);var g=this.grid[a.oldRow];g&&g[a.oldColumn]===a&&delete g[a.oldColumn]}a.oldRow=a.row=b,a.oldColumn=a.col=c,this.moveOverlappingItems(a,d),this.grid[b]||(this.grid[b]=[]),this.grid[b][c]=a,this.movingItem===a&&this.floatItemUp(a),this.layoutChanged()},this.swapItems=function(a,b){this.grid[a.row][a.col]=b,this.grid[b.row][b.col]=a;var c=a.row,d=a.col;a.row=b.row,a.col=b.col,b.row=c,b.col=d},this.moveOverlappingItems=function(a,b){b?-1===b.indexOf(a)&&(b=b.slice(0),b.push(a)):b=[a];var c=this.getItems(a.row,a.col,a.sizeX,a.sizeY,b);this.moveItemsDown(c,a.row+a.sizeY,b)},this.moveItemsDown=function(a,b,c){if(a&&0!==a.length){a.sort(function(a,b){return a.row-b.row}),c=c?c.slice(0):[];var d,e,f,g={};for(e=0,f=a.length;f>e;++e){d=a[e];var h=g[d.col];("undefined"==typeof h||d.rowe;++e){d=a[e];var i=b-g[d.col];this.moveItemDown(d,d.row+i,c),c.push(d)}}},this.moveItemDown=function(a,b,c){if(!(a.row>=b)){for(;a.rowa;++a){var c=this.grid[a];if(c)for(var d=0,e=c.length;e>d;++d){var f=c[d];f&&this.floatItemUp(f)}}},this.floatItemUp=function(a){if(this.floating!==!1){for(var b=a.col,c=a.sizeY,d=a.sizeX,e=null,f=null,g=a.row-1;g>-1;){var h=this.getItems(g,b,d,c,a);if(0!==h.length)break;e=g,f=b,--g}null!==e&&this.putItem(a,e,f)}},this.updateHeight=function(a){var b=this.minRows;a=a||0;for(var c=this.grid.length;c>=0;--c){var d=this.grid[c];if(d)for(var e=0,f=d.length;f>e;++e)d[e]&&(b=Math.max(b,c+a+d[e].sizeY))}this.gridHeight=this.maxRows-b>0?Math.min(this.maxRows,b):Math.max(this.maxRows,b)},this.pixelsToRows=function(a,b){return b===!0?Math.ceil(a/this.curRowHeight):b===!1?Math.floor(a/this.curRowHeight):Math.round(a/this.curRowHeight)},this.pixelsToColumns=function(a,b){return b===!0?Math.ceil(a/this.curColWidth):b===!1?Math.floor(a/this.curColWidth):Math.round(a/this.curColWidth)},this.unifiedInput=function(a,b,c,d){var e,f,g={},h=function(a){if(Object.keys)return Object.keys(a).length;var b,c=0;for(b in a)++c;return c},i=function(a){for(var b=0,c=0,d=navigator.userAgent.match(/\bMSIE\b/),e=a;null!=e;e=e.offsetParent)d&&(!document.documentMode||document.documentMode<8)&&"relative"===e.currentStyle.position&&e.offsetParent&&"relative"===e.offsetParent.currentStyle.position&&e.offsetLeft===e.offsetParent.offsetLeft?c+=e.offsetTop:(b+=e.offsetLeft,c+=e.offsetTop);return{x:b,y:c}},j=i(a),k=function(e){if("mousemove"!==e.type||0!==h(g)){for(var f=!0,m=e.changedTouches?e.changedTouches:[e],n=0;n
    ',controller:"GridsterCtrl",controllerAs:"gridster",scope:{config:"=?gridster"},compile:function(){return function(e,f,g,h){function i(){var a=f[0].offsetWidth||parseInt(f.css("width"),10);a&&a!==m&&!h.movingItem&&(m=a,h.loaded&&f.removeClass("gridster-loaded"),k(),h.loaded&&f.addClass("gridster-loaded"),e.$parent.$broadcast("gridster-resized",[a,f.offsetHeight]))}function j(){i(),b(function(){e.$apply()})}h.loaded=!1,e.gridsterClass=function(){return{gridster:!0,"gridster-desktop":!h.isMobile,"gridster-mobile":h.isMobile,"gridster-loaded":h.loaded}},e.previewStyle=function(){return h.movingItem?{display:"block",height:h.movingItem.sizeY*h.curRowHeight-h.margins[0]+"px",width:h.movingItem.sizeX*h.curColWidth-h.margins[1]+"px",top:h.movingItem.row*h.curRowHeight+(h.outerMargin?h.margins[0]:0)+"px",left:h.movingItem.col*h.curColWidth+(h.outerMargin?h.margins[1]:0)+"px"}:{display:"none"}};var k=function(){h.setOptions(e.config),h.curWidth="auto"===h.width?f[0].offsetWidth||parseInt(f.css("width"),10):h.width,h.curColWidth="auto"===h.colWidth?(h.curWidth+(h.outerMargin?-h.margins[1]:h.margins[1]))/h.columns:h.colWidth,h.curRowHeight=h.rowHeight,"string"==typeof h.rowHeight&&("match"===h.rowHeight?h.curRowHeight=Math.round(h.curColWidth):-1!==h.rowHeight.indexOf("*")?h.curRowHeight=Math.round(h.curColWidth*h.rowHeight.replace("*","").replace(" ","")):-1!==h.rowHeight.indexOf("/")&&(h.curRowHeight=Math.round(h.curColWidth/h.rowHeight.replace("/","").replace(" ","")))),h.isMobile=h.mobileModeEnabled&&h.curWidth<=h.mobileBreakPoint;for(var a=0,b=h.grid.length;b>a;++a){var c=h.grid[a];if(c)for(var d=0,g=c.length;g>d;++d)if(c[d]){var i=c[d];i.setElementPosition(),i.setElementSizeY(),i.setElementSizeX()}}l()};e.$watch("config",k,!0),e.$watch("config.draggable",function(){c.$broadcast("gridster-draggable-changed")},!0),e.$watch("config.resizable",function(){c.$broadcast("gridster-resizable-changed")},!0);var l=function(){f.css("height",h.gridHeight*h.curRowHeight+(h.outerMargin?h.margins[0]:-h.margins[0])+"px")};e.$watch("gridster.gridHeight",l),e.$watch("gridster.movingItem",function(){h.updateHeight(h.movingItem?h.movingItem.sizeY:0)});var m=f[0].offsetWidth||parseInt(f.css("width"),10);"function"==typeof f.resize&&f.resize(j);var n=a.element(d);n.on("resize",j),e.$watch(function(){return f[0].offsetWidth||parseInt(f.css("width"),10)},i),e.$on("$destroy",function(){h.destroy(),n.off("resize",j)}),b(function(){e.$watch("gridster.floating",function(){h.floatItemsUp()}),h.loaded=!0},100)}}}}]).controller("GridsterItemCtrl",function(){this.$element=null,this.gridster=null,this.row=null,this.col=null,this.sizeX=null,this.sizeY=null,this.minSizeX=0,this.minSizeY=0,this.maxSizeX=null,this.maxSizeY=null,this.init=function(a,b){this.$element=a,this.gridster=b,this.sizeX=b.defaultSizeX,this.sizeY=b.defaultSizeY},this.destroy=function(){this.gridster=null,this.$element=null},this.toJSON=function(){return{row:this.row,col:this.col,sizeY:this.sizeY,sizeX:this.sizeX}},this.isMoving=function(){return this.gridster.movingItem===this},this.setPosition=function(a,b){this.gridster.putItem(this,a,b),this.isMoving()||this.setElementPosition()},this.setSize=function(a,b,c){a=a.toUpperCase();var d="size"+a,e="Size"+a;if(""!==b){b=parseInt(b,10),(isNaN(b)||0===b)&&(b=this.gridster["default"+e]);var f="X"===a?this.gridster.columns:this.gridster.maxRows;this["max"+e]&&(f=Math.min(this["max"+e],f)),this.gridster["max"+e]&&(f=Math.min(this.gridster["max"+e],f)),"X"===a&&this.cols?f-=this.cols:"Y"===a&&this.rows&&(f-=this.rows);var g=0;this["min"+e]&&(g=Math.max(this["min"+e],g)),this.gridster["min"+e]&&(g=Math.max(this.gridster["min"+e],g)),b=Math.max(Math.min(b,f),g);var h=this[d]!==b||this["old"+e]&&this["old"+e]!==b;return this["old"+e]=this[d]=b,this.isMoving()||this["setElement"+e](),!c&&h&&(this.gridster.moveOverlappingItems(this),this.gridster.layoutChanged()),h}},this.setSizeY=function(a,b){return this.setSize("Y",a,b)},this.setSizeX=function(a,b){return this.setSize("X",a,b)},this.setElementPosition=function(){this.$element.css(this.gridster.isMobile?{marginLeft:this.gridster.margins[0]+"px",marginRight:this.gridster.margins[0]+"px",marginTop:this.gridster.margins[1]+"px",marginBottom:this.gridster.margins[1]+"px",top:"",left:""}:{margin:0,top:this.row*this.gridster.curRowHeight+(this.gridster.outerMargin?this.gridster.margins[0]:0)+"px",left:this.col*this.gridster.curColWidth+(this.gridster.outerMargin?this.gridster.margins[1]:0)+"px"})},this.setElementSizeY=function(){this.gridster.isMobile&&!this.gridster.saveGridItemCalculatedHeightInMobile?this.$element.css("height",""):this.$element.css("height",this.sizeY*this.gridster.curRowHeight-this.gridster.margins[0]+"px")},this.setElementSizeX=function(){this.gridster.isMobile?this.$element.css("width",""):this.$element.css("width",this.sizeX*this.gridster.curColWidth-this.gridster.margins[1]+"px")},this.getElementSizeX=function(){return this.sizeX*this.gridster.curColWidth-this.gridster.margins[1]},this.getElementSizeY=function(){return this.sizeY*this.gridster.curRowHeight-this.gridster.margins[0]}}).factory("GridsterDraggable",["$document","$timeout","$window",function(b,c,d){function e(e,f,g,h,i){function j(b){if(-1!==G.indexOf(b.target.nodeName.toLowerCase()))return!1;if(a.element(b.target).hasClass("gridster-item-resizable-handler"))return!1;if(a.element(b.target).attr("onclick")||a.element(b.target).attr("ng-click"))return!1;switch(b.which){case 1:break;case 2:case 3:return}return y=b.pageX,z=b.pageY,p=parseInt(e.css("left"),10),q=parseInt(e.css("top"),10),r=e[0].offsetWidth,s=e[0].offsetHeight,t=h.col,u=h.row,m(b),!0}function k(a){if(!e.hasClass("gridster-item-moving")||e.hasClass("gridster-item-resizing"))return!1;var b=g.curWidth-1;w=a.pageX,x=a.pageY;var c=w-y+A,d=x-z+B;A=B=0,y=w,z=x;var f=c,h=d;return E>p+f?(c=E-p,A=f-c):p+r+f>b&&(c=b-p-r,A=f-c),C>q+h?(d=C-q,B=h-d):q+s+h>D&&(d=D-q-s,B=h-d),p+=c,q+=d,e.css({top:q+"px",left:p+"px"}),n(a),!0}function l(a){return!e.hasClass("gridster-item-moving")||e.hasClass("gridster-item-resizing")?!1:(A=B=0,o(a),!0)}function m(a){e.addClass("gridster-item-moving"),g.movingItem=h,g.updateHeight(h.sizeY),f.$apply(function(){g.draggable&&g.draggable.start&&g.draggable.start(a,e,i)})}function n(a){var b=h.row,c=h.col,j=g.draggable&&g.draggable.drag,k=g.draggable.scrollSensitivity,l=g.draggable.scrollSpeed,m=g.pixelsToRows(q),n=g.pixelsToColumns(p),o=g.getItems(m,n,h.sizeX,h.sizeY,h),r=0!==o.length;if(g.swapping===!0&&r){var s=g.getBoundingBox(o),t=s.sizeX===h.sizeX&&s.sizeY===h.sizeY,u=s.row===m,v=s.col===n,w=u&&v,x=u||v;if(t&&1===o.length){if(w)g.swapItems(h,o[0]);else if(x)return}else if(s.sizeX<=h.sizeX&&s.sizeY<=h.sizeY&&x)for(var y=h.row<=m?h.row:m+h.sizeY,z=h.col<=n?h.col:n+h.sizeX,A=y-s.row,B=z-s.col,C=0,D=o.length;D>C;++C){var E=o[C],G=g.getItems(E.row+A,E.col+B,E.sizeX,E.sizeY,h);0===G.length&&g.putItem(E,E.row+A,E.col+B)}}g.pushing===!1&&r||(h.row=m,h.col=n),a.pageY-F.body.scrollTop=0&&(q-go+g&&(f=C-o,B=g-f),o+=f,q-=f),v.indexOf("s")>=0&&(q+gD&&(f=D-o-q,B=g-f),q+=f),v.indexOf("w")>=0&&(p-hn+h&&(e=E-n,A=h-e),n+=e,p-=e),v.indexOf("e")>=0&&(p+hc&&(e=c-n-p,A=h-e),p+=e),b.css({top:o+"px",left:n+"px",width:p+"px",height:q+"px"}),l(a),!0}function k(a){return d.draggable.enabled!==t&&(d.draggable.enabled=t,c.$broadcast("gridster-draggable-changed")),A=B=0,m(a),!0}function l(a){var h=e.row,i=e.col,j=e.sizeX,k=e.sizeY,l=d.resizable&&d.resizable.resize,m=e.col;-1!==["w","nw","sw"].indexOf(g)&&(m=d.pixelsToColumns(n,!1));var r=e.row;-1!==["n","ne","nw"].indexOf(g)&&(r=d.pixelsToRows(o,!1));var s=e.sizeX;-1===["n","s"].indexOf(g)&&(s=d.pixelsToColumns(p,!0));var t=e.sizeY;-1===["e","w"].indexOf(g)&&(t=d.pixelsToRows(q,!0)),(d.pushing!==!1||0===d.getItems(r,m,s,t,e).length)&&(e.row=r,e.col=m,e.sizeX=s,e.sizeY=t);var u=e.row!==h||e.col!==i||e.sizeX!==j||e.sizeY!==k;(l||u)&&c.$apply(function(){l&&d.resizable.resize(a,b,f)})}function m(a){b.removeClass("gridster-item-moving"),b.removeClass("gridster-item-resizing"),d.movingItem=null,e.setPosition(e.row,e.col),e.setSizeY(e.sizeY),e.setSizeX(e.sizeX),c.$apply(function(){d.resizable&&d.resizable.stop&&d.resizable.stop(a,b,f)})}var n,o,p,q,r,s,t,u,v=g,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=9999,E=0,F=function(){return d.curRowHeight-d.margins[0]},G=function(){return d.curColWidth-d.margins[1]},H=null;this.enable=function(){H||(H=a.element('
    '),b.append(H)),u=new d.unifiedInput(H[0],h,j,k),u.enable()},this.disable=function(){H&&(H.remove(),H=null),u.disable(),u=void 0},this.destroy=function(){this.disable()}}var h=[],i=d.resizable.handles;"string"==typeof i&&(i=d.resizable.handles.split(","));for(var j=!1,k=0,l=i.length;l>k;k++)h.push(new g(i[k]));this.enable=function(){if(!j){for(var a=0,b=h.length;b>a;a++)h[a].enable();j=!0}},this.disable=function(){if(j){for(var a=0,b=h.length;b>a;a++)h[a].disable();j=!1}},this.toggle=function(a){a?this.enable():this.disable()},this.destroy=function(){for(var a=0,b=h.length;b>a;a++)h[a].destroy()}}return b}]).directive("gridsterItem",["$parse","GridsterDraggable","GridsterResizable",function(a,b,c){return{restrict:"EA",controller:"GridsterItemCtrl",require:["^gridster","gridsterItem"],link:function(d,e,f,g){function h(){n.setPosition(n.row,n.col),q.row&&q.row.assign&&q.row.assign(d,n.row),q.col&&q.col.assign&&q.col.assign(d,n.col)}function i(){var a=n.setSizeX(n.sizeX,!0);a&&q.sizeX&&q.sizeX.assign&&q.sizeX.assign(d,n.sizeX);var b=n.setSizeY(n.sizeY,!0);b&&q.sizeY&&q.sizeY.assign&&q.sizeY.assign(d,n.sizeY),(a||b)&&(n.gridster.moveOverlappingItems(n),m.layoutChanged())}function j(){var a=document.createElement("div"),b={transition:"transitionend",OTransition:"oTransitionEnd",MozTransition:"transitionend",WebkitTransition:"webkitTransitionEnd"};for(var c in b)if(void 0!==a.style[c])return b[c]}var k,l=f.gridsterItem,m=g[0],n=g[1];if(l){var o=a(l);k=o(d)||{},!k&&o.assign&&(k={row:n.row,col:n.col,sizeX:n.sizeX,sizeY:n.sizeY,minSizeX:0,minSizeY:0,maxSizeX:null,maxSizeY:null},o.assign(d,k))}else k=f;n.init(e,m),e.addClass("gridster-item");for(var p=["minSizeX","maxSizeX","minSizeY","maxSizeY","sizeX","sizeY","row","col"],q={},r=function(b){var c;if("string"==typeof k[b])c=k[b];else if("string"==typeof k[b.toLowerCase()])c=k[b.toLowerCase()];else{if(!l)return;c=a(l+"."+b)}q[b]=a(c),d.$watch(c,function(a){a=parseInt(a,10),isNaN(a)||(n[b]=a)});var e=q[b](d);"number"==typeof e&&(n[b]=e)},s=0,t=p.length;t>s;++s)r(p[s]);d.$broadcast("gridster-item-initialized",[n.sizeY,n.sizeX,n.getElementSizeY(),n.getElementSizeX()]),d.$watch(function(){return n.row+","+n.col},h),d.$watch(function(){return n.sizeY+","+n.sizeX+"|"+n.minSizeX+","+n.maxSizeX+","+n.minSizeY+","+n.maxSizeY},i);var u=new b(e,d,m,n,k),v=new c(e,d,m,n,k);return d.$on("gridster-draggable-changed",function(){u.toggle(!m.isMobile&&m.draggable&&m.draggable.enabled)}),d.$on("gridster-resizable-changed",function(){v.toggle(!m.isMobile&&m.resizable&&m.resizable.enabled)}),d.$on("gridster-resized",function(){v.toggle(!m.isMobile&&m.resizable&&m.resizable.enabled)}),d.$watch(function(){return m.isMobile},function(){v.toggle(!m.isMobile&&m.resizable&&m.resizable.enabled),u.toggle(!m.isMobile&&m.draggable&&m.draggable.enabled)}),e.on(j(),function(){d.$apply(function(){d.$broadcast("gridster-item-transition-end")})}),d.$on("$destroy",function(){try{v.destroy(),u.destroy()}catch(a){}try{m.removeItem(n)}catch(a){}try{n.destroy()}catch(a){}})}}}])}(angular); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/libs/angular-hotkeys_1.4.5/hotkeys--activiti-patch.js b/snow-flowable/src/main/resources/static/libs/angular-hotkeys_1.4.5/hotkeys--activiti-patch.js new file mode 100644 index 0000000..fa747f0 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-hotkeys_1.4.5/hotkeys--activiti-patch.js @@ -0,0 +1,1533 @@ +/*! + * angular-hotkeys v1.4.5 + * https://chieffancypants.github.io/angular-hotkeys + * Copyright (c) 2014 Wes Cruver + * License: MIT + */ +/* + * angular-hotkeys + * + * Automatic keyboard shortcuts for your angular apps + * + * (c) 2014 Wes Cruver + * License: MIT + */ + +(function() { + + 'use strict'; + + angular.module('cfp.hotkeys', []).provider('hotkeys', function() { + + /** + * Configurable setting to disable the cheatsheet entirely + * @type {Boolean} + */ + this.includeCheatSheet = true; + + /** + * Configurable setting for the cheat sheet title + * @type {String} + */ + + this.templateTitle = 'Keyboard Shortcuts:'; + + /** + * Cheat sheet template in the event you want to totally customize it. + * @type {String} + */ + this.template = ''; + + /** + * Configurable setting for the cheat sheet hotkey + * @type {String} + */ + this.cheatSheetHotkey = '?'; + + /** + * Configurable setting for the cheat sheet description + * @type {String} + */ + this.cheatSheetDescription = 'Show / hide this help menu'; + + this.$get = ['$rootElement', '$rootScope', '$compile', '$window', '$document', function ($rootElement, $rootScope, $compile, $window, $document) { + + // monkeypatch Mousetrap's stopCallback() function + // this version doesn't return true when the element is an INPUT, SELECT, or TEXTAREA + // (instead we will perform this check per-key in the _add() method) + Mousetrap.stopCallback = function(event, element) { + // if the element has the class "mousetrap" then no need to stop + if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) { + return false; + } + + return (element.contentEditable && element.contentEditable == 'true'); + }; + + /** + * Convert strings like cmd into symbols like ⌘ + * @param {String} combo Key combination, e.g. 'mod+f' + * @return {String} The key combination with symbols + */ + function symbolize (combo) { + var map = { + command : '⌘', + shift : '⇧', + left : '←', + right : '→', + up : '↑', + down : '↓', + 'return' : '↩', + backspace : '⌫' + }; + combo = combo.split('+'); + + for (var i = 0; i < combo.length; i++) { + // try to resolve command / ctrl based on OS: + if (combo[i] === 'mod') { + if ($window.navigator && $window.navigator.platform.indexOf('Mac') >=0 ) { + combo[i] = 'command'; + } else { + combo[i] = 'ctrl'; + } + } + + combo[i] = map[combo[i]] || combo[i]; + } + + return combo.join(' + '); + } + + /** + * Hotkey object used internally for consistency + * + * @param {array} combo The keycombo. it's an array to support multiple combos + * @param {String} description Description for the keycombo + * @param {Function} callback function to execute when keycombo pressed + * @param {string} action the type of event to listen for (for mousetrap) + * @param {array} allowIn an array of tag names to allow this combo in ('INPUT', 'SELECT', and/or 'TEXTAREA') + * @param {Boolean} persistent Whether the hotkey persists navigation events + */ + function Hotkey (combo, description, callback, action, allowIn, persistent) { + // TODO: Check that the values are sane because we could + // be trying to instantiate a new Hotkey with outside dev's + // supplied values + + this.combo = combo instanceof Array ? combo : [combo]; + this.description = description; + this.callback = callback; + this.action = action; + this.allowIn = allowIn; + this.persistent = persistent; + } + + /** + * Helper method to format (symbolize) the key combo for display + * + * @return {[Array]} An array of the key combination sequence + * for example: "command+g c i" becomes ["⌘ + g", "c", "i"] + * + * TODO: this gets called a lot. We should cache the result + */ + Hotkey.prototype.format = function() { + + // Don't show all the possible key combos, just the first one. Not sure + // of usecase here, so open a ticket if my assumptions are wrong + var combo = this.combo[0]; + + var sequence = combo.split(/[\s]/); + for (var i = 0; i < sequence.length; i++) { + sequence[i] = symbolize(sequence[i]); + } + + return sequence; + }; + + /** + * A new scope used internally for the cheatsheet + * @type {$rootScope.Scope} + */ + var scope = $rootScope.$new(); + + /** + * Holds an array of Hotkey objects currently bound + * @type {Array} + */ + scope.hotkeys = []; + + /** + * Contains the state of the help's visibility + * @type {Boolean} + */ + scope.helpVisible = false; + + /** + * Holds the title string for the help menu + * @type {String} + */ + scope.title = this.templateTitle; + + /** + * Expose toggleCheatSheet to hotkeys scope so we can call it using + * ng-click from the template + * @type {function} + */ + scope.toggleCheatSheet = toggleCheatSheet; + + + /** + * Holds references to the different scopes that have bound hotkeys + * attached. This is useful to catch when the scopes are `$destroy`d and + * then automatically unbind the hotkey. + * + * @type {Array} + */ + var boundScopes = []; + + + $rootScope.$on('$routeChangeSuccess', function (event, route) { + purgeHotkeys(); + + if (route && route.hotkeys) { + angular.forEach(route.hotkeys, function (hotkey) { + // a string was given, which implies this is a function that is to be + // $eval()'d within that controller's scope + // TODO: hotkey here is super confusing. sometimes a function (that gets turned into an array), sometimes a string + var callback = hotkey[2]; + if (typeof(callback) === 'string' || callback instanceof String) { + hotkey[2] = [callback, route]; + } + + // todo: perform check to make sure not already defined: + // this came from a route, so it's likely not meant to be persistent + hotkey[5] = false; + _add.apply(this, hotkey); + }); + } + }); + + + // Auto-create a help menu: + if (this.includeCheatSheet) { + var document = $document[0]; + var element = $rootElement[0]; + var helpMenu = angular.element(this.template); + _add(this.cheatSheetHotkey, this.cheatSheetDescription, toggleCheatSheet); + + // If $rootElement is document or documentElement, then body must be used + if (element === document || element === document.documentElement) { + element = document.body; + } + + angular.element(element).append($compile(helpMenu)(scope)); + } + + + /** + * Purges all non-persistent hotkeys (such as those defined in routes) + * + * Without this, the same hotkey would get recreated everytime + * the route is accessed. + */ + function purgeHotkeys() { + var i = scope.hotkeys.length; + while (i--) { + var hotkey = scope.hotkeys[i]; + if (hotkey && !hotkey.persistent) { + _del(hotkey); + } + } + } + + /** + * Toggles the help menu element's visiblity + */ + var previousEsc = false; + + function toggleCheatSheet() { + scope.helpVisible = !scope.helpVisible; + + // Bind to esc to remove the cheat sheet. Ideally, this would be done + // as a directive in the template, but that would create a nasty + // circular dependency issue that I don't feel like sorting out. + if (scope.helpVisible) { + previousEsc = _get('esc'); + _del('esc'); + + // Here's an odd way to do this: we're going to use the original + // description of the hotkey on the cheat sheet so that it shows up. + // without it, no entry for esc will ever show up (#22) + _add('esc', previousEsc.description, toggleCheatSheet); + } else { + _del('esc'); + + // restore the previously bound ESC key + if (previousEsc !== false) { + _add(previousEsc); + } + } + } + + /** + * Creates a new Hotkey and creates the Mousetrap binding + * + * @param {string} combo mousetrap key binding + * @param {string} description description for the help menu + * @param {Function} callback method to call when key is pressed + * @param {string} action the type of event to listen for (for mousetrap) + * @param {array} allowIn an array of tag names to allow this combo in ('INPUT', 'SELECT', and/or 'TEXTAREA') + * @param {boolean} persistent if true, the binding is preserved upon route changes + */ + function _add (combo, description, callback, action, allowIn, persistent) { + + // used to save original callback for "allowIn" wrapping: + var _callback; + + // these elements are prevented by the default Mousetrap.stopCallback(): + var preventIn = ['INPUT', 'SELECT', 'TEXTAREA']; + + // Determine if object format was given: + var objType = Object.prototype.toString.call(combo); + + if (objType === '[object Object]') { + description = combo.description; + callback = combo.callback; + action = combo.action; + persistent = combo.persistent; + allowIn = combo.allowIn; + combo = combo.combo; + } + + // description is optional: + if (description instanceof Function) { + action = callback; + callback = description; + description = '$$undefined$$'; + } else if (angular.isUndefined(description)) { + description = '$$undefined$$'; + } + + // any items added through the public API are for controllers + // that persist through navigation, and thus undefined should mean + // true in this case. + if (persistent === undefined) { + persistent = true; + } + + // if callback is defined, then wrap it in a function + // that checks if the event originated from a form element. + // the function blocks the callback from executing unless the element is specified + // in allowIn (emulates Mousetrap.stopCallback() on a per-key level) + if (typeof callback === 'function') { + + // save the original callback + _callback = callback; + + // make sure allowIn is an array + if (!(allowIn instanceof Array)) { + allowIn = []; + } + + // remove anything from preventIn that's present in allowIn + var index; + for (var i=0; i < allowIn.length; i++) { + allowIn[i] = allowIn[i].toUpperCase(); + index = preventIn.indexOf(allowIn[i]); + if (index !== -1) { + preventIn.splice(index, 1); + } + } + + // create the new wrapper callback + callback = function(event) { + var shouldExecute = true; + var target = event.target || event.srcElement; // srcElement is IE only + var nodeName = target.nodeName.toUpperCase(); + + // check if the input has a mousetrap class, and skip checking preventIn if so + if ((' ' + target.className + ' ').indexOf(' mousetrap ') > -1) { + shouldExecute = true; + } else { + // don't execute callback if the event was fired from inside an element listed in preventIn + for (var i=0; i -1) { + // if the combo has other combos bound, don't unbind the whole thing, just the one combo: + if (scope.hotkeys[index].combo.length > 1) { + scope.hotkeys[index].combo.splice(scope.hotkeys[index].combo.indexOf(combo), 1); + } else { + scope.hotkeys.splice(index, 1); + } + return true; + } + } + + return false; + + } + + /** + * Get a Hotkey object by key binding + * + * @param {[string]} combo the key the Hotkey is bound to + * @return {Hotkey} The Hotkey object + */ + function _get (combo) { + + var hotkey; + + for (var i = 0; i < scope.hotkeys.length; i++) { + hotkey = scope.hotkeys[i]; + + if (hotkey.combo.indexOf(combo) > -1) { + return hotkey; + } + } + + return false; + } + + /** + * Binds the hotkey to a particular scope. Useful if the scope is + * destroyed, we can automatically destroy the hotkey binding. + * + * @param {Object} scope The scope to bind to + */ + function bindTo (scope) { + // Only initialize once to allow multiple calls for same scope. + if (!(scope.$id in boundScopes)) { + + // Add the scope to the list of bound scopes + boundScopes[scope.$id] = []; + + scope.$on('$destroy', function () { + var i = boundScopes[scope.$id].length; + while (i--) { + _del(boundScopes[scope.$id][i]); + delete boundScopes[scope.$id][i]; + } + }); + } + // return an object with an add function so we can keep track of the + // hotkeys and their scope that we added via this chaining method + return { + add: function (args) { + var hotkey; + + if (arguments.length > 1) { + hotkey = _add.apply(this, arguments); + } else { + hotkey = _add(args); + } + + boundScopes[scope.$id].push(hotkey); + return this; + } + }; + } + + /** + * All callbacks sent to Mousetrap are wrapped using this function + * so that we can force a $scope.$apply() + * + * @param {Function} callback [description] + * @return {[type]} [description] + */ + function wrapApply (callback) { + // return mousetrap a function to call + return function (event, combo) { + + // if this is an array, it means we provided a route object + // because the scope wasn't available yet, so rewrap the callback + // now that the scope is available: + if (callback instanceof Array) { + var funcString = callback[0]; + var route = callback[1]; + callback = function (event) { + route.scope.$eval(funcString); + }; + } + + // this takes place outside angular, so we'll have to call + // $apply() to make sure angular's digest happens + $rootScope.$apply(function() { + // call the original hotkey callback with the keyboard event + callback(event, _get(combo)); + }); + }; + } + + + var publicApi = { + add : _add, + del : _del, + get : _get, + bindTo : bindTo, + template : this.template, + toggleCheatSheet : toggleCheatSheet, + includeCheatSheet : this.includeCheatSheet, + cheatSheetHotkey : this.cheatSheetHotkey, + cheatSheetDescription : this.cheatSheetDescription, + purgeHotkeys : purgeHotkeys, + templateTitle : this.templateTitle + }; + + return publicApi; + + }]; + }) + + .directive('hotkey', ['hotkeys', function (hotkeys) { + return { + restrict: 'A', + link: function (scope, el, attrs) { + var key, allowIn; + + angular.forEach(scope.$eval(attrs.hotkey), function (func, hotkey) { + // split and trim the hotkeys string into array + allowIn = typeof attrs.hotkeyAllowIn === "string" ? attrs.hotkeyAllowIn.split(/[\s,]+/) : []; + + key = hotkey; + + hotkeys.add({ + combo: hotkey, + description: attrs.hotkeyDescription, + callback: func, + action: attrs.hotkeyAction, + allowIn: allowIn + }); + }); + + // remove the hotkey if the directive is destroyed: + el.bind('$destroy', function() { + hotkeys.del(key); + }); + } + }; + }]) + + .run(['hotkeys', function(hotkeys) { + // force hotkeys to run by injecting it. Without this, hotkeys only runs + // when a controller or something else asks for it via DI. + }]); + +})(); + +/*global define:false */ +/** + * Copyright 2013 Craig Campbell + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Mousetrap is a simple keyboard shortcut library for Javascript with + * no external dependencies + * + * @version 1.4.6 + * @url craig.is/killing/mice + */ +(function(window, document, undefined) { + + /** + * mapping of special keycodes to their corresponding keys + * + * everything in this dictionary cannot use keypress events + * so it has to be here to map to the correct keycodes for + * keyup/keydown events + * + * @type {Object} + */ + var _MAP = { + 8: 'backspace', + 9: 'tab', + 13: 'enter', + 16: 'shift', + 17: 'ctrl', + 18: 'alt', + 20: 'capslock', + 27: 'esc', + 32: 'space', + 33: 'pageup', + 34: 'pagedown', + 35: 'end', + 36: 'home', + 37: 'left', + 38: 'up', + 39: 'right', + 40: 'down', + 45: 'ins', + 46: 'del', + 91: 'meta', + 93: 'meta', + 224: 'meta' + }, + + /** + * mapping for special characters so they can support + * + * this dictionary is only used incase you want to bind a + * keyup or keydown event to one of these keys + * + * @type {Object} + */ + _KEYCODE_MAP = { + 106: '*', + 107: '+', + 109: '-', + 110: '.', + 111 : '/', + 186: ';', + 187: '=', + 188: ',', + 189: '-', + 190: '.', + 191: '/', + 192: '`', + 219: '[', + 220: '\\', + 221: ']', + 222: '\'' + }, + + /** + * this is a mapping of keys that require shift on a US keypad + * back to the non shift equivelents + * + * this is so you can use keyup events with these keys + * + * note that this will only work reliably on US keyboards + * + * @type {Object} + */ + _SHIFT_MAP = { + '~': '`', + '!': '1', + '@': '2', + '#': '3', + '$': '4', + '%': '5', + '^': '6', + '&': '7', + '*': '8', + '(': '9', + ')': '0', + '_': '-', + '+': '=', + ':': ';', + '\"': '\'', + '<': ',', + '>': '.', + '?': '/', + '|': '\\' + }, + + /** + * this is a list of special strings you can use to map + * to modifier keys when you specify your keyboard shortcuts + * + * @type {Object} + */ + _SPECIAL_ALIASES = { + 'option': 'alt', + 'command': 'meta', + 'return': 'enter', + 'escape': 'esc', + 'mod': /Mac|iPod|iPhone|iPad/.test(navigator.platform) ? 'meta' : 'ctrl' + }, + + /** + * variable to store the flipped version of _MAP from above + * needed to check if we should use keypress or not when no action + * is specified + * + * @type {Object|undefined} + */ + _REVERSE_MAP, + + /** + * a list of all the callbacks setup via Mousetrap.bind() + * + * @type {Object} + */ + _callbacks = {}, + + /** + * direct map of string combinations to callbacks used for trigger() + * + * @type {Object} + */ + _directMap = {}, + + /** + * keeps track of what level each sequence is at since multiple + * sequences can start out with the same sequence + * + * @type {Object} + */ + _sequenceLevels = {}, + + /** + * variable to store the setTimeout call + * + * @type {null|number} + */ + _resetTimer, + + /** + * temporary state where we will ignore the next keyup + * + * @type {boolean|string} + */ + _ignoreNextKeyup = false, + + /** + * temporary state where we will ignore the next keypress + * + * @type {boolean} + */ + _ignoreNextKeypress = false, + + /** + * are we currently inside of a sequence? + * type of action ("keyup" or "keydown" or "keypress") or false + * + * @type {boolean|string} + */ + _nextExpectedAction = false; + + /** + * loop through the f keys, f1 to f19 and add them to the map + * programatically + */ + for (var i = 1; i < 20; ++i) { + _MAP[111 + i] = 'f' + i; + } + + /** + * loop through to map numbers on the numeric keypad + */ + for (i = 0; i <= 9; ++i) { + _MAP[i + 96] = i; + } + + /** + * cross browser add event method + * + * @param {Element|HTMLDocument} object + * @param {string} type + * @param {Function} callback + * @returns void + */ + function _addEvent(object, type, callback) { + if (object.addEventListener) { + object.addEventListener(type, callback, false); + return; + } + + object.attachEvent('on' + type, callback); + } + + /** + * takes the event and returns the key character + * + * @param {Event} e + * @return {string} + */ + function _characterFromEvent(e) { + + // for keypress events we should return the character as is + if (e.type == 'keypress') { + var character = String.fromCharCode(e.which); + + // if the shift key is not pressed then it is safe to assume + // that we want the character to be lowercase. this means if + // you accidentally have caps lock on then your key bindings + // will continue to work + // + // the only side effect that might not be desired is if you + // bind something like 'A' cause you want to trigger an + // event when capital A is pressed caps lock will no longer + // trigger the event. shift+a will though. + if (!e.shiftKey) { + character = character.toLowerCase(); + } + + return character; + } + + // for non keypress events the special maps are needed + if (_MAP[e.which]) { + return _MAP[e.which]; + } + + if (_KEYCODE_MAP[e.which]) { + return _KEYCODE_MAP[e.which]; + } + + // if it is not in the special map + + // with keydown and keyup events the character seems to always + // come in as an uppercase character whether you are pressing shift + // or not. we should make sure it is always lowercase for comparisons + return String.fromCharCode(e.which).toLowerCase(); + } + + /** + * checks if two arrays are equal + * + * @param {Array} modifiers1 + * @param {Array} modifiers2 + * @returns {boolean} + */ + function _modifiersMatch(modifiers1, modifiers2) { + return modifiers1.sort().join(',') === modifiers2.sort().join(','); + } + + /** + * resets all sequence counters except for the ones passed in + * + * @param {Object} doNotReset + * @returns void + */ + function _resetSequences(doNotReset) { + doNotReset = doNotReset || {}; + + var activeSequences = false, + key; + + for (key in _sequenceLevels) { + if (doNotReset[key]) { + activeSequences = true; + continue; + } + _sequenceLevels[key] = 0; + } + + if (!activeSequences) { + _nextExpectedAction = false; + } + } + + /** + * finds all callbacks that match based on the keycode, modifiers, + * and action + * + * @param {string} character + * @param {Array} modifiers + * @param {Event|Object} e + * @param {string=} sequenceName - name of the sequence we are looking for + * @param {string=} combination + * @param {number=} level + * @returns {Array} + */ + function _getMatches(character, modifiers, e, sequenceName, combination, level) { + var i, + callback, + matches = [], + action = e.type; + + // if there are no events related to this keycode + if (!_callbacks[character]) { + return []; + } + + // if a modifier key is coming up on its own we should allow it + if (action == 'keyup' && _isModifier(character)) { + modifiers = [character]; + } + + // loop through all callbacks for the key that was pressed + // and see if any of them match + for (i = 0; i < _callbacks[character].length; ++i) { + callback = _callbacks[character][i]; + + // if a sequence name is not specified, but this is a sequence at + // the wrong level then move onto the next match + if (!sequenceName && callback.seq && _sequenceLevels[callback.seq] != callback.level) { + continue; + } + + // if the action we are looking for doesn't match the action we got + // then we should keep going + if (action != callback.action) { + continue; + } + + // if this is a keypress event and the meta key and control key + // are not pressed that means that we need to only look at the + // character, otherwise check the modifiers as well + // + // chrome will not fire a keypress if meta or control is down + // safari will fire a keypress if meta or meta+shift is down + // firefox will fire a keypress if meta or control is down + if ((action == 'keypress' && !e.metaKey && !e.ctrlKey) || _modifiersMatch(modifiers, callback.modifiers)) { + + // when you bind a combination or sequence a second time it + // should overwrite the first one. if a sequenceName or + // combination is specified in this call it does just that + // + // @todo make deleting its own method? + var deleteCombo = !sequenceName && callback.combo == combination; + var deleteSequence = sequenceName && callback.seq == sequenceName && callback.level == level; + if (deleteCombo || deleteSequence) { + _callbacks[character].splice(i, 1); + } + + matches.push(callback); + } + } + + return matches; + } + + /** + * takes a key event and figures out what the modifiers are + * + * @param {Event} e + * @returns {Array} + */ + function _eventModifiers(e) { + var modifiers = []; + + if (e.shiftKey) { + modifiers.push('shift'); + } + + if (e.altKey) { + modifiers.push('alt'); + } + + if (e.ctrlKey) { + modifiers.push('ctrl'); + } + + if (e.metaKey) { + modifiers.push('meta'); + } + + return modifiers; + } + + /** + * prevents default for this event + * + * @param {Event} e + * @returns void + */ + function _preventDefault(e) { + if (e.preventDefault) { + e.preventDefault(); + return; + } + + e.returnValue = false; + } + + /** + * stops propogation for this event + * + * @param {Event} e + * @returns void + */ + function _stopPropagation(e) { + if (e.stopPropagation) { + e.stopPropagation(); + return; + } + + e.cancelBubble = true; + } + + /** + * actually calls the callback function + * + * if your callback function returns false this will use the jquery + * convention - prevent default and stop propogation on the event + * + * @param {Function} callback + * @param {Event} e + * @returns void + */ + function _fireCallback(callback, e, combo, sequence) { + + // if this event should not happen stop here + if (Mousetrap.stopCallback(e, e.target || e.srcElement, combo, sequence)) { + return; + } + + if (callback(e, combo) === false) { + _preventDefault(e); + _stopPropagation(e); + } + } + + /** + * handles a character key event + * + * @param {string} character + * @param {Array} modifiers + * @param {Event} e + * @returns void + */ + function _handleKey(character, modifiers, e) { + var callbacks = _getMatches(character, modifiers, e), + i, + doNotReset = {}, + maxLevel = 0, + processedSequenceCallback = false; + + // Calculate the maxLevel for sequences so we can only execute the longest callback sequence + for (i = 0; i < callbacks.length; ++i) { + if (callbacks[i].seq) { + maxLevel = Math.max(maxLevel, callbacks[i].level); + } + } + + // loop through matching callbacks for this key event + for (i = 0; i < callbacks.length; ++i) { + + // fire for all sequence callbacks + // this is because if for example you have multiple sequences + // bound such as "g i" and "g t" they both need to fire the + // callback for matching g cause otherwise you can only ever + // match the first one + if (callbacks[i].seq) { + + // only fire callbacks for the maxLevel to prevent + // subsequences from also firing + // + // for example 'a option b' should not cause 'option b' to fire + // even though 'option b' is part of the other sequence + // + // any sequences that do not match here will be discarded + // below by the _resetSequences call + if (callbacks[i].level != maxLevel) { + continue; + } + + processedSequenceCallback = true; + + // keep a list of which sequences were matches for later + doNotReset[callbacks[i].seq] = 1; + _fireCallback(callbacks[i].callback, e, callbacks[i].combo, callbacks[i].seq); + continue; + } + + // if there were no sequence matches but we are still here + // that means this is a regular match so we should fire that + if (!processedSequenceCallback) { + _fireCallback(callbacks[i].callback, e, callbacks[i].combo); + } + } + + // if the key you pressed matches the type of sequence without + // being a modifier (ie "keyup" or "keypress") then we should + // reset all sequences that were not matched by this event + // + // this is so, for example, if you have the sequence "h a t" and you + // type "h e a r t" it does not match. in this case the "e" will + // cause the sequence to reset + // + // modifier keys are ignored because you can have a sequence + // that contains modifiers such as "enter ctrl+space" and in most + // cases the modifier key will be pressed before the next key + // + // also if you have a sequence such as "ctrl+b a" then pressing the + // "b" key will trigger a "keypress" and a "keydown" + // + // the "keydown" is expected when there is a modifier, but the + // "keypress" ends up matching the _nextExpectedAction since it occurs + // after and that causes the sequence to reset + // + // we ignore keypresses in a sequence that directly follow a keydown + // for the same character + var ignoreThisKeypress = e.type == 'keypress' && _ignoreNextKeypress; + if (e.type == _nextExpectedAction && !_isModifier(character) && !ignoreThisKeypress) { + _resetSequences(doNotReset); + } + + _ignoreNextKeypress = processedSequenceCallback && e.type == 'keydown'; + } + + /** + * handles a keydown event + * + * @param {Event} e + * @returns void + */ + function _handleKeyEvent(e) { + + // normalize e.which for key events + // @see http://stackoverflow.com/questions/4285627/javascript-keycode-vs-charcode-utter-confusion + if (typeof e.which !== 'number') { + e.which = e.keyCode; + } + + var character = _characterFromEvent(e); + + // no character found then stop + if (!character) { + return; + } + + // need to use === for the character check because the character can be 0 + if (e.type == 'keyup' && _ignoreNextKeyup === character) { + _ignoreNextKeyup = false; + return; + } + + Mousetrap.handleKey(character, _eventModifiers(e), e); + } + + /** + * determines if the keycode specified is a modifier key or not + * + * @param {string} key + * @returns {boolean} + */ + function _isModifier(key) { + return key == 'shift' || key == 'ctrl' || key == 'alt' || key == 'meta'; + } + + /** + * called to set a 1 second timeout on the specified sequence + * + * this is so after each key press in the sequence you have 1 second + * to press the next key before you have to start over + * + * @returns void + */ + function _resetSequenceTimer() { + clearTimeout(_resetTimer); + _resetTimer = setTimeout(_resetSequences, 1000); + } + + /** + * reverses the map lookup so that we can look for specific keys + * to see what can and can't use keypress + * + * @return {Object} + */ + function _getReverseMap() { + if (!_REVERSE_MAP) { + _REVERSE_MAP = {}; + for (var key in _MAP) { + + // pull out the numeric keypad from here cause keypress should + // be able to detect the keys from the character + if (key > 95 && key < 112) { + continue; + } + + if (_MAP.hasOwnProperty(key)) { + _REVERSE_MAP[_MAP[key]] = key; + } + } + } + return _REVERSE_MAP; + } + + /** + * picks the best action based on the key combination + * + * @param {string} key - character for key + * @param {Array} modifiers + * @param {string=} action passed in + */ + function _pickBestAction(key, modifiers, action) { + + // if no action was picked in we should try to pick the one + // that we think would work best for this key + if (!action) { + action = _getReverseMap()[key] ? 'keydown' : 'keypress'; + } + + // modifier keys don't work as expected with keypress, + // switch to keydown + if (action == 'keypress' && modifiers.length) { + action = 'keydown'; + } + + return action; + } + + /** + * binds a key sequence to an event + * + * @param {string} combo - combo specified in bind call + * @param {Array} keys + * @param {Function} callback + * @param {string=} action + * @returns void + */ + function _bindSequence(combo, keys, callback, action) { + + // start off by adding a sequence level record for this combination + // and setting the level to 0 + _sequenceLevels[combo] = 0; + + /** + * callback to increase the sequence level for this sequence and reset + * all other sequences that were active + * + * @param {string} nextAction + * @returns {Function} + */ + function _increaseSequence(nextAction) { + return function() { + _nextExpectedAction = nextAction; + ++_sequenceLevels[combo]; + _resetSequenceTimer(); + }; + } + + /** + * wraps the specified callback inside of another function in order + * to reset all sequence counters as soon as this sequence is done + * + * @param {Event} e + * @returns void + */ + function _callbackAndReset(e) { + _fireCallback(callback, e, combo); + + // we should ignore the next key up if the action is key down + // or keypress. this is so if you finish a sequence and + // release the key the final key will not trigger a keyup + if (action !== 'keyup') { + _ignoreNextKeyup = _characterFromEvent(e); + } + + // weird race condition if a sequence ends with the key + // another sequence begins with + setTimeout(_resetSequences, 10); + } + + // loop through keys one at a time and bind the appropriate callback + // function. for any key leading up to the final one it should + // increase the sequence. after the final, it should reset all sequences + // + // if an action is specified in the original bind call then that will + // be used throughout. otherwise we will pass the action that the + // next key in the sequence should match. this allows a sequence + // to mix and match keypress and keydown events depending on which + // ones are better suited to the key provided + for (var i = 0; i < keys.length; ++i) { + var isFinal = i + 1 === keys.length; + var wrappedCallback = isFinal ? _callbackAndReset : _increaseSequence(action || _getKeyInfo(keys[i + 1]).action); + _bindSingle(keys[i], wrappedCallback, action, combo, i); + } + } + + /** + * Converts from a string key combination to an array + * + * @param {string} combination like "command+shift+l" + * @return {Array} + */ + function _keysFromString(combination) { + if (combination === '+') { + return ['+']; + } + + return combination.split('+'); + } + + /** + * Gets info for a specific key combination + * + * @param {string} combination key combination ("command+s" or "a" or "*") + * @param {string=} action + * @returns {Object} + */ + function _getKeyInfo(combination, action) { + var keys, + key, + i, + modifiers = []; + + // take the keys from this pattern and figure out what the actual + // pattern is all about + keys = _keysFromString(combination); + + for (i = 0; i < keys.length; ++i) { + key = keys[i]; + + // normalize key names + if (_SPECIAL_ALIASES[key]) { + key = _SPECIAL_ALIASES[key]; + } + + // if this is not a keypress event then we should + // be smart about using shift keys + // this will only work for US keyboards however + if (action && action != 'keypress' && _SHIFT_MAP[key]) { + key = _SHIFT_MAP[key]; + modifiers.push('shift'); + } + + // if this key is a modifier then add it to the list of modifiers + if (_isModifier(key)) { + modifiers.push(key); + } + } + + // depending on what the key combination is + // we will try to pick the best event for it + action = _pickBestAction(key, modifiers, action); + + return { + key: key, + modifiers: modifiers, + action: action + }; + } + + /** + * binds a single keyboard combination + * + * @param {string} combination + * @param {Function} callback + * @param {string=} action + * @param {string=} sequenceName - name of sequence if part of sequence + * @param {number=} level - what part of the sequence the command is + * @returns void + */ + function _bindSingle(combination, callback, action, sequenceName, level) { + + // store a direct mapped reference for use with Mousetrap.trigger + _directMap[combination + ':' + action] = callback; + + // make sure multiple spaces in a row become a single space + combination = combination.replace(/\s+/g, ' '); + + var sequence = combination.split(' '), + info; + + // if this pattern is a sequence of keys then run through this method + // to reprocess each pattern one key at a time + if (sequence.length > 1) { + _bindSequence(combination, sequence, callback, action); + return; + } + + info = _getKeyInfo(combination, action); + + // make sure to initialize array if this is the first time + // a callback is added for this key + _callbacks[info.key] = _callbacks[info.key] || []; + + // remove an existing match if there is one + _getMatches(info.key, info.modifiers, {type: info.action}, sequenceName, combination, level); + + // add this call back to the array + // if it is a sequence put it at the beginning + // if not put it at the end + // + // this is important because the way these are processed expects + // the sequence ones to come first + _callbacks[info.key][sequenceName ? 'unshift' : 'push']({ + callback: callback, + modifiers: info.modifiers, + action: info.action, + seq: sequenceName, + level: level, + combo: combination + }); + } + + /** + * binds multiple combinations to the same callback + * + * @param {Array} combinations + * @param {Function} callback + * @param {string|undefined} action + * @returns void + */ + function _bindMultiple(combinations, callback, action) { + for (var i = 0; i < combinations.length; ++i) { + _bindSingle(combinations[i], callback, action); + } + } + + // start! + _addEvent(document, 'keypress', _handleKeyEvent); + _addEvent(document, 'keydown', _handleKeyEvent); + _addEvent(document, 'keyup', _handleKeyEvent); + + var Mousetrap = { + + /** + * binds an event to mousetrap + * + * can be a single key, a combination of keys separated with +, + * an array of keys, or a sequence of keys separated by spaces + * + * be sure to list the modifier keys first to make sure that the + * correct key ends up getting bound (the last key in the pattern) + * + * @param {string|Array} keys + * @param {Function} callback + * @param {string=} action - 'keypress', 'keydown', or 'keyup' + * @returns void + */ + bind: function(keys, callback, action) { + keys = keys instanceof Array ? keys : [keys]; + _bindMultiple(keys, callback, action); + return this; + }, + + /** + * unbinds an event to mousetrap + * + * the unbinding sets the callback function of the specified key combo + * to an empty function and deletes the corresponding key in the + * _directMap dict. + * + * TODO: actually remove this from the _callbacks dictionary instead + * of binding an empty function + * + * the keycombo+action has to be exactly the same as + * it was defined in the bind method + * + * @param {string|Array} keys + * @param {string} action + * @returns void + */ + unbind: function(keys, action) { + return Mousetrap.bind(keys, function() {}, action); + }, + + /** + * triggers an event that has already been bound + * + * @param {string} keys + * @param {string=} action + * @returns void + */ + trigger: function(keys, action) { + if (_directMap[keys + ':' + action]) { + _directMap[keys + ':' + action]({}, keys); + } + return this; + }, + + /** + * resets the library back to its initial state. this is useful + * if you want to clear out the current keyboard shortcuts and bind + * new ones - for example if you switch to another page + * + * @returns void + */ + reset: function() { + _callbacks = {}; + _directMap = {}; + return this; + }, + + /** + * should we stop this event before firing off callbacks + * + * @param {Event} e + * @param {Element} element + * @return {boolean} + */ + stopCallback: function(e, element) { + + // if the element has the class "mousetrap" then no need to stop + if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) { + return false; + } + + // stop for input, select, and textarea + return element.tagName == 'INPUT' || element.tagName == 'SELECT' || element.tagName == 'TEXTAREA' || element.isContentEditable; + }, + + /** + * exposes _handleKey publicly so it can be overwritten by extensions + */ + handleKey: _handleKey + }; + + // expose mousetrap to the global object + window.Mousetrap = Mousetrap; + + /* + + Can't let hotkeys define itself as a module since it will cause Flowable to not work in Alfresco Share: + In Share this file is being loaded from a +
    + Snippet: + + + + + + + + + + + + + + + + + + + + + + + + + +
    DirectiveHowSourceRendered
    ng-bind-htmlAutomatically uses $sanitize
    <div ng-bind-html="snippet">
    </div>
    ng-bind-htmlBypass $sanitize by explicitly trusting the dangerous value +
    <div ng-bind-html="deliberatelyTrustDangerousSnippet()">
    +</div>
    +
    ng-bindAutomatically escapes
    <div ng-bind="snippet">
    </div>
    +
    + + + it('should sanitize the html snippet by default', function() { + expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()). + toBe('

    an html\nclick here\nsnippet

    '); + }); + + it('should inline raw snippet if bound to a trusted value', function() { + expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()). + toBe("

    an html\n" + + "click here\n" + + "snippet

    "); + }); + + it('should escape snippet without any filter', function() { + expect(element(by.css('#bind-default div')).getInnerHtml()). + toBe("<p style=\"color:blue\">an html\n" + + "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + + "snippet</p>"); + }); + + it('should update', function() { + element(by.model('snippet')).clear(); + element(by.model('snippet')).sendKeys('new text'); + expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()). + toBe('new text'); + expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).toBe( + 'new text'); + expect(element(by.css('#bind-default div')).getInnerHtml()).toBe( + "new <b onclick=\"alert(1)\">text</b>"); + }); +
    + + */ +function $SanitizeProvider() { + this.$get = ['$$sanitizeUri', function($$sanitizeUri) { + return function(html) { + var buf = []; + htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) { + return !/^unsafe/.test($$sanitizeUri(uri, isImage)); + })); + return buf.join(''); + }; + }]; +} + +function sanitizeText(chars) { + var buf = []; + var writer = htmlSanitizeWriter(buf, angular.noop); + writer.chars(chars); + return buf.join(''); +} + + +// Regular Expressions for parsing tags and attributes +var START_TAG_REGEXP = + /^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/, + END_TAG_REGEXP = /^<\/\s*([\w:-]+)[^>]*>/, + ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g, + BEGIN_TAG_REGEXP = /^/g, + DOCTYPE_REGEXP = /]*?)>/i, + CDATA_REGEXP = //g, + SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g, + // Match everything outside of normal chars and " (quote character) + NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; + + +// Good source of info about elements and attributes +// http://dev.w3.org/html5/spec/Overview.html#semantics +// http://simon.html5.org/html-elements + +// Safe Void Elements - HTML5 +// http://dev.w3.org/html5/spec/Overview.html#void-elements +var voidElements = makeMap("area,br,col,hr,img,wbr"); + +// Elements that you can, intentionally, leave open (and which close themselves) +// http://dev.w3.org/html5/spec/Overview.html#optional-tags +var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"), + optionalEndTagInlineElements = makeMap("rp,rt"), + optionalEndTagElements = angular.extend({}, + optionalEndTagInlineElements, + optionalEndTagBlockElements); + +// Safe Block Elements - HTML5 +var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article," + + "aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," + + "h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul")); + +// Inline Elements - HTML5 +var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b," + + "bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," + + "samp,small,span,strike,strong,sub,sup,time,tt,u,var")); + +// SVG Elements +// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements +var svgElements = makeMap("animate,animateColor,animateMotion,animateTransform,circle,defs," + + "desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,hkern,image,linearGradient," + + "line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,radialGradient,rect,set," + + "stop,svg,switch,text,title,tspan,use"); + +// Special Elements (can contain anything) +var specialElements = makeMap("script,style"); + +var validElements = angular.extend({}, + voidElements, + blockElements, + inlineElements, + optionalEndTagElements, + svgElements); + +//Attributes that have href and hence need to be sanitized +var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap,xlink:href"); + +var htmlAttrs = makeMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' + + 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' + + 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' + + 'scope,scrolling,shape,size,span,start,summary,target,title,type,' + + 'valign,value,vspace,width'); + +// SVG attributes (without "id" and "name" attributes) +// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes +var svgAttrs = makeMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' + + 'attributeName,attributeType,baseProfile,bbox,begin,by,calcMode,cap-height,class,color,' + + 'color-rendering,content,cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,' + + 'font-size,font-stretch,font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,' + + 'gradientUnits,hanging,height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,' + + 'keySplines,keyTimes,lang,marker-end,marker-mid,marker-start,markerHeight,markerUnits,' + + 'markerWidth,mathematical,max,min,offset,opacity,orient,origin,overline-position,' + + 'overline-thickness,panose-1,path,pathLength,points,preserveAspectRatio,r,refX,refY,' + + 'repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,' + + 'stemv,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,stroke,' + + 'stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,' + + 'stroke-opacity,stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,' + + 'underline-position,underline-thickness,unicode,unicode-range,units-per-em,values,version,' + + 'viewBox,visibility,width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,' + + 'xlink:show,xlink:title,xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,' + + 'zoomAndPan'); + +var validAttrs = angular.extend({}, + uriAttrs, + svgAttrs, + htmlAttrs); + +function makeMap(str) { + var obj = {}, items = str.split(','), i; + for (i = 0; i < items.length; i++) obj[items[i]] = true; + return obj; +} + + +/** + * @example + * htmlParser(htmlString, { + * start: function(tag, attrs, unary) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * }); + * + * @param {string} html string + * @param {object} handler + */ +function htmlParser(html, handler) { + if (typeof html !== 'string') { + if (html === null || typeof html === 'undefined') { + html = ''; + } else { + html = '' + html; + } + } + var index, chars, match, stack = [], last = html, text; + stack.last = function() { return stack[stack.length - 1]; }; + + while (html) { + text = ''; + chars = true; + + // Make sure we're not in a script or style element + if (!stack.last() || !specialElements[stack.last()]) { + + // Comment + if (html.indexOf("", index) === index) { + if (handler.comment) handler.comment(html.substring(4, index)); + html = html.substring(index + 3); + chars = false; + } + // DOCTYPE + } else if (DOCTYPE_REGEXP.test(html)) { + match = html.match(DOCTYPE_REGEXP); + + if (match) { + html = html.replace(match[0], ''); + chars = false; + } + // end tag + } else if (BEGING_END_TAGE_REGEXP.test(html)) { + match = html.match(END_TAG_REGEXP); + + if (match) { + html = html.substring(match[0].length); + match[0].replace(END_TAG_REGEXP, parseEndTag); + chars = false; + } + + // start tag + } else if (BEGIN_TAG_REGEXP.test(html)) { + match = html.match(START_TAG_REGEXP); + + if (match) { + // We only have a valid start-tag if there is a '>'. + if (match[4]) { + html = html.substring(match[0].length); + match[0].replace(START_TAG_REGEXP, parseStartTag); + } + chars = false; + } else { + // no ending tag found --- this piece should be encoded as an entity. + text += '<'; + html = html.substring(1); + } + } + + if (chars) { + index = html.indexOf("<"); + + text += index < 0 ? html : html.substring(0, index); + html = index < 0 ? "" : html.substring(index); + + if (handler.chars) handler.chars(decodeEntities(text)); + } + + } else { + // IE versions 9 and 10 do not understand the regex '[^]', so using a workaround with [\W\w]. + html = html.replace(new RegExp("([\\W\\w]*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'), + function(all, text) { + text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1"); + + if (handler.chars) handler.chars(decodeEntities(text)); + + return ""; + }); + + parseEndTag("", stack.last()); + } + + if (html == last) { + throw $sanitizeMinErr('badparse', "The sanitizer was unable to parse the following block " + + "of html: {0}", html); + } + last = html; + } + + // Clean up any remaining tags + parseEndTag(); + + function parseStartTag(tag, tagName, rest, unary) { + tagName = angular.lowercase(tagName); + if (blockElements[tagName]) { + while (stack.last() && inlineElements[stack.last()]) { + parseEndTag("", stack.last()); + } + } + + if (optionalEndTagElements[tagName] && stack.last() == tagName) { + parseEndTag("", tagName); + } + + unary = voidElements[tagName] || !!unary; + + if (!unary) + stack.push(tagName); + + var attrs = {}; + + rest.replace(ATTR_REGEXP, + function(match, name, doubleQuotedValue, singleQuotedValue, unquotedValue) { + var value = doubleQuotedValue + || singleQuotedValue + || unquotedValue + || ''; + + attrs[name] = decodeEntities(value); + }); + if (handler.start) handler.start(tagName, attrs, unary); + } + + function parseEndTag(tag, tagName) { + var pos = 0, i; + tagName = angular.lowercase(tagName); + if (tagName) + // Find the closest opened tag of the same type + for (pos = stack.length - 1; pos >= 0; pos--) + if (stack[pos] == tagName) + break; + + if (pos >= 0) { + // Close all the open elements, up the stack + for (i = stack.length - 1; i >= pos; i--) + if (handler.end) handler.end(stack[i]); + + // Remove the open elements from the stack + stack.length = pos; + } + } +} + +var hiddenPre=document.createElement("pre"); +var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/; +/** + * decodes all entities into regular string + * @param value + * @returns {string} A string with decoded entities. + */ +function decodeEntities(value) { + if (!value) { return ''; } + + // Note: IE8 does not preserve spaces at the start/end of innerHTML + // so we must capture them and reattach them afterward + var parts = spaceRe.exec(value); + var spaceBefore = parts[1]; + var spaceAfter = parts[3]; + var content = parts[2]; + if (content) { + hiddenPre.innerHTML=content.replace(//g, '>'); +} + +/** + * create an HTML/XML writer which writes to buffer + * @param {Array} buf use buf.jain('') to get out sanitized html string + * @returns {object} in the form of { + * start: function(tag, attrs, unary) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * } + */ +function htmlSanitizeWriter(buf, uriValidator) { + var ignore = false; + var out = angular.bind(buf, buf.push); + return { + start: function(tag, attrs, unary) { + tag = angular.lowercase(tag); + if (!ignore && specialElements[tag]) { + ignore = tag; + } + if (!ignore && validElements[tag] === true) { + out('<'); + out(tag); + angular.forEach(attrs, function(value, key) { + var lkey=angular.lowercase(key); + var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background'); + if (validAttrs[lkey] === true && + (uriAttrs[lkey] !== true || uriValidator(value, isImage))) { + out(' '); + out(key); + out('="'); + out(encodeEntities(value)); + out('"'); + } + }); + out(unary ? '/>' : '>'); + } + }, + end: function(tag) { + tag = angular.lowercase(tag); + if (!ignore && validElements[tag] === true) { + out(''); + } + if (tag == ignore) { + ignore = false; + } + }, + chars: function(chars) { + if (!ignore) { + out(encodeEntities(chars)); + } + } + }; +} + + +// define ngSanitize module and register $sanitize service +angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider); + +/* global sanitizeText: false */ + +/** + * @ngdoc filter + * @name linky + * @kind function + * + * @description + * Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and + * plain email address links. + * + * Requires the {@link ngSanitize `ngSanitize`} module to be installed. + * + * @param {string} text Input text. + * @param {string} target Window (_blank|_self|_parent|_top) or named frame to open links in. + * @returns {string} Html-linkified text. + * + * @usage + + * + * @example + + + +
    + Snippet: + + + + + + + + + + + + + + + + + + + + + +
    FilterSourceRendered
    linky filter +
    <div ng-bind-html="snippet | linky">
    </div>
    +
    +
    +
    linky target +
    <div ng-bind-html="snippetWithTarget | linky:'_blank'">
    </div>
    +
    +
    +
    no filter
    <div ng-bind="snippet">
    </div>
    + + + it('should linkify the snippet with urls', function() { + expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). + toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' + + 'another@somewhere.org, and one more: ftp://127.0.0.1/.'); + expect(element.all(by.css('#linky-filter a')).count()).toEqual(4); + }); + + it('should not linkify snippet without the linky filter', function() { + expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()). + toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' + + 'another@somewhere.org, and one more: ftp://127.0.0.1/.'); + expect(element.all(by.css('#escaped-html a')).count()).toEqual(0); + }); + + it('should update', function() { + element(by.model('snippet')).clear(); + element(by.model('snippet')).sendKeys('new http://link.'); + expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). + toBe('new http://link.'); + expect(element.all(by.css('#linky-filter a')).count()).toEqual(1); + expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()) + .toBe('new http://link.'); + }); + + it('should work with the target property', function() { + expect(element(by.id('linky-target')). + element(by.binding("snippetWithTarget | linky:'_blank'")).getText()). + toBe('http://angularjs.org/'); + expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank'); + }); + + + */ +angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) { + var LINKY_URL_REGEXP = + /((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"”’]/, + MAILTO_REGEXP = /^mailto:/; + + return function(text, target) { + if (!text) return text; + var match; + var raw = text; + var html = []; + var url; + var i; + while ((match = raw.match(LINKY_URL_REGEXP))) { + // We can not end in these as they are sometimes found at the end of the sentence + url = match[0]; + // if we did not match ftp/http/www/mailto then assume mailto + if (!match[2] && !match[4]) { + url = (match[3] ? 'http://' : 'mailto:') + url; + } + i = match.index; + addText(raw.substr(0, i)); + addLink(url, match[0].replace(MAILTO_REGEXP, '')); + raw = raw.substring(i + match[0].length); + } + addText(raw); + return $sanitize(html.join('')); + + function addText(text) { + if (!text) { + return; + } + html.push(sanitizeText(text)); + } + + function addLink(url, text) { + html.push(''); + addText(text); + html.push(''); + } + }; +}]); + + +})(window, window.angular); diff --git a/snow-flowable/src/main/resources/static/libs/angular-sanitize_1.3.13/angular-sanitize.min.js b/snow-flowable/src/main/resources/static/libs/angular-sanitize_1.3.13/angular-sanitize.min.js new file mode 100644 index 0000000..e6c2b1e --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-sanitize_1.3.13/angular-sanitize.min.js @@ -0,0 +1,16 @@ +/* + AngularJS v1.3.13 + (c) 2010-2014 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(n,h,p){'use strict';function E(a){var d=[];s(d,h.noop).chars(a);return d.join("")}function g(a){var d={};a=a.split(",");var c;for(c=0;c=c;e--)d.end&&d.end(f[e]);f.length=c}}"string"!==typeof a&&(a=null===a||"undefined"===typeof a?"":""+a);var b,k,f=[],m=a,l;for(f.last=function(){return f[f.length-1]};a;){l="";k=!0;if(f.last()&&x[f.last()])a=a.replace(new RegExp("([\\W\\w]*)<\\s*\\/\\s*"+f.last()+"[^>]*>","i"),function(a,b){b=b.replace(H,"$1").replace(I,"$1");d.chars&&d.chars(r(b));return""}),e("",f.last());else{if(0===a.indexOf("\x3c!--"))b=a.indexOf("--",4),0<=b&&a.lastIndexOf("--\x3e",b)===b&&(d.comment&& +d.comment(a.substring(4,b)),a=a.substring(b+3),k=!1);else if(y.test(a)){if(b=a.match(y))a=a.replace(b[0],""),k=!1}else if(J.test(a)){if(b=a.match(z))a=a.substring(b[0].length),b[0].replace(z,e),k=!1}else K.test(a)&&((b=a.match(A))?(b[4]&&(a=a.substring(b[0].length),b[0].replace(A,c)),k=!1):(l+="<",a=a.substring(1)));k&&(b=a.indexOf("<"),l+=0>b?a:a.substring(0,b),a=0>b?"":a.substring(b),d.chars&&d.chars(r(l)))}if(a==m)throw L("badparse",a);m=a}e()}function r(a){if(!a)return"";var d=M.exec(a);a=d[1]; +var c=d[3];if(d=d[2])q.innerHTML=d.replace(//g,">")}function s(a,d){var c=!1,e=h.bind(a,a.push);return{start:function(a,k,f){a=h.lowercase(a);!c&&x[a]&&(c=a);c||!0!==C[a]||(e("<"),e(a), +h.forEach(k,function(c,f){var k=h.lowercase(f),g="img"===a&&"src"===k||"background"===k;!0!==P[k]||!0===D[k]&&!d(c,g)||(e(" "),e(f),e('="'),e(B(c)),e('"'))}),e(f?"/>":">"))},end:function(a){a=h.lowercase(a);c||!0!==C[a]||(e(""));a==c&&(c=!1)},chars:function(a){c||e(B(a))}}}var L=h.$$minErr("$sanitize"),A=/^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/,z=/^<\/\s*([\w:-]+)[^>]*>/,G=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g, +K=/^]*?)>/i,I=/"\u201d\u2019]/,c=/^mailto:/;return function(e,b){function k(a){a&&g.push(E(a))} +function f(a,c){g.push("');k(c);g.push("")}if(!e)return e;for(var m,l=e,g=[],n,p;m=l.match(d);)n=m[0],m[2]||m[4]||(n=(m[3]?"http://":"mailto:")+n),p=m.index,k(l.substr(0,p)),f(n,m[0].replace(c,"")),l=l.substring(p+m[0].length);k(l);return a(g.join(""))}}])})(window,window.angular); +//# sourceMappingURL=angular-sanitize.min.js.map diff --git a/snow-flowable/src/main/resources/static/libs/angular-sanitize_1.3.13/angular-sanitize.min.js.map b/snow-flowable/src/main/resources/static/libs/angular-sanitize_1.3.13/angular-sanitize.min.js.map new file mode 100644 index 0000000..66bf00a --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-sanitize_1.3.13/angular-sanitize.min.js.map @@ -0,0 +1,8 @@ +{ +"version":3, +"file":"angular-sanitize.min.js", +"lineCount":15, +"mappings":"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", +"sources":["angular-sanitize.js"], +"names":["window","angular","undefined","sanitizeText","chars","buf","htmlSanitizeWriter","writer","noop","join","makeMap","str","obj","items","split","i","length","htmlParser","html","handler","parseStartTag","tag","tagName","rest","unary","lowercase","blockElements","stack","last","inlineElements","parseEndTag","optionalEndTagElements","voidElements","push","attrs","replace","ATTR_REGEXP","match","name","doubleQuotedValue","singleQuotedValue","unquotedValue","decodeEntities","start","pos","end","index","text","stack.last","specialElements","RegExp","all","COMMENT_REGEXP","CDATA_REGEXP","indexOf","lastIndexOf","comment","substring","DOCTYPE_REGEXP","test","BEGING_END_TAGE_REGEXP","END_TAG_REGEXP","BEGIN_TAG_REGEXP","START_TAG_REGEXP","$sanitizeMinErr","value","parts","spaceRe","exec","spaceBefore","spaceAfter","content","hiddenPre","innerHTML","textContent","innerText","encodeEntities","SURROGATE_PAIR_REGEXP","hi","charCodeAt","low","NON_ALPHANUMERIC_REGEXP","uriValidator","ignore","out","bind","validElements","forEach","key","lkey","isImage","validAttrs","uriAttrs","$$minErr","optionalEndTagBlockElements","optionalEndTagInlineElements","extend","svgElements","htmlAttrs","svgAttrs","document","createElement","module","provider","$SanitizeProvider","$get","$$sanitizeUri","uri","filter","$sanitize","LINKY_URL_REGEXP","MAILTO_REGEXP","target","addText","addLink","url","isDefined","raw","substr"] +} diff --git a/snow-flowable/src/main/resources/static/libs/angular-scroll_0.5.7/angular-scroll.min.js b/snow-flowable/src/main/resources/static/libs/angular-scroll_0.5.7/angular-scroll.min.js new file mode 100644 index 0000000..d979dfe --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-scroll_0.5.7/angular-scroll.min.js @@ -0,0 +1 @@ +var duScrollDefaultEasing=function(e){return.5>e?Math.pow(2*e,2)/2:1-Math.pow(2*(1-e),2)/2};angular.module("duScroll",["duScroll.scrollspy","duScroll.requestAnimation","duScroll.smoothScroll","duScroll.scrollContainer","duScroll.scrollHelpers"]).value("duScrollDuration",350).value("duScrollGreedy",!1).value("duScrollEasing",duScrollDefaultEasing),angular.module("duScroll.scrollHelpers",[]).run(["$window","$q","cancelAnimation","requestAnimation","duScrollEasing",function(e,t,n,r,o){var l=angular.element.prototype;this.$get=function(){return l};var i=function(e){return"undefined"!=typeof HTMLDocument&&e instanceof HTMLDocument||e.nodeType&&e.nodeType===e.DOCUMENT_NODE},u=function(e){return"undefined"!=typeof HTMLElement&&e instanceof HTMLElement||e.nodeType&&e.nodeType===e.ELEMENT_NODE},c=function(e){return u(e)||i(e)?e:e[0]};l.scrollTo=function(t,n,r){var o;if(angular.isElement(t)?o=this.scrollToElement:r&&(o=this.scrollToAnimated),o)return o.apply(this,arguments);var l=c(this);return i(l)?e.scrollTo(t,n):(l.scrollLeft=t,void(l.scrollTop=n))};var a,s;l.scrollToAnimated=function(e,l,i,u){i&&!u&&(u=o);var c=this.scrollLeft(),d=this.scrollTop(),f=Math.round(e-c),p=Math.round(l-d),m=null;a&&(n(a),s.reject());var g=this;if(s=t.defer(),!f&&!p)return s.resolve(),s.promise;var v=function(e){null===m&&(m=e);var t=e-m,n=t>=i?1:u(t/i);g.scrollTo(c+Math.ceil(f*n),d+Math.ceil(p*n)),1>n?a=r(v):(a=null,s.resolve())};return g.scrollTo(c,d),a=r(v),s.promise},l.scrollToElement=function(e,t,n,r){var o=c(this),l=this.scrollTop()+c(e).getBoundingClientRect().top-t;return u(o)&&(l-=o.getBoundingClientRect().top),this.scrollTo(0,l,n,r)};var d={scrollLeft:function(t,n,r){if(angular.isNumber(t))return this.scrollTo(t,this.scrollTop(),n,r);var o=c(this);return i(o)?e.scrollX||document.documentElement.scrollLeft||document.body.scrollLeft:o.scrollLeft},scrollTop:function(t,n,r){if(angular.isNumber(t))return this.scrollTo(this.scrollTop(),t,n,r);var o=c(this);return i(o)?e.scrollY||document.documentElement.scrollTop||document.body.scrollTop:o.scrollTop}},f=function(e,t){return function(n,r){return r?t.apply(this,arguments):e.apply(this,arguments)}};for(var p in d)l[p]=l[p]?f(l[p],d[p]):d[p]}]),angular.module("duScroll.polyfill",[]).factory("polyfill",["$window",function(e){var t=["webkit","moz","o","ms"];return function(n,r){if(e[n])return e[n];for(var o,l=n.substr(0,1).toUpperCase()+n.substr(1),i=0;i',link:function(b,c,d,e){function f(b){var c=h;b?c=b.toString():a.isUndefined(h)&&(c=b),e.$setViewValue(c)}var g=c.find("input"),h=b.$eval(d.fallbackValue),i=function(a){b.$apply(function(){f(a)})},j=function(){return g.spectrum("toggle"),!1},k=a.extend({color:e.$viewValue,change:i,move:i,hide:i},b.$eval(d.options));d.triggerId&&a.element(document.body).on("click","#"+d.triggerId,j),e.$render=function(){g.spectrum("set",e.$viewValue||"")},k.color&&(g.spectrum("set",k.color||""),f(k.color)),g.spectrum(k),b.$on("$destroy",function(){g.spectrum("destroy")})}}})}(angular); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/libs/angular-spectrum-colorpicker_1.0.13/spectrum.css b/snow-flowable/src/main/resources/static/libs/angular-spectrum-colorpicker_1.0.13/spectrum.css new file mode 100644 index 0000000..6a83b72 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-spectrum-colorpicker_1.0.13/spectrum.css @@ -0,0 +1,519 @@ +/*** +Spectrum Colorpicker v1.3.4 +https://github.com/bgrins/spectrum +Author: Brian Grinstead +License: MIT +***/ + +.sp-container { + position:absolute; + top:0; + left:0; + display:inline-block; + *display: inline; + *zoom: 1; + /* https://github.com/bgrins/spectrum/issues/40 */ + z-index: 9999994; + overflow: hidden; +} +.sp-container.sp-flat { + position: relative; +} + +/* Fix for * { box-sizing: border-box; } */ +.sp-container, +.sp-container * { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +/* http://ansciath.tumblr.com/post/7347495869/css-aspect-ratio */ +.sp-top { + position:relative; + width: 100%; + display:inline-block; +} +.sp-top-inner { + position:absolute; + top:0; + left:0; + bottom:0; + right:0; +} +.sp-color { + position: absolute; + top:0; + left:0; + bottom:0; + right:20%; +} +.sp-hue { + position: absolute; + top:0; + right:0; + bottom:0; + left:84%; + height: 100%; +} + +.sp-clear-enabled .sp-hue { + top:33px; + height: 77.5%; +} + +.sp-fill { + padding-top: 80%; +} +.sp-sat, .sp-val { + position: absolute; + top:0; + left:0; + right:0; + bottom:0; +} + +.sp-alpha-enabled .sp-top { + margin-bottom: 18px; +} +.sp-alpha-enabled .sp-alpha { + display: block; +} +.sp-alpha-handle { + position:absolute; + top:-4px; + bottom: -4px; + width: 6px; + left: 50%; + cursor: pointer; + border: 1px solid black; + background: white; + opacity: .8; +} +.sp-alpha { + display: none; + position: absolute; + bottom: -14px; + right: 0; + left: 0; + height: 8px; +} +.sp-alpha-inner { + border: solid 1px #333; +} + +.sp-clear { + display: none; +} + +.sp-clear.sp-clear-display { + background-position: center; +} + +.sp-clear-enabled .sp-clear { + display: block; + position:absolute; + top:0px; + right:0; + bottom:0; + left:84%; + height: 28px; +} + +/* Don't allow text selection */ +.sp-container, .sp-replacer, .sp-preview, .sp-dragger, .sp-slider, .sp-alpha, .sp-clear, .sp-alpha-handle, .sp-container.sp-dragging .sp-input, .sp-container button { + -webkit-user-select:none; + -moz-user-select: -moz-none; + -o-user-select:none; + user-select: none; +} + +.sp-container.sp-input-disabled .sp-input-container { + display: none; +} +.sp-container.sp-buttons-disabled .sp-button-container { + display: none; +} +.sp-palette-only .sp-picker-container { + display: none; +} +.sp-palette-disabled .sp-palette-container { + display: none; +} + +.sp-initial-disabled .sp-initial { + display: none; +} + + +/* Gradients for hue, saturation and value instead of images. Not pretty... but it works */ +.sp-sat { + background-image: -webkit-gradient(linear, 0 0, 100% 0, from(#FFF), to(rgba(204, 154, 129, 0))); + background-image: -webkit-linear-gradient(left, #FFF, rgba(204, 154, 129, 0)); + background-image: -moz-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); + background-image: -o-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); + background-image: -ms-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); + background-image: linear-gradient(to right, #fff, rgba(204, 154, 129, 0)); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr=#FFFFFFFF, endColorstr=#00CC9A81)"; + filter : progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr='#FFFFFFFF', endColorstr='#00CC9A81'); +} +.sp-val { + background-image: -webkit-gradient(linear, 0 100%, 0 0, from(#000000), to(rgba(204, 154, 129, 0))); + background-image: -webkit-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0)); + background-image: -moz-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); + background-image: -o-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); + background-image: -ms-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); + background-image: linear-gradient(to top, #000, rgba(204, 154, 129, 0)); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00CC9A81, endColorstr=#FF000000)"; + filter : progid:DXImageTransform.Microsoft.gradient(startColorstr='#00CC9A81', endColorstr='#FF000000'); +} + +.sp-hue { + background: -moz-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); + background: -ms-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); + background: -o-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); + background: -webkit-gradient(linear, left top, left bottom, from(#ff0000), color-stop(0.17, #ffff00), color-stop(0.33, #00ff00), color-stop(0.5, #00ffff), color-stop(0.67, #0000ff), color-stop(0.83, #ff00ff), to(#ff0000)); + background: -webkit-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); +} + +/* IE filters do not support multiple color stops. + Generate 6 divs, line them up, and do two color gradients for each. + Yes, really. + */ +.sp-1 { + height:17%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0000', endColorstr='#ffff00'); +} +.sp-2 { + height:16%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff00', endColorstr='#00ff00'); +} +.sp-3 { + height:17%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ff00', endColorstr='#00ffff'); +} +.sp-4 { + height:17%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ffff', endColorstr='#0000ff'); +} +.sp-5 { + height:16%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0000ff', endColorstr='#ff00ff'); +} +.sp-6 { + height:17%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff00ff', endColorstr='#ff0000'); +} + +.sp-hidden { + display: none !important; +} + +/* Clearfix hack */ +.sp-cf:before, .sp-cf:after { content: ""; display: table; } +.sp-cf:after { clear: both; } +.sp-cf { *zoom: 1; } + +/* Mobile devices, make hue slider bigger so it is easier to slide */ +@media (max-device-width: 480px) { + .sp-color { right: 40%; } + .sp-hue { left: 63%; } + .sp-fill { padding-top: 60%; } +} +.sp-dragger { + border-radius: 5px; + height: 5px; + width: 5px; + border: 1px solid #fff; + background: #000; + cursor: pointer; + position:absolute; + top:0; + left: 0; +} +.sp-slider { + position: absolute; + top:0; + cursor:pointer; + height: 3px; + left: -1px; + right: -1px; + border: 1px solid #000; + background: white; + opacity: .8; +} + +/* +Theme authors: +Here are the basic themeable display options (colors, fonts, global widths). +See http://bgrins.github.io/spectrum/themes/ for instructions. +*/ + +.sp-container { + border-radius: 0; + background-color: #ECECEC; + border: solid 1px #f0c49B; + padding: 0; +} +.sp-container, .sp-container button, .sp-container input, .sp-color, .sp-hue, .sp-clear +{ + font: normal 12px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; +} +.sp-top +{ + margin-bottom: 3px; +} +.sp-color, .sp-hue, .sp-clear +{ + border: solid 1px #666; +} + +/* Input */ +.sp-input-container { + float:right; + width: 100px; + margin-bottom: 4px; +} +.sp-initial-disabled .sp-input-container { + width: 100%; +} +.sp-input { + font-size: 12px !important; + border: 1px inset; + padding: 4px 5px; + margin: 0; + width: 100%; + background:transparent; + border-radius: 3px; + color: #222; +} +.sp-input:focus { + border: 1px solid orange; +} +.sp-input.sp-validation-error +{ + border: 1px solid red; + background: #fdd; +} +.sp-picker-container , .sp-palette-container +{ + float:left; + position: relative; + padding: 10px; + padding-bottom: 300px; + margin-bottom: -290px; +} +.sp-picker-container +{ + width: 172px; + border-left: solid 1px #fff; +} + +/* Palettes */ +.sp-palette-container +{ + border-right: solid 1px #ccc; +} + +.sp-palette .sp-thumb-el { + display: block; + position:relative; + float:left; + width: 24px; + height: 15px; + margin: 3px; + cursor: pointer; + border:solid 2px transparent; +} +.sp-palette .sp-thumb-el:hover, .sp-palette .sp-thumb-el.sp-thumb-active { + border-color: orange; +} +.sp-thumb-el +{ + position:relative; +} + +/* Initial */ +.sp-initial +{ + float: left; + border: solid 1px #333; +} +.sp-initial span { + width: 30px; + height: 25px; + border:none; + display:block; + float:left; + margin:0; +} + +.sp-initial .sp-clear-display { + background-position: center; +} + +/* Buttons */ +.sp-button-container { + float: right; +} + +/* Replacer (the little preview div that shows up instead of the ) */ +.sp-replacer { + margin:0; + overflow:hidden; + cursor:pointer; + padding: 4px; + display:inline-block; + *zoom: 1; + *display: inline; + border: solid 1px #91765d; + background: #eee; + color: #333; + vertical-align: middle; +} +.sp-replacer:hover, .sp-replacer.sp-active { + border-color: #F0C49B; + color: #111; +} +.sp-replacer.sp-disabled { + cursor:default; + border-color: silver; + color: silver; +} +.sp-dd { + padding: 2px 0; + height: 16px; + line-height: 16px; + float:left; + font-size:10px; +} +.sp-preview +{ + position:relative; + width:25px; + height: 20px; + border: solid 1px #222; + margin-right: 5px; + float:left; + z-index: 0; +} + +.sp-palette +{ + *width: 220px; + max-width: 220px; +} +.sp-palette .sp-thumb-el +{ + width:16px; + height: 16px; + margin:2px 1px; + border: solid 1px #d0d0d0; +} + +.sp-container +{ + padding-bottom:0; +} + + +/* Buttons: http://hellohappy.org/css3-buttons/ */ +.sp-container button { + background-color: #eeeeee; + background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc); + background-image: -moz-linear-gradient(top, #eeeeee, #cccccc); + background-image: -ms-linear-gradient(top, #eeeeee, #cccccc); + background-image: -o-linear-gradient(top, #eeeeee, #cccccc); + background-image: linear-gradient(to bottom, #eeeeee, #cccccc); + border: 1px solid #ccc; + border-bottom: 1px solid #bbb; + border-radius: 3px; + color: #333; + font-size: 14px; + line-height: 1; + padding: 5px 4px; + text-align: center; + text-shadow: 0 1px 0 #eee; + vertical-align: middle; +} +.sp-container button:hover { + background-color: #dddddd; + background-image: -webkit-linear-gradient(top, #dddddd, #bbbbbb); + background-image: -moz-linear-gradient(top, #dddddd, #bbbbbb); + background-image: -ms-linear-gradient(top, #dddddd, #bbbbbb); + background-image: -o-linear-gradient(top, #dddddd, #bbbbbb); + background-image: linear-gradient(to bottom, #dddddd, #bbbbbb); + border: 1px solid #bbb; + border-bottom: 1px solid #999; + cursor: pointer; + text-shadow: 0 1px 0 #ddd; +} +.sp-container button:active { + border: 1px solid #aaa; + border-bottom: 1px solid #888; + -webkit-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; + -moz-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; + -ms-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; + -o-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; + box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; +} +.sp-cancel +{ + font-size: 11px; + color: #d93f3f !important; + margin:0; + padding:2px; + margin-right: 5px; + vertical-align: middle; + text-decoration:none; + +} +.sp-cancel:hover +{ + color: #d93f3f !important; + text-decoration: underline; +} + + +.sp-palette span:hover, .sp-palette span.sp-thumb-active +{ + border-color: #000; +} + +.sp-preview, .sp-alpha, .sp-thumb-el +{ + position:relative; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); +} +.sp-preview-inner, .sp-alpha-inner, .sp-thumb-inner +{ + display:block; + position:absolute; + top:0;left:0;bottom:0;right:0; +} + +.sp-palette .sp-thumb-inner +{ + background-position: 50% 50%; + background-repeat: no-repeat; +} + +.sp-palette .sp-thumb-light.sp-thumb-active .sp-thumb-inner +{ + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIVJREFUeNpiYBhsgJFMffxAXABlN5JruT4Q3wfi/0DsT64h8UD8HmpIPCWG/KemIfOJCUB+Aoacx6EGBZyHBqI+WsDCwuQ9mhxeg2A210Ntfo8klk9sOMijaURm7yc1UP2RNCMbKE9ODK1HM6iegYLkfx8pligC9lCD7KmRof0ZhjQACDAAceovrtpVBRkAAAAASUVORK5CYII=); +} + +.sp-palette .sp-thumb-dark.sp-thumb-active .sp-thumb-inner +{ + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAMdJREFUOE+tkgsNwzAMRMugEAahEAahEAZhEAqlEAZhEAohEAYh81X2dIm8fKpEspLGvudPOsUYpxE2BIJCroJmEW9qJ+MKaBFhEMNabSy9oIcIPwrB+afvAUFoK4H0tMaQ3XtlrggDhOVVMuT4E5MMG0FBbCEYzjYT7OxLEvIHQLY2zWwQ3D+9luyOQTfKDiFD3iUIfPk8VqrKjgAiSfGFPecrg6HN6m/iBcwiDAo7WiBeawa+Kwh7tZoSCGLMqwlSAzVDhoK+6vH4G0P5wdkAAAAASUVORK5CYII=); +} + +.sp-clear-display { + background-repeat:no-repeat; + background-position: center; + background-image: url(data:image/gif;base64,R0lGODlhFAAUAPcAAAAAAJmZmZ2dnZ6enqKioqOjo6SkpKWlpaampqenp6ioqKmpqaqqqqurq/Hx8fLy8vT09PX19ff39/j4+Pn5+fr6+vv7+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAP8ALAAAAAAUABQAAAihAP9FoPCvoMGDBy08+EdhQAIJCCMybCDAAYUEARBAlFiQQoMABQhKUJBxY0SPICEYHBnggEmDKAuoPMjS5cGYMxHW3IiT478JJA8M/CjTZ0GgLRekNGpwAsYABHIypcAgQMsITDtWJYBR6NSqMico9cqR6tKfY7GeBCuVwlipDNmefAtTrkSzB1RaIAoXodsABiZAEFB06gIBWC1mLVgBa0AAOw==); +} diff --git a/snow-flowable/src/main/resources/static/libs/angular-spectrum-colorpicker_1.0.13/spectrum.js b/snow-flowable/src/main/resources/static/libs/angular-spectrum-colorpicker_1.0.13/spectrum.js new file mode 100644 index 0000000..8ced40a --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-spectrum-colorpicker_1.0.13/spectrum.js @@ -0,0 +1,2080 @@ +// Spectrum Colorpicker v1.3.4 +// https://github.com/bgrins/spectrum +// Author: Brian Grinstead +// License: MIT + +(function (window, $, undefined) { + var defaultOpts = { + + // Callbacks + beforeShow: noop, + move: noop, + change: noop, + show: noop, + hide: noop, + + // Options + color: false, + flat: false, + showInput: false, + allowEmpty: false, + showButtons: true, + clickoutFiresChange: false, + showInitial: false, + showPalette: false, + showPaletteOnly: false, + showSelectionPalette: true, + localStorageKey: false, + appendTo: "body", + maxSelectionSize: 7, + cancelText: "cancel", + chooseText: "choose", + clearText: "Clear Color Selection", + preferredFormat: false, + className: "", // Deprecated - use containerClassName and replacerClassName instead. + containerClassName: "", + replacerClassName: "", + showAlpha: false, + theme: "sp-light", + palette: [["#ffffff", "#000000", "#ff0000", "#ff8000", "#ffff00", "#008000", "#0000ff", "#4b0082", "#9400d3"]], + selectionPalette: [], + disabled: false + }, + spectrums = [], + IE = !!/msie/i.exec( window.navigator.userAgent ), + rgbaSupport = (function() { + function contains( str, substr ) { + return !!~('' + str).indexOf(substr); + } + + var elem = document.createElement('div'); + var style = elem.style; + style.cssText = 'background-color:rgba(0,0,0,.5)'; + return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla'); + })(), + inputTypeColorSupport = (function() { + var colorInput = $("")[0]; + return colorInput.type === "color" && colorInput.value !== "!"; + })(), + replaceInput = [ + "
    ", + "
    ", + "
    ", + "
    " + ].join(''), + markup = (function () { + + // IE does not support gradients with multiple stops, so we need to simulate + // that for the rainbow slider with 8 divs that each have a single gradient + var gradientFix = ""; + if (IE) { + for (var i = 1; i <= 6; i++) { + gradientFix += "
    "; + } + } + + return [ + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + gradientFix, + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "", + "
    ", + "
    ", + "
    ", + "", + "", + "
    ", + "
    ", + "
    " + ].join(""); + })(); + + function paletteTemplate (p, color, className, tooltipFormat) { + var html = []; + for (var i = 0; i < p.length; i++) { + var current = p[i]; + if(current) { + var tiny = tinycolor(current); + var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light"; + c += (tinycolor.equals(color, current)) ? " sp-thumb-active" : ""; + + var formattedString = tiny.toString(tooltipFormat || "rgb"); + var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter(); + html.push(''); + } else { + var cls = 'sp-clear-display'; + html.push(''); + } + } + return "
    " + html.join('') + "
    "; + } + + function hideAll() { + for (var i = 0; i < spectrums.length; i++) { + if (spectrums[i]) { + spectrums[i].hide(); + } + } + } + + function instanceOptions(o, callbackContext) { + var opts = $.extend({}, defaultOpts, o); + opts.callbacks = { + 'move': bind(opts.move, callbackContext), + 'change': bind(opts.change, callbackContext), + 'show': bind(opts.show, callbackContext), + 'hide': bind(opts.hide, callbackContext), + 'beforeShow': bind(opts.beforeShow, callbackContext) + }; + + return opts; + } + + function spectrum(element, o) { + + var opts = instanceOptions(o, element), + flat = opts.flat, + showSelectionPalette = opts.showSelectionPalette, + localStorageKey = opts.localStorageKey, + theme = opts.theme, + callbacks = opts.callbacks, + resize = throttle(reflow, 10), + visible = false, + dragWidth = 0, + dragHeight = 0, + dragHelperHeight = 0, + slideHeight = 0, + slideWidth = 0, + alphaWidth = 0, + alphaSlideHelperWidth = 0, + slideHelperHeight = 0, + currentHue = 0, + currentSaturation = 0, + currentValue = 0, + currentAlpha = 1, + palette = [], + paletteArray = [], + paletteLookup = {}, + selectionPalette = opts.selectionPalette.slice(0), + maxSelectionSize = opts.maxSelectionSize, + draggingClass = "sp-dragging", + shiftMovementDirection = null; + + var doc = element.ownerDocument, + body = doc.body, + boundElement = $(element), + disabled = false, + container = $(markup, doc).addClass(theme), + dragger = container.find(".sp-color"), + dragHelper = container.find(".sp-dragger"), + slider = container.find(".sp-hue"), + slideHelper = container.find(".sp-slider"), + alphaSliderInner = container.find(".sp-alpha-inner"), + alphaSlider = container.find(".sp-alpha"), + alphaSlideHelper = container.find(".sp-alpha-handle"), + textInput = container.find(".sp-input"), + paletteContainer = container.find(".sp-palette"), + initialColorContainer = container.find(".sp-initial"), + cancelButton = container.find(".sp-cancel"), + clearButton = container.find(".sp-clear"), + chooseButton = container.find(".sp-choose"), + isInput = boundElement.is("input"), + isInputTypeColor = isInput && inputTypeColorSupport && boundElement.attr("type") === "color", + shouldReplace = isInput && !flat, + replacer = (shouldReplace) ? $(replaceInput).addClass(theme).addClass(opts.className).addClass(opts.replacerClassName) : $([]), + offsetElement = (shouldReplace) ? replacer : boundElement, + previewElement = replacer.find(".sp-preview-inner"), + initialColor = opts.color || (isInput && boundElement.val()), + colorOnShow = false, + preferredFormat = opts.preferredFormat, + currentPreferredFormat = preferredFormat, + clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange, + isEmpty = !initialColor, + allowEmpty = opts.allowEmpty && !isInputTypeColor; + + function applyOptions() { + + if (opts.showPaletteOnly) { + opts.showPalette = true; + } + + if (opts.palette) { + palette = opts.palette.slice(0); + paletteArray = $.isArray(palette[0]) ? palette : [palette]; + paletteLookup = {}; + for (var i = 0; i < paletteArray.length; i++) { + for (var j = 0; j < paletteArray[i].length; j++) { + var rgb = tinycolor(paletteArray[i][j]).toRgbString(); + paletteLookup[rgb] = true; + } + } + } + + container.toggleClass("sp-flat", flat); + container.toggleClass("sp-input-disabled", !opts.showInput); + container.toggleClass("sp-alpha-enabled", opts.showAlpha); + container.toggleClass("sp-clear-enabled", allowEmpty); + container.toggleClass("sp-buttons-disabled", !opts.showButtons); + container.toggleClass("sp-palette-disabled", !opts.showPalette); + container.toggleClass("sp-palette-only", opts.showPaletteOnly); + container.toggleClass("sp-initial-disabled", !opts.showInitial); + container.addClass(opts.className).addClass(opts.containerClassName); + + reflow(); + } + + function initialize() { + + if (IE) { + container.find("*:not(input)").attr("unselectable", "on"); + } + + applyOptions(); + + if (shouldReplace) { + boundElement.after(replacer).hide(); + } + + if (!allowEmpty) { + clearButton.hide(); + } + + if (flat) { + boundElement.after(container).hide(); + } + else { + + var appendTo = opts.appendTo === "parent" ? boundElement.parent() : $(opts.appendTo); + if (appendTo.length !== 1) { + appendTo = $("body"); + } + + appendTo.append(container); + } + + updateSelectionPaletteFromStorage(); + + offsetElement.bind("click.spectrum touchstart.spectrum", function (e) { + if (!disabled) { + toggle(); + } + + e.stopPropagation(); + + if (!$(e.target).is("input")) { + e.preventDefault(); + } + }); + + if(boundElement.is(":disabled") || (opts.disabled === true)) { + disable(); + } + + // Prevent clicks from bubbling up to document. This would cause it to be hidden. + container.click(stopPropagation); + + // Handle user typed input + textInput.change(setFromTextInput); + textInput.bind("paste", function () { + setTimeout(setFromTextInput, 1); + }); + textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } }); + + cancelButton.text(opts.cancelText); + cancelButton.bind("click.spectrum", function (e) { + e.stopPropagation(); + e.preventDefault(); + hide("cancel"); + }); + + clearButton.attr("title", opts.clearText); + clearButton.bind("click.spectrum", function (e) { + e.stopPropagation(); + e.preventDefault(); + isEmpty = true; + move(); + + if(flat) { + //for the flat style, this is a change event + updateOriginalInput(true); + } + }); + + chooseButton.text(opts.chooseText); + chooseButton.bind("click.spectrum", function (e) { + e.stopPropagation(); + e.preventDefault(); + + if (isValid()) { + updateOriginalInput(true); + hide(); + } + }); + + draggable(alphaSlider, function (dragX, dragY, e) { + currentAlpha = (dragX / alphaWidth); + isEmpty = false; + if (e.shiftKey) { + currentAlpha = Math.round(currentAlpha * 10) / 10; + } + + move(); + }, dragStart, dragStop); + + draggable(slider, function (dragX, dragY) { + currentHue = parseFloat(dragY / slideHeight); + isEmpty = false; + if (!opts.showAlpha) { + currentAlpha = 1; + } + move(); + }, dragStart, dragStop); + + draggable(dragger, function (dragX, dragY, e) { + + // shift+drag should snap the movement to either the x or y axis. + if (!e.shiftKey) { + shiftMovementDirection = null; + } + else if (!shiftMovementDirection) { + var oldDragX = currentSaturation * dragWidth; + var oldDragY = dragHeight - (currentValue * dragHeight); + var furtherFromX = Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY); + + shiftMovementDirection = furtherFromX ? "x" : "y"; + } + + var setSaturation = !shiftMovementDirection || shiftMovementDirection === "x"; + var setValue = !shiftMovementDirection || shiftMovementDirection === "y"; + + if (setSaturation) { + currentSaturation = parseFloat(dragX / dragWidth); + } + if (setValue) { + currentValue = parseFloat((dragHeight - dragY) / dragHeight); + } + + isEmpty = false; + if (!opts.showAlpha) { + currentAlpha = 1; + } + + move(); + + }, dragStart, dragStop); + + if (!!initialColor) { + set(initialColor); + + // In case color was black - update the preview UI and set the format + // since the set function will not run (default color is black). + updateUI(); + currentPreferredFormat = preferredFormat || tinycolor(initialColor).format; + + addColorToSelectionPalette(initialColor); + } + else { + updateUI(); + } + + if (flat) { + show(); + } + + function palletElementClick(e) { + if (e.data && e.data.ignore) { + set($(this).data("color")); + move(); + } + else { + set($(this).data("color")); + move(); + updateOriginalInput(true); + hide(); + } + + return false; + } + + var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum"; + paletteContainer.delegate(".sp-thumb-el", paletteEvent, palletElementClick); + initialColorContainer.delegate(".sp-thumb-el:nth-child(1)", paletteEvent, { ignore: true }, palletElementClick); + } + + function updateSelectionPaletteFromStorage() { + + if (localStorageKey && window.localStorage) { + + // Migrate old palettes over to new format. May want to remove this eventually. + try { + var oldPalette = window.localStorage[localStorageKey].split(",#"); + if (oldPalette.length > 1) { + delete window.localStorage[localStorageKey]; + $.each(oldPalette, function(i, c) { + addColorToSelectionPalette(c); + }); + } + } + catch(e) { } + + try { + selectionPalette = window.localStorage[localStorageKey].split(";"); + } + catch (e) { } + } + } + + function addColorToSelectionPalette(color) { + if (showSelectionPalette) { + var rgb = tinycolor(color).toRgbString(); + if (!paletteLookup[rgb] && $.inArray(rgb, selectionPalette) === -1) { + selectionPalette.push(rgb); + while(selectionPalette.length > maxSelectionSize) { + selectionPalette.shift(); + } + } + + if (localStorageKey && window.localStorage) { + try { + window.localStorage[localStorageKey] = selectionPalette.join(";"); + } + catch(e) { } + } + } + } + + function getUniqueSelectionPalette() { + var unique = []; + if (opts.showPalette) { + for (i = 0; i < selectionPalette.length; i++) { + var rgb = tinycolor(selectionPalette[i]).toRgbString(); + + if (!paletteLookup[rgb]) { + unique.push(selectionPalette[i]); + } + } + } + + return unique.reverse().slice(0, opts.maxSelectionSize); + } + + function drawPalette() { + + var currentColor = get(); + + var html = $.map(paletteArray, function (palette, i) { + return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i, opts.preferredFormat); + }); + + updateSelectionPaletteFromStorage(); + + if (selectionPalette) { + html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection", opts.preferredFormat)); + } + + paletteContainer.html(html.join("")); + } + + function drawInitial() { + if (opts.showInitial) { + var initial = colorOnShow; + var current = get(); + initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial", opts.preferredFormat)); + } + } + + function dragStart() { + if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) { + reflow(); + } + container.addClass(draggingClass); + shiftMovementDirection = null; + boundElement.trigger('dragstart.spectrum', [ get() ]); + } + + function dragStop() { + container.removeClass(draggingClass); + boundElement.trigger('dragstop.spectrum', [ get() ]); + } + + function setFromTextInput() { + + var value = textInput.val(); + + if ((value === null || value === "") && allowEmpty) { + set(null); + updateOriginalInput(true); + } + else { + var tiny = tinycolor(value); + if (tiny.ok) { + set(tiny); + updateOriginalInput(true); + } + else { + textInput.addClass("sp-validation-error"); + } + } + } + + function toggle() { + if (visible) { + hide(); + } + else { + show(); + } + } + + function show() { + var event = $.Event('beforeShow.spectrum'); + + if (visible) { + reflow(); + return; + } + + boundElement.trigger(event, [ get() ]); + + if (callbacks.beforeShow(get()) === false || event.isDefaultPrevented()) { + return; + } + + hideAll(); + visible = true; + + $(doc).bind("click.spectrum", hide); + $(window).bind("resize.spectrum", resize); + replacer.addClass("sp-active"); + container.removeClass("sp-hidden"); + + reflow(); + updateUI(); + + colorOnShow = get(); + + drawInitial(); + callbacks.show(colorOnShow); + boundElement.trigger('show.spectrum', [ colorOnShow ]); + } + + function hide(e) { + + // Return on right click + if (e && e.type == "click" && e.button == 2) { return; } + + // Return if hiding is unnecessary + if (!visible || flat) { return; } + visible = false; + + $(doc).unbind("click.spectrum", hide); + $(window).unbind("resize.spectrum", resize); + + replacer.removeClass("sp-active"); + container.addClass("sp-hidden"); + + var colorHasChanged = !tinycolor.equals(get(), colorOnShow); + + if (colorHasChanged) { + if (clickoutFiresChange && e !== "cancel") { + updateOriginalInput(true); + } + else { + revert(); + } + } + + callbacks.hide(get()); + boundElement.trigger('hide.spectrum', [ get() ]); + } + + function revert() { + set(colorOnShow, true); + } + + function set(color, ignoreFormatChange) { + if (tinycolor.equals(color, get())) { + // Update UI just in case a validation error needs + // to be cleared. + updateUI(); + return; + } + + var newColor, newHsv; + if (!color && allowEmpty) { + isEmpty = true; + } else { + isEmpty = false; + newColor = tinycolor(color); + newHsv = newColor.toHsv(); + + currentHue = (newHsv.h % 360) / 360; + currentSaturation = newHsv.s; + currentValue = newHsv.v; + currentAlpha = newHsv.a; + } + updateUI(); + + if (newColor && newColor.ok && !ignoreFormatChange) { + currentPreferredFormat = preferredFormat || newColor.format; + } + } + + function get(opts) { + opts = opts || { }; + + if (allowEmpty && isEmpty) { + return null; + } + + return tinycolor.fromRatio({ + h: currentHue, + s: currentSaturation, + v: currentValue, + a: Math.round(currentAlpha * 100) / 100 + }, { format: opts.format || currentPreferredFormat }); + } + + function isValid() { + return !textInput.hasClass("sp-validation-error"); + } + + function move() { + updateUI(); + + callbacks.move(get()); + boundElement.trigger('move.spectrum', [ get() ]); + } + + function updateUI() { + + textInput.removeClass("sp-validation-error"); + + updateHelperLocations(); + + // Update dragger background color (gradients take care of saturation and value). + var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 }); + dragger.css("background-color", flatColor.toHexString()); + + // Get a format that alpha will be included in (hex and names ignore alpha) + var format = currentPreferredFormat; + if (currentAlpha < 1 && !(currentAlpha === 0 && format === "name")) { + if (format === "hex" || format === "hex3" || format === "hex6" || format === "name") { + format = "rgb"; + } + } + + var realColor = get({ format: format }), + displayColor = ''; + + //reset background info for preview element + previewElement.removeClass("sp-clear-display"); + previewElement.css('background-color', 'transparent'); + + if (!realColor && allowEmpty) { + // Update the replaced elements background with icon indicating no color selection + previewElement.addClass("sp-clear-display"); + } + else { + var realHex = realColor.toHexString(), + realRgb = realColor.toRgbString(); + + // Update the replaced elements background color (with actual selected color) + if (rgbaSupport || realColor.alpha === 1) { + previewElement.css("background-color", realRgb); + } + else { + previewElement.css("background-color", "transparent"); + previewElement.css("filter", realColor.toFilter()); + } + + if (opts.showAlpha) { + var rgb = realColor.toRgb(); + rgb.a = 0; + var realAlpha = tinycolor(rgb).toRgbString(); + var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")"; + + if (IE) { + alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex)); + } + else { + alphaSliderInner.css("background", "-webkit-" + gradient); + alphaSliderInner.css("background", "-moz-" + gradient); + alphaSliderInner.css("background", "-ms-" + gradient); + // Use current syntax gradient on unprefixed property. + alphaSliderInner.css("background", + "linear-gradient(to right, " + realAlpha + ", " + realHex + ")"); + } + } + + displayColor = realColor.toString(format); + } + + // Update the text entry input as it changes happen + if (opts.showInput) { + textInput.val(displayColor); + } + + if (opts.showPalette) { + drawPalette(); + } + + drawInitial(); + } + + function updateHelperLocations() { + var s = currentSaturation; + var v = currentValue; + + if(allowEmpty && isEmpty) { + //if selected color is empty, hide the helpers + alphaSlideHelper.hide(); + slideHelper.hide(); + dragHelper.hide(); + } + else { + //make sure helpers are visible + alphaSlideHelper.show(); + slideHelper.show(); + dragHelper.show(); + + // Where to show the little circle in that displays your current selected color + var dragX = s * dragWidth; + var dragY = dragHeight - (v * dragHeight); + dragX = Math.max( + -dragHelperHeight, + Math.min(dragWidth - dragHelperHeight, dragX - dragHelperHeight) + ); + dragY = Math.max( + -dragHelperHeight, + Math.min(dragHeight - dragHelperHeight, dragY - dragHelperHeight) + ); + dragHelper.css({ + "top": dragY + "px", + "left": dragX + "px" + }); + + var alphaX = currentAlpha * alphaWidth; + alphaSlideHelper.css({ + "left": (alphaX - (alphaSlideHelperWidth / 2)) + "px" + }); + + // Where to show the bar that displays your current selected hue + var slideY = (currentHue) * slideHeight; + slideHelper.css({ + "top": (slideY - slideHelperHeight) + "px" + }); + } + } + + function updateOriginalInput(fireCallback) { + var color = get(), + displayColor = '', + hasChanged = !tinycolor.equals(color, colorOnShow); + + if (color) { + displayColor = color.toString(currentPreferredFormat); + // Update the selection palette with the current color + addColorToSelectionPalette(color); + } + + if (isInput) { + boundElement.val(displayColor); + } + + colorOnShow = color; + + if (fireCallback && hasChanged) { + callbacks.change(color); + boundElement.trigger('change', [ color ]); + } + } + + function reflow() { + dragWidth = dragger.width(); + dragHeight = dragger.height(); + dragHelperHeight = dragHelper.height(); + slideWidth = slider.width(); + slideHeight = slider.height(); + slideHelperHeight = slideHelper.height(); + alphaWidth = alphaSlider.width(); + alphaSlideHelperWidth = alphaSlideHelper.width(); + + if (!flat) { + container.css("position", "absolute"); + container.offset(getOffset(container, offsetElement)); + } + + updateHelperLocations(); + + if (opts.showPalette) { + drawPalette(); + } + + boundElement.trigger('reflow.spectrum'); + } + + function destroy() { + boundElement.show(); + offsetElement.unbind("click.spectrum touchstart.spectrum"); + container.remove(); + replacer.remove(); + spectrums[spect.id] = null; + } + + function option(optionName, optionValue) { + if (optionName === undefined) { + return $.extend({}, opts); + } + if (optionValue === undefined) { + return opts[optionName]; + } + + opts[optionName] = optionValue; + applyOptions(); + } + + function enable() { + disabled = false; + boundElement.attr("disabled", false); + offsetElement.removeClass("sp-disabled"); + } + + function disable() { + hide(); + disabled = true; + boundElement.attr("disabled", true); + offsetElement.addClass("sp-disabled"); + } + + initialize(); + + var spect = { + show: show, + hide: hide, + toggle: toggle, + reflow: reflow, + option: option, + enable: enable, + disable: disable, + set: function (c) { + set(c); + updateOriginalInput(); + }, + get: get, + destroy: destroy, + container: container + }; + + spect.id = spectrums.push(spect) - 1; + + return spect; + } + + /** + * checkOffset - get the offset below/above and left/right element depending on screen position + * Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js + */ + function getOffset(picker, input) { + var extraY = 0; + var dpWidth = picker.outerWidth(); + var dpHeight = picker.outerHeight(); + var inputHeight = input.outerHeight(); + var doc = picker[0].ownerDocument; + var docElem = doc.documentElement; + var viewWidth = docElem.clientWidth + $(doc).scrollLeft(); + var viewHeight = docElem.clientHeight + $(doc).scrollTop(); + var offset = input.offset(); + offset.top += inputHeight; + + offset.left -= + Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? + Math.abs(offset.left + dpWidth - viewWidth) : 0); + + offset.top -= + Math.min(offset.top, ((offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? + Math.abs(dpHeight + inputHeight - extraY) : extraY)); + + return offset; + } + + /** + * noop - do nothing + */ + function noop() { + + } + + /** + * stopPropagation - makes the code only doing this a little easier to read in line + */ + function stopPropagation(e) { + e.stopPropagation(); + } + + /** + * Create a function bound to a given object + * Thanks to underscore.js + */ + function bind(func, obj) { + var slice = Array.prototype.slice; + var args = slice.call(arguments, 2); + return function () { + return func.apply(obj, args.concat(slice.call(arguments))); + }; + } + + /** + * Lightweight drag helper. Handles containment within the element, so that + * when dragging, the x is within [0,element.width] and y is within [0,element.height] + */ + function draggable(element, onmove, onstart, onstop) { + onmove = onmove || function () { }; + onstart = onstart || function () { }; + onstop = onstop || function () { }; + var doc = element.ownerDocument || document; + var dragging = false; + var offset = {}; + var maxHeight = 0; + var maxWidth = 0; + var hasTouch = ('ontouchstart' in window); + + var duringDragEvents = {}; + duringDragEvents["selectstart"] = prevent; + duringDragEvents["dragstart"] = prevent; + duringDragEvents["touchmove mousemove"] = move; + duringDragEvents["touchend mouseup"] = stop; + + function prevent(e) { + if (e.stopPropagation) { + e.stopPropagation(); + } + if (e.preventDefault) { + e.preventDefault(); + } + e.returnValue = false; + } + + function move(e) { + if (dragging) { + // Mouseup happened outside of window + if (IE && document.documentMode < 9 && !e.button) { + return stop(); + } + + var touches = e.originalEvent.touches; + var pageX = touches ? touches[0].pageX : e.pageX; + var pageY = touches ? touches[0].pageY : e.pageY; + + var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth)); + var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight)); + + if (hasTouch) { + // Stop scrolling in iOS + prevent(e); + } + + onmove.apply(element, [dragX, dragY, e]); + } + } + + function start(e) { + var rightclick = (e.which) ? (e.which == 3) : (e.button == 2); + var touches = e.originalEvent.touches; + + if (!rightclick && !dragging) { + if (onstart.apply(element, arguments) !== false) { + dragging = true; + maxHeight = $(element).height(); + maxWidth = $(element).width(); + offset = $(element).offset(); + + $(doc).bind(duringDragEvents); + $(doc.body).addClass("sp-dragging"); + + if (!hasTouch) { + move(e); + } + + prevent(e); + } + } + } + + function stop() { + if (dragging) { + $(doc).unbind(duringDragEvents); + $(doc.body).removeClass("sp-dragging"); + onstop.apply(element, arguments); + } + dragging = false; + } + + $(element).bind("touchstart mousedown", start); + } + + function throttle(func, wait, debounce) { + var timeout; + return function () { + var context = this, args = arguments; + var throttler = function () { + timeout = null; + func.apply(context, args); + }; + if (debounce) clearTimeout(timeout); + if (debounce || !timeout) timeout = setTimeout(throttler, wait); + }; + } + + function log(){/* jshint -W021 */if(window.console){if(Function.prototype.bind)log=Function.prototype.bind.call(console.log,console);else log=function(){Function.prototype.apply.call(console.log,console,arguments);};log.apply(this,arguments);}} + + /** + * Define a jQuery plugin + */ + var dataID = "spectrum.id"; + $.fn.spectrum = function (opts, extra) { + + if (typeof opts == "string") { + + var returnValue = this; + var args = Array.prototype.slice.call( arguments, 1 ); + + this.each(function () { + var spect = spectrums[$(this).data(dataID)]; + if (spect) { + var method = spect[opts]; + if (!method) { + throw new Error( "Spectrum: no such method: '" + opts + "'" ); + } + + if (opts == "get") { + returnValue = spect.get(); + } + else if (opts == "container") { + returnValue = spect.container; + } + else if (opts == "option") { + returnValue = spect.option.apply(spect, args); + } + else if (opts == "destroy") { + spect.destroy(); + $(this).removeData(dataID); + } + else { + method.apply(spect, args); + } + } + }); + + return returnValue; + } + + // Initializing a new instance of spectrum + return this.spectrum("destroy").each(function () { + var options = $.extend({}, opts, $(this).data()); + var spect = spectrum(this, options); + $(this).data(dataID, spect.id); + }); + }; + + $.fn.spectrum.load = true; + $.fn.spectrum.loadOpts = {}; + $.fn.spectrum.draggable = draggable; + $.fn.spectrum.defaults = defaultOpts; + + $.spectrum = { }; + $.spectrum.localization = { }; + $.spectrum.palettes = { }; + + $.fn.spectrum.processNativeColorInputs = function () { + if (!inputTypeColorSupport) { + $("input[type=color]").spectrum({ + preferredFormat: "hex6" + }); + } + }; + + // TinyColor v0.9.17 + // https://github.com/bgrins/TinyColor + // 2013-08-10, Brian Grinstead, MIT License + + (function() { + + var trimLeft = /^[\s,#]+/, + trimRight = /\s+$/, + tinyCounter = 0, + math = Math, + mathRound = math.round, + mathMin = math.min, + mathMax = math.max, + mathRandom = math.random; + + function tinycolor (color, opts) { + + color = (color) ? color : ''; + opts = opts || { }; + + // If input is already a tinycolor, return itself + if (typeof color == "object" && color.hasOwnProperty("_tc_id")) { + return color; + } + + var rgb = inputToRGB(color); + var r = rgb.r, + g = rgb.g, + b = rgb.b, + a = rgb.a, + roundA = mathRound(100*a) / 100, + format = opts.format || rgb.format; + + // Don't let the range of [0,255] come back in [0,1]. + // Potentially lose a little bit of precision here, but will fix issues where + // .5 gets interpreted as half of the total, instead of half of 1 + // If it was supposed to be 128, this was already taken care of by `inputToRgb` + if (r < 1) { r = mathRound(r); } + if (g < 1) { g = mathRound(g); } + if (b < 1) { b = mathRound(b); } + + return { + ok: rgb.ok, + format: format, + _tc_id: tinyCounter++, + alpha: a, + getAlpha: function() { + return a; + }, + setAlpha: function(value) { + a = boundAlpha(value); + roundA = mathRound(100*a) / 100; + }, + toHsv: function() { + var hsv = rgbToHsv(r, g, b); + return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: a }; + }, + toHsvString: function() { + var hsv = rgbToHsv(r, g, b); + var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100); + return (a == 1) ? + "hsv(" + h + ", " + s + "%, " + v + "%)" : + "hsva(" + h + ", " + s + "%, " + v + "%, "+ roundA + ")"; + }, + toHsl: function() { + var hsl = rgbToHsl(r, g, b); + return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: a }; + }, + toHslString: function() { + var hsl = rgbToHsl(r, g, b); + var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100); + return (a == 1) ? + "hsl(" + h + ", " + s + "%, " + l + "%)" : + "hsla(" + h + ", " + s + "%, " + l + "%, "+ roundA + ")"; + }, + toHex: function(allow3Char) { + return rgbToHex(r, g, b, allow3Char); + }, + toHexString: function(allow3Char) { + return '#' + this.toHex(allow3Char); + }, + toHex8: function() { + return rgbaToHex(r, g, b, a); + }, + toHex8String: function() { + return '#' + this.toHex8(); + }, + toRgb: function() { + return { r: mathRound(r), g: mathRound(g), b: mathRound(b), a: a }; + }, + toRgbString: function() { + return (a == 1) ? + "rgb(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ")" : + "rgba(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ", " + roundA + ")"; + }, + toPercentageRgb: function() { + return { r: mathRound(bound01(r, 255) * 100) + "%", g: mathRound(bound01(g, 255) * 100) + "%", b: mathRound(bound01(b, 255) * 100) + "%", a: a }; + }, + toPercentageRgbString: function() { + return (a == 1) ? + "rgb(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%)" : + "rgba(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%, " + roundA + ")"; + }, + toName: function() { + if (a === 0) { + return "transparent"; + } + + return hexNames[rgbToHex(r, g, b, true)] || false; + }, + toFilter: function(secondColor) { + var hex8String = '#' + rgbaToHex(r, g, b, a); + var secondHex8String = hex8String; + var gradientType = opts && opts.gradientType ? "GradientType = 1, " : ""; + + if (secondColor) { + var s = tinycolor(secondColor); + secondHex8String = s.toHex8String(); + } + + return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr="+hex8String+",endColorstr="+secondHex8String+")"; + }, + toString: function(format) { + var formatSet = !!format; + format = format || this.format; + + var formattedString = false; + var hasAlphaAndFormatNotSet = !formatSet && a < 1 && a > 0; + var formatWithAlpha = hasAlphaAndFormatNotSet && (format === "hex" || format === "hex6" || format === "hex3" || format === "name"); + + if (format === "rgb") { + formattedString = this.toRgbString(); + } + if (format === "prgb") { + formattedString = this.toPercentageRgbString(); + } + if (format === "hex" || format === "hex6") { + formattedString = this.toHexString(); + } + if (format === "hex3") { + formattedString = this.toHexString(true); + } + if (format === "hex8") { + formattedString = this.toHex8String(); + } + if (format === "name") { + formattedString = this.toName(); + } + if (format === "hsl") { + formattedString = this.toHslString(); + } + if (format === "hsv") { + formattedString = this.toHsvString(); + } + + if (formatWithAlpha) { + return this.toRgbString(); + } + + return formattedString || this.toHexString(); + } + }; + } + + // If input is an object, force 1 into "1.0" to handle ratios properly + // String input requires "1.0" as input, so 1 will be treated as 1 + tinycolor.fromRatio = function(color, opts) { + if (typeof color == "object") { + var newColor = {}; + for (var i in color) { + if (color.hasOwnProperty(i)) { + if (i === "a") { + newColor[i] = color[i]; + } + else { + newColor[i] = convertToPercentage(color[i]); + } + } + } + color = newColor; + } + + return tinycolor(color, opts); + }; + + // Given a string or object, convert that input to RGB + // Possible string inputs: + // + // "red" + // "#f00" or "f00" + // "#ff0000" or "ff0000" + // "#ff000000" or "ff000000" + // "rgb 255 0 0" or "rgb (255, 0, 0)" + // "rgb 1.0 0 0" or "rgb (1, 0, 0)" + // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" + // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" + // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" + // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" + // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" + // + function inputToRGB(color) { + + var rgb = { r: 0, g: 0, b: 0 }; + var a = 1; + var ok = false; + var format = false; + + if (typeof color == "string") { + color = stringInputToObject(color); + } + + if (typeof color == "object") { + if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) { + rgb = rgbToRgb(color.r, color.g, color.b); + ok = true; + format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; + } + else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) { + color.s = convertToPercentage(color.s); + color.v = convertToPercentage(color.v); + rgb = hsvToRgb(color.h, color.s, color.v); + ok = true; + format = "hsv"; + } + else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) { + color.s = convertToPercentage(color.s); + color.l = convertToPercentage(color.l); + rgb = hslToRgb(color.h, color.s, color.l); + ok = true; + format = "hsl"; + } + + if (color.hasOwnProperty("a")) { + a = color.a; + } + } + + a = boundAlpha(a); + + return { + ok: ok, + format: color.format || format, + r: mathMin(255, mathMax(rgb.r, 0)), + g: mathMin(255, mathMax(rgb.g, 0)), + b: mathMin(255, mathMax(rgb.b, 0)), + a: a + }; + } + + + // Conversion Functions + // -------------------- + + // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: + // + + // `rgbToRgb` + // Handle bounds / percentage checking to conform to CSS color spec + // + // *Assumes:* r, g, b in [0, 255] or [0, 1] + // *Returns:* { r, g, b } in [0, 255] + function rgbToRgb(r, g, b){ + return { + r: bound01(r, 255) * 255, + g: bound01(g, 255) * 255, + b: bound01(b, 255) * 255 + }; + } + + // `rgbToHsl` + // Converts an RGB color value to HSL. + // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] + // *Returns:* { h, s, l } in [0,1] + function rgbToHsl(r, g, b) { + + r = bound01(r, 255); + g = bound01(g, 255); + b = bound01(b, 255); + + var max = mathMax(r, g, b), min = mathMin(r, g, b); + var h, s, l = (max + min) / 2; + + if(max == min) { + h = s = 0; // achromatic + } + else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch(max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + + h /= 6; + } + + return { h: h, s: s, l: l }; + } + + // `hslToRgb` + // Converts an HSL color value to RGB. + // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] + // *Returns:* { r, g, b } in the set [0, 255] + function hslToRgb(h, s, l) { + var r, g, b; + + h = bound01(h, 360); + s = bound01(s, 100); + l = bound01(l, 100); + + function hue2rgb(p, q, t) { + if(t < 0) t += 1; + if(t > 1) t -= 1; + if(t < 1/6) return p + (q - p) * 6 * t; + if(t < 1/2) return q; + if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; + return p; + } + + if(s === 0) { + r = g = b = l; // achromatic + } + else { + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1/3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1/3); + } + + return { r: r * 255, g: g * 255, b: b * 255 }; + } + + // `rgbToHsv` + // Converts an RGB color value to HSV + // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] + // *Returns:* { h, s, v } in [0,1] + function rgbToHsv(r, g, b) { + + r = bound01(r, 255); + g = bound01(g, 255); + b = bound01(b, 255); + + var max = mathMax(r, g, b), min = mathMin(r, g, b); + var h, s, v = max; + + var d = max - min; + s = max === 0 ? 0 : d / max; + + if(max == min) { + h = 0; // achromatic + } + else { + switch(max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; + } + return { h: h, s: s, v: v }; + } + + // `hsvToRgb` + // Converts an HSV color value to RGB. + // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] + // *Returns:* { r, g, b } in the set [0, 255] + function hsvToRgb(h, s, v) { + + h = bound01(h, 360) * 6; + s = bound01(s, 100); + v = bound01(v, 100); + + var i = math.floor(h), + f = h - i, + p = v * (1 - s), + q = v * (1 - f * s), + t = v * (1 - (1 - f) * s), + mod = i % 6, + r = [v, q, p, p, t, v][mod], + g = [t, v, v, q, p, p][mod], + b = [p, p, t, v, v, q][mod]; + + return { r: r * 255, g: g * 255, b: b * 255 }; + } + + // `rgbToHex` + // Converts an RGB color to hex + // Assumes r, g, and b are contained in the set [0, 255] + // Returns a 3 or 6 character hex + function rgbToHex(r, g, b, allow3Char) { + + var hex = [ + pad2(mathRound(r).toString(16)), + pad2(mathRound(g).toString(16)), + pad2(mathRound(b).toString(16)) + ]; + + // Return a 3 character hex if possible + if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) { + return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); + } + + return hex.join(""); + } + // `rgbaToHex` + // Converts an RGBA color plus alpha transparency to hex + // Assumes r, g, b and a are contained in the set [0, 255] + // Returns an 8 character hex + function rgbaToHex(r, g, b, a) { + + var hex = [ + pad2(convertDecimalToHex(a)), + pad2(mathRound(r).toString(16)), + pad2(mathRound(g).toString(16)), + pad2(mathRound(b).toString(16)) + ]; + + return hex.join(""); + } + + // `equals` + // Can be called with any tinycolor input + tinycolor.equals = function (color1, color2) { + if (!color1 || !color2) { return false; } + return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); + }; + tinycolor.random = function() { + return tinycolor.fromRatio({ + r: mathRandom(), + g: mathRandom(), + b: mathRandom() + }); + }; + + + // Modification Functions + // ---------------------- + // Thanks to less.js for some of the basics here + // + + tinycolor.desaturate = function (color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.s -= amount / 100; + hsl.s = clamp01(hsl.s); + return tinycolor(hsl); + }; + tinycolor.saturate = function (color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.s += amount / 100; + hsl.s = clamp01(hsl.s); + return tinycolor(hsl); + }; + tinycolor.greyscale = function(color) { + return tinycolor.desaturate(color, 100); + }; + tinycolor.lighten = function(color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.l += amount / 100; + hsl.l = clamp01(hsl.l); + return tinycolor(hsl); + }; + tinycolor.darken = function (color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.l -= amount / 100; + hsl.l = clamp01(hsl.l); + return tinycolor(hsl); + }; + tinycolor.complement = function(color) { + var hsl = tinycolor(color).toHsl(); + hsl.h = (hsl.h + 180) % 360; + return tinycolor(hsl); + }; + + + // Combination Functions + // --------------------- + // Thanks to jQuery xColor for some of the ideas behind these + // + + tinycolor.triad = function(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [ + tinycolor(color), + tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }), + tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l }) + ]; + }; + tinycolor.tetrad = function(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [ + tinycolor(color), + tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }), + tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }), + tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l }) + ]; + }; + tinycolor.splitcomplement = function(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [ + tinycolor(color), + tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}), + tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l}) + ]; + }; + tinycolor.analogous = function(color, results, slices) { + results = results || 6; + slices = slices || 30; + + var hsl = tinycolor(color).toHsl(); + var part = 360 / slices; + var ret = [tinycolor(color)]; + + for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) { + hsl.h = (hsl.h + part) % 360; + ret.push(tinycolor(hsl)); + } + return ret; + }; + tinycolor.monochromatic = function(color, results) { + results = results || 6; + var hsv = tinycolor(color).toHsv(); + var h = hsv.h, s = hsv.s, v = hsv.v; + var ret = []; + var modification = 1 / results; + + while (results--) { + ret.push(tinycolor({ h: h, s: s, v: v})); + v = (v + modification) % 1; + } + + return ret; + }; + + + // Readability Functions + // --------------------- + // + + // `readability` + // Analyze the 2 colors and returns an object with the following properties: + // `brightness`: difference in brightness between the two colors + // `color`: difference in color/hue between the two colors + tinycolor.readability = function(color1, color2) { + var a = tinycolor(color1).toRgb(); + var b = tinycolor(color2).toRgb(); + var brightnessA = (a.r * 299 + a.g * 587 + a.b * 114) / 1000; + var brightnessB = (b.r * 299 + b.g * 587 + b.b * 114) / 1000; + var colorDiff = ( + Math.max(a.r, b.r) - Math.min(a.r, b.r) + + Math.max(a.g, b.g) - Math.min(a.g, b.g) + + Math.max(a.b, b.b) - Math.min(a.b, b.b) + ); + + return { + brightness: Math.abs(brightnessA - brightnessB), + color: colorDiff + }; + }; + + // `readable` + // http://www.w3.org/TR/AERT#color-contrast + // Ensure that foreground and background color combinations provide sufficient contrast. + // *Example* + // tinycolor.readable("#000", "#111") => false + tinycolor.readable = function(color1, color2) { + var readability = tinycolor.readability(color1, color2); + return readability.brightness > 125 && readability.color > 500; + }; + + // `mostReadable` + // Given a base color and a list of possible foreground or background + // colors for that base, returns the most readable color. + // *Example* + // tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000" + tinycolor.mostReadable = function(baseColor, colorList) { + var bestColor = null; + var bestScore = 0; + var bestIsReadable = false; + for (var i=0; i < colorList.length; i++) { + + // We normalize both around the "acceptable" breaking point, + // but rank brightness constrast higher than hue. + + var readability = tinycolor.readability(baseColor, colorList[i]); + var readable = readability.brightness > 125 && readability.color > 500; + var score = 3 * (readability.brightness / 125) + (readability.color / 500); + + if ((readable && ! bestIsReadable) || + (readable && bestIsReadable && score > bestScore) || + ((! readable) && (! bestIsReadable) && score > bestScore)) { + bestIsReadable = readable; + bestScore = score; + bestColor = tinycolor(colorList[i]); + } + } + return bestColor; + }; + + + // Big List of Colors + // ------------------ + // + var names = tinycolor.names = { + aliceblue: "f0f8ff", + antiquewhite: "faebd7", + aqua: "0ff", + aquamarine: "7fffd4", + azure: "f0ffff", + beige: "f5f5dc", + bisque: "ffe4c4", + black: "000", + blanchedalmond: "ffebcd", + blue: "00f", + blueviolet: "8a2be2", + brown: "a52a2a", + burlywood: "deb887", + burntsienna: "ea7e5d", + cadetblue: "5f9ea0", + chartreuse: "7fff00", + chocolate: "d2691e", + coral: "ff7f50", + cornflowerblue: "6495ed", + cornsilk: "fff8dc", + crimson: "dc143c", + cyan: "0ff", + darkblue: "00008b", + darkcyan: "008b8b", + darkgoldenrod: "b8860b", + darkgray: "a9a9a9", + darkgreen: "006400", + darkgrey: "a9a9a9", + darkkhaki: "bdb76b", + darkmagenta: "8b008b", + darkolivegreen: "556b2f", + darkorange: "ff8c00", + darkorchid: "9932cc", + darkred: "8b0000", + darksalmon: "e9967a", + darkseagreen: "8fbc8f", + darkslateblue: "483d8b", + darkslategray: "2f4f4f", + darkslategrey: "2f4f4f", + darkturquoise: "00ced1", + darkviolet: "9400d3", + deeppink: "ff1493", + deepskyblue: "00bfff", + dimgray: "696969", + dimgrey: "696969", + dodgerblue: "1e90ff", + firebrick: "b22222", + floralwhite: "fffaf0", + forestgreen: "228b22", + fuchsia: "f0f", + gainsboro: "dcdcdc", + ghostwhite: "f8f8ff", + gold: "ffd700", + goldenrod: "daa520", + gray: "808080", + green: "008000", + greenyellow: "adff2f", + grey: "808080", + honeydew: "f0fff0", + hotpink: "ff69b4", + indianred: "cd5c5c", + indigo: "4b0082", + ivory: "fffff0", + khaki: "f0e68c", + lavender: "e6e6fa", + lavenderblush: "fff0f5", + lawngreen: "7cfc00", + lemonchiffon: "fffacd", + lightblue: "add8e6", + lightcoral: "f08080", + lightcyan: "e0ffff", + lightgoldenrodyellow: "fafad2", + lightgray: "d3d3d3", + lightgreen: "90ee90", + lightgrey: "d3d3d3", + lightpink: "ffb6c1", + lightsalmon: "ffa07a", + lightseagreen: "20b2aa", + lightskyblue: "87cefa", + lightslategray: "789", + lightslategrey: "789", + lightsteelblue: "b0c4de", + lightyellow: "ffffe0", + lime: "0f0", + limegreen: "32cd32", + linen: "faf0e6", + magenta: "f0f", + maroon: "800000", + mediumaquamarine: "66cdaa", + mediumblue: "0000cd", + mediumorchid: "ba55d3", + mediumpurple: "9370db", + mediumseagreen: "3cb371", + mediumslateblue: "7b68ee", + mediumspringgreen: "00fa9a", + mediumturquoise: "48d1cc", + mediumvioletred: "c71585", + midnightblue: "191970", + mintcream: "f5fffa", + mistyrose: "ffe4e1", + moccasin: "ffe4b5", + navajowhite: "ffdead", + navy: "000080", + oldlace: "fdf5e6", + olive: "808000", + olivedrab: "6b8e23", + orange: "ffa500", + orangered: "ff4500", + orchid: "da70d6", + palegoldenrod: "eee8aa", + palegreen: "98fb98", + paleturquoise: "afeeee", + palevioletred: "db7093", + papayawhip: "ffefd5", + peachpuff: "ffdab9", + peru: "cd853f", + pink: "ffc0cb", + plum: "dda0dd", + powderblue: "b0e0e6", + purple: "800080", + red: "f00", + rosybrown: "bc8f8f", + royalblue: "4169e1", + saddlebrown: "8b4513", + salmon: "fa8072", + sandybrown: "f4a460", + seagreen: "2e8b57", + seashell: "fff5ee", + sienna: "a0522d", + silver: "c0c0c0", + skyblue: "87ceeb", + slateblue: "6a5acd", + slategray: "708090", + slategrey: "708090", + snow: "fffafa", + springgreen: "00ff7f", + steelblue: "4682b4", + tan: "d2b48c", + teal: "008080", + thistle: "d8bfd8", + tomato: "ff6347", + turquoise: "40e0d0", + violet: "ee82ee", + wheat: "f5deb3", + white: "fff", + whitesmoke: "f5f5f5", + yellow: "ff0", + yellowgreen: "9acd32" + }; + + // Make it easy to access colors via `hexNames[hex]` + var hexNames = tinycolor.hexNames = flip(names); + + + // Utilities + // --------- + + // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` + function flip(o) { + var flipped = { }; + for (var i in o) { + if (o.hasOwnProperty(i)) { + flipped[o[i]] = i; + } + } + return flipped; + } + + // Return a valid alpha value [0,1] with all invalid values being set to 1 + function boundAlpha(a) { + a = parseFloat(a); + + if (isNaN(a) || a < 0 || a > 1) { + a = 1; + } + + return a; + } + + // Take input from [0, n] and return it as [0, 1] + function bound01(n, max) { + if (isOnePointZero(n)) { n = "100%"; } + + var processPercent = isPercentage(n); + n = mathMin(max, mathMax(0, parseFloat(n))); + + // Automatically convert percentage into number + if (processPercent) { + n = parseInt(n * max, 10) / 100; + } + + // Handle floating point rounding errors + if ((math.abs(n - max) < 0.000001)) { + return 1; + } + + // Convert into [0, 1] range if it isn't already + return (n % max) / parseFloat(max); + } + + // Force a number between 0 and 1 + function clamp01(val) { + return mathMin(1, mathMax(0, val)); + } + + // Parse a base-16 hex value into a base-10 integer + function parseIntFromHex(val) { + return parseInt(val, 16); + } + + // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 + // + function isOnePointZero(n) { + return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1; + } + + // Check to see if string passed in is a percentage + function isPercentage(n) { + return typeof n === "string" && n.indexOf('%') != -1; + } + + // Force a hex value to have 2 characters + function pad2(c) { + return c.length == 1 ? '0' + c : '' + c; + } + + // Replace a decimal with it's percentage value + function convertToPercentage(n) { + if (n <= 1) { + n = (n * 100) + "%"; + } + + return n; + } + + // Converts a decimal to a hex value + function convertDecimalToHex(d) { + return Math.round(parseFloat(d) * 255).toString(16); + } + // Converts a hex value to a decimal + function convertHexToDecimal(h) { + return (parseIntFromHex(h) / 255); + } + + var matchers = (function() { + + // + var CSS_INTEGER = "[-\\+]?\\d+%?"; + + // + var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; + + // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. + var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; + + // Actual matching. + // Parentheses and commas are optional, but not required. + // Whitespace can take the place of commas or opening paren + var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; + var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; + + return { + rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), + rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), + hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), + hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), + hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), + hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, + hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/, + hex8: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ + }; + })(); + + // `stringInputToObject` + // Permissive string parsing. Take in a number of formats, and output an object + // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` + function stringInputToObject(color) { + + color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase(); + var named = false; + if (names[color]) { + color = names[color]; + named = true; + } + else if (color == 'transparent') { + return { r: 0, g: 0, b: 0, a: 0, format: "name" }; + } + + // Try to match string input using regular expressions. + // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] + // Just return an object and let the conversion functions handle that. + // This way the result will be the same whether the tinycolor is initialized with string or object. + var match; + if ((match = matchers.rgb.exec(color))) { + return { r: match[1], g: match[2], b: match[3] }; + } + if ((match = matchers.rgba.exec(color))) { + return { r: match[1], g: match[2], b: match[3], a: match[4] }; + } + if ((match = matchers.hsl.exec(color))) { + return { h: match[1], s: match[2], l: match[3] }; + } + if ((match = matchers.hsla.exec(color))) { + return { h: match[1], s: match[2], l: match[3], a: match[4] }; + } + if ((match = matchers.hsv.exec(color))) { + return { h: match[1], s: match[2], v: match[3] }; + } + if ((match = matchers.hex8.exec(color))) { + return { + a: convertHexToDecimal(match[1]), + r: parseIntFromHex(match[2]), + g: parseIntFromHex(match[3]), + b: parseIntFromHex(match[4]), + format: named ? "name" : "hex8" + }; + } + if ((match = matchers.hex6.exec(color))) { + return { + r: parseIntFromHex(match[1]), + g: parseIntFromHex(match[2]), + b: parseIntFromHex(match[3]), + format: named ? "name" : "hex" + }; + } + if ((match = matchers.hex3.exec(color))) { + return { + r: parseIntFromHex(match[1] + '' + match[1]), + g: parseIntFromHex(match[2] + '' + match[2]), + b: parseIntFromHex(match[3] + '' + match[3]), + format: named ? "name" : "hex" + }; + } + + return false; + } + + // Expose tinycolor to window, does not need to run in non-browser context. + window.tinycolor = tinycolor; + + })(); + + + $(function () { + if ($.fn.spectrum.load) { + $.fn.spectrum.processNativeColorInputs(); + } + }); + +})(window, jQuery); diff --git a/snow-flowable/src/main/resources/static/libs/angular-strap_2.1.6/angular-strap.js b/snow-flowable/src/main/resources/static/libs/angular-strap_2.1.6/angular-strap.js new file mode 100644 index 0000000..5971d88 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-strap_2.1.6/angular-strap.js @@ -0,0 +1,5014 @@ +/** + * angular-strap + * @version v2.1.6 - 2015-01-11 + * @link http://mgcrea.github.io/angular-strap + * @author Olivier Louvignes (olivier@mg-crea.com) + * @license MIT License, http://www.opensource.org/licenses/MIT + */ +(function(window, document, undefined) { +'use strict'; +// Source: module.js +angular.module('mgcrea.ngStrap', [ + 'mgcrea.ngStrap.modal', + 'mgcrea.ngStrap.aside', + 'mgcrea.ngStrap.alert', + 'mgcrea.ngStrap.button', + 'mgcrea.ngStrap.select', + 'mgcrea.ngStrap.datepicker', + 'mgcrea.ngStrap.timepicker', + 'mgcrea.ngStrap.navbar', + 'mgcrea.ngStrap.tooltip', + 'mgcrea.ngStrap.popover', + 'mgcrea.ngStrap.dropdown', + 'mgcrea.ngStrap.typeahead', + 'mgcrea.ngStrap.scrollspy', + 'mgcrea.ngStrap.affix', + 'mgcrea.ngStrap.tab', + 'mgcrea.ngStrap.collapse' +]); + +// Source: affix.js +angular.module('mgcrea.ngStrap.affix', ['mgcrea.ngStrap.helpers.dimensions', 'mgcrea.ngStrap.helpers.debounce']) + + .provider('$affix', function() { + + var defaults = this.defaults = { + offsetTop: 'auto' + }; + + this.$get = ["$window", "debounce", "dimensions", function($window, debounce, dimensions) { + + var bodyEl = angular.element($window.document.body); + var windowEl = angular.element($window); + + function AffixFactory(element, config) { + + var $affix = {}; + + // Common vars + var options = angular.extend({}, defaults, config); + var targetEl = options.target; + + // Initial private vars + var reset = 'affix affix-top affix-bottom', + setWidth = false, + initialAffixTop = 0, + initialOffsetTop = 0, + offsetTop = 0, + offsetBottom = 0, + affixed = null, + unpin = null; + + var parent = element.parent(); + // Options: custom parent + if (options.offsetParent) { + if (options.offsetParent.match(/^\d+$/)) { + for (var i = 0; i < (options.offsetParent * 1) - 1; i++) { + parent = parent.parent(); + } + } + else { + parent = angular.element(options.offsetParent); + } + } + + $affix.init = function() { + + this.$parseOffsets(); + initialOffsetTop = dimensions.offset(element[0]).top + initialAffixTop; + setWidth = !element[0].style.width; + + // Bind events + targetEl.on('scroll', this.checkPosition); + targetEl.on('click', this.checkPositionWithEventLoop); + windowEl.on('resize', this.$debouncedOnResize); + + // Both of these checkPosition() calls are necessary for the case where + // the user hits refresh after scrolling to the bottom of the page. + this.checkPosition(); + this.checkPositionWithEventLoop(); + + }; + + $affix.destroy = function() { + + // Unbind events + targetEl.off('scroll', this.checkPosition); + targetEl.off('click', this.checkPositionWithEventLoop); + windowEl.off('resize', this.$debouncedOnResize); + + }; + + $affix.checkPositionWithEventLoop = function() { + + // IE 9 throws an error if we use 'this' instead of '$affix' + // in this setTimeout call + setTimeout($affix.checkPosition, 1); + + }; + + $affix.checkPosition = function() { + // if (!this.$element.is(':visible')) return + + var scrollTop = getScrollTop(); + var position = dimensions.offset(element[0]); + var elementHeight = dimensions.height(element[0]); + + // Get required affix class according to position + var affix = getRequiredAffixClass(unpin, position, elementHeight); + + // Did affix status changed this last check? + if(affixed === affix) return; + affixed = affix; + + // Add proper affix class + element.removeClass(reset).addClass('affix' + ((affix !== 'middle') ? '-' + affix : '')); + + if(affix === 'top') { + unpin = null; + element.css('position', (options.offsetParent) ? '' : 'relative'); + if(setWidth) { + element.css('width', ''); + } + element.css('top', ''); + } else if(affix === 'bottom') { + if (options.offsetUnpin) { + unpin = -(options.offsetUnpin * 1); + } + else { + // Calculate unpin threshold when affixed to bottom. + // Hopefully the browser scrolls pixel by pixel. + unpin = position.top - scrollTop; + } + if(setWidth) { + element.css('width', ''); + } + element.css('position', (options.offsetParent) ? '' : 'relative'); + element.css('top', (options.offsetParent) ? '' : ((bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop) + 'px')); + } else { // affix === 'middle' + unpin = null; + if(setWidth) { + element.css('width', element[0].offsetWidth + 'px'); + } + element.css('position', 'fixed'); + element.css('top', initialAffixTop + 'px'); + } + + }; + + $affix.$onResize = function() { + $affix.$parseOffsets(); + $affix.checkPosition(); + }; + $affix.$debouncedOnResize = debounce($affix.$onResize, 50); + + $affix.$parseOffsets = function() { + var initialPosition = element.css('position'); + // Reset position to calculate correct offsetTop + element.css('position', (options.offsetParent) ? '' : 'relative'); + + if(options.offsetTop) { + if(options.offsetTop === 'auto') { + options.offsetTop = '+0'; + } + if(options.offsetTop.match(/^[-+]\d+$/)) { + initialAffixTop = - options.offsetTop * 1; + if(options.offsetParent) { + offsetTop = dimensions.offset(parent[0]).top + (options.offsetTop * 1); + } + else { + offsetTop = dimensions.offset(element[0]).top - dimensions.css(element[0], 'marginTop', true) + (options.offsetTop * 1); + } + } + else { + offsetTop = options.offsetTop * 1; + } + } + + if(options.offsetBottom) { + if(options.offsetParent && options.offsetBottom.match(/^[-+]\d+$/)) { + // add 1 pixel due to rounding problems... + offsetBottom = getScrollHeight() - (dimensions.offset(parent[0]).top + dimensions.height(parent[0])) + (options.offsetBottom * 1) + 1; + } + else { + offsetBottom = options.offsetBottom * 1; + } + } + + // Bring back the element's position after calculations + element.css('position', initialPosition); + }; + + // Private methods + + function getRequiredAffixClass(unpin, position, elementHeight) { + + var scrollTop = getScrollTop(); + var scrollHeight = getScrollHeight(); + + if(scrollTop <= offsetTop) { + return 'top'; + } else if(unpin !== null && (scrollTop + unpin <= position.top)) { + return 'middle'; + } else if(offsetBottom !== null && (position.top + elementHeight + initialAffixTop >= scrollHeight - offsetBottom)) { + return 'bottom'; + } else { + return 'middle'; + } + + } + + function getScrollTop() { + return targetEl[0] === $window ? $window.pageYOffset : targetEl[0].scrollTop; + } + + function getScrollHeight() { + return targetEl[0] === $window ? $window.document.body.scrollHeight : targetEl[0].scrollHeight; + } + + $affix.init(); + return $affix; + + } + + return AffixFactory; + + }]; + + }) + + .directive('bsAffix', ["$affix", "$window", function($affix, $window) { + + return { + restrict: 'EAC', + require: '^?bsAffixTarget', + link: function postLink(scope, element, attr, affixTarget) { + + var options = {scope: scope, offsetTop: 'auto', target: affixTarget ? affixTarget.$element : angular.element($window)}; + angular.forEach(['offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + var affix = $affix(element, options); + scope.$on('$destroy', function() { + affix && affix.destroy(); + options = null; + affix = null; + }); + + } + }; + + }]) + + .directive('bsAffixTarget', function() { + return { + controller: ["$element", function($element) { + this.$element = $element; + }] + }; + }); + +// Source: alert.js +// @BUG: following snippet won't compile correctly +// @TODO: submit issue to core +// ' ' + + +angular.module('mgcrea.ngStrap.alert', ['mgcrea.ngStrap.modal']) + + .provider('$alert', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + prefixClass: 'alert', + prefixEvent: 'alert', + placement: null, + template: 'alert/alert.tpl.html', + container: false, + element: null, + backdrop: false, + keyboard: true, + show: true, + // Specific options + duration: false, + type: false, + dismissable: true + }; + + this.$get = ["$modal", "$timeout", function($modal, $timeout) { + + function AlertFactory(config) { + + var $alert = {}; + + // Common vars + var options = angular.extend({}, defaults, config); + + $alert = $modal(options); + + // Support scope as string options [/*title, content, */ type, dismissable] + $alert.$scope.dismissable = !!options.dismissable; + if(options.type) { + $alert.$scope.type = options.type; + } + + // Support auto-close duration + var show = $alert.show; + if(options.duration) { + $alert.show = function() { + show(); + $timeout(function() { + $alert.hide(); + }, options.duration * 1000); + }; + } + + return $alert; + + } + + return AlertFactory; + + }]; + + }) + + .directive('bsAlert', ["$window", "$sce", "$alert", function($window, $sce, $alert) { + + var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; + + return { + restrict: 'EAC', + scope: true, + link: function postLink(scope, element, attr, transclusion) { + + // Directive options + var options = {scope: scope, element: element, show: false}; + angular.forEach(['template', 'placement', 'keyboard', 'html', 'container', 'animation', 'duration', 'dismissable'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Support scope as data-attrs + angular.forEach(['title', 'content', 'type'], function(key) { + attr[key] && attr.$observe(key, function(newValue, oldValue) { + scope[key] = $sce.trustAsHtml(newValue); + }); + }); + + // Support scope as an object + attr.bsAlert && scope.$watch(attr.bsAlert, function(newValue, oldValue) { + if(angular.isObject(newValue)) { + angular.extend(scope, newValue); + } else { + scope.content = newValue; + } + }, true); + + // Initialize alert + var alert = $alert(options); + + // Trigger + element.on(attr.trigger || 'click', alert.toggle); + + // Garbage collection + scope.$on('$destroy', function() { + if (alert) alert.destroy(); + options = null; + alert = null; + }); + + } + }; + + }]); + +// Source: aside.js +angular.module('mgcrea.ngStrap.aside', ['mgcrea.ngStrap.modal']) + + .provider('$aside', function() { + + var defaults = this.defaults = { + animation: 'am-fade-and-slide-right', + prefixClass: 'aside', + prefixEvent: 'aside', + placement: 'right', + template: 'aside/aside.tpl.html', + contentTemplate: false, + container: false, + element: null, + backdrop: true, + keyboard: true, + html: false, + show: true + }; + + this.$get = ["$modal", function($modal) { + + function AsideFactory(config) { + + var $aside = {}; + + // Common vars + var options = angular.extend({}, defaults, config); + + $aside = $modal(options); + + return $aside; + + } + + return AsideFactory; + + }]; + + }) + + .directive('bsAside', ["$window", "$sce", "$aside", function($window, $sce, $aside) { + + var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; + + return { + restrict: 'EAC', + scope: true, + link: function postLink(scope, element, attr, transclusion) { + // Directive options + var options = {scope: scope, element: element, show: false}; + angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Support scope as data-attrs + angular.forEach(['title', 'content'], function(key) { + attr[key] && attr.$observe(key, function(newValue, oldValue) { + scope[key] = $sce.trustAsHtml(newValue); + }); + }); + + // Support scope as an object + attr.bsAside && scope.$watch(attr.bsAside, function(newValue, oldValue) { + if(angular.isObject(newValue)) { + angular.extend(scope, newValue); + } else { + scope.content = newValue; + } + }, true); + + // Initialize aside + var aside = $aside(options); + + // Trigger + element.on(attr.trigger || 'click', aside.toggle); + + // Garbage collection + scope.$on('$destroy', function() { + if (aside) aside.destroy(); + options = null; + aside = null; + }); + + } + }; + + }]); + +// Source: button.js +angular.module('mgcrea.ngStrap.button', []) + + .provider('$button', function() { + + var defaults = this.defaults = { + activeClass:'active', + toggleEvent:'click' + }; + + this.$get = function() { + return {defaults: defaults}; + }; + + }) + + .directive('bsCheckboxGroup', function() { + + return { + restrict: 'A', + require: 'ngModel', + compile: function postLink(element, attr) { + element.attr('data-toggle', 'buttons'); + element.removeAttr('ng-model'); + var children = element[0].querySelectorAll('input[type="checkbox"]'); + angular.forEach(children, function(child) { + var childEl = angular.element(child); + childEl.attr('bs-checkbox', ''); + childEl.attr('ng-model', attr.ngModel + '.' + childEl.attr('value')); + }); + } + + }; + + }) + + .directive('bsCheckbox', ["$button", "$$rAF", function($button, $$rAF) { + + var defaults = $button.defaults; + var constantValueRegExp = /^(true|false|\d+)$/; + + return { + restrict: 'A', + require: 'ngModel', + link: function postLink(scope, element, attr, controller) { + + var options = defaults; + + // Support label > input[type="checkbox"] + var isInput = element[0].nodeName === 'INPUT'; + var activeElement = isInput ? element.parent() : element; + + var trueValue = angular.isDefined(attr.trueValue) ? attr.trueValue : true; + if(constantValueRegExp.test(attr.trueValue)) { + trueValue = scope.$eval(attr.trueValue); + } + var falseValue = angular.isDefined(attr.falseValue) ? attr.falseValue : false; + if(constantValueRegExp.test(attr.falseValue)) { + falseValue = scope.$eval(attr.falseValue); + } + + // Parse exotic values + var hasExoticValues = typeof trueValue !== 'boolean' || typeof falseValue !== 'boolean'; + if(hasExoticValues) { + controller.$parsers.push(function(viewValue) { + // console.warn('$parser', element.attr('ng-model'), 'viewValue', viewValue); + return viewValue ? trueValue : falseValue; + }); + // modelValue -> $formatters -> viewValue + controller.$formatters.push(function(modelValue) { + // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue); + return angular.equals(modelValue, trueValue); + }); + // Fix rendering for exotic values + scope.$watch(attr.ngModel, function(newValue, oldValue) { + controller.$render(); + }); + } + + // model -> view + controller.$render = function () { + // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue); + var isActive = angular.equals(controller.$modelValue, trueValue); + $$rAF(function() { + if(isInput) element[0].checked = isActive; + activeElement.toggleClass(options.activeClass, isActive); + }); + }; + + // view -> model + element.bind(options.toggleEvent, function() { + scope.$apply(function () { + // console.warn('!click', element.attr('ng-model'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue); + if(!isInput) { + controller.$setViewValue(!activeElement.hasClass('active')); + } + if(!hasExoticValues) { + controller.$render(); + } + }); + }); + + } + + }; + + }]) + + .directive('bsRadioGroup', function() { + + return { + restrict: 'A', + require: 'ngModel', + compile: function postLink(element, attr) { + element.attr('data-toggle', 'buttons'); + element.removeAttr('ng-model'); + var children = element[0].querySelectorAll('input[type="radio"]'); + angular.forEach(children, function(child) { + angular.element(child).attr('bs-radio', ''); + angular.element(child).attr('ng-model', attr.ngModel); + }); + } + + }; + + }) + + .directive('bsRadio', ["$button", "$$rAF", function($button, $$rAF) { + + var defaults = $button.defaults; + var constantValueRegExp = /^(true|false|\d+)$/; + + return { + restrict: 'A', + require: 'ngModel', + link: function postLink(scope, element, attr, controller) { + + var options = defaults; + + // Support `label > input[type="radio"]` markup + var isInput = element[0].nodeName === 'INPUT'; + var activeElement = isInput ? element.parent() : element; + + var value = constantValueRegExp.test(attr.value) ? scope.$eval(attr.value) : attr.value; + + // model -> view + controller.$render = function () { + // console.warn('$render', element.attr('value'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue); + var isActive = angular.equals(controller.$modelValue, value); + $$rAF(function() { + if(isInput) element[0].checked = isActive; + activeElement.toggleClass(options.activeClass, isActive); + }); + }; + + // view -> model + element.bind(options.toggleEvent, function() { + scope.$apply(function () { + // console.warn('!click', element.attr('value'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue); + controller.$setViewValue(value); + controller.$render(); + }); + }); + + } + + }; + + }]); + +// Source: collapse.js +angular.module('mgcrea.ngStrap.collapse', []) + + .provider('$collapse', function() { + + var defaults = this.defaults = { + animation: 'am-collapse', + disallowToggle: false, + activeClass: 'in', + startCollapsed: false, + allowMultiple: false + }; + + var controller = this.controller = function($scope, $element, $attrs) { + var self = this; + + // Attributes options + self.$options = angular.copy(defaults); + angular.forEach(['animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple'], function (key) { + if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key]; + }); + + self.$toggles = []; + self.$targets = []; + + self.$viewChangeListeners = []; + + self.$registerToggle = function(element) { + self.$toggles.push(element); + }; + self.$registerTarget = function(element) { + self.$targets.push(element); + }; + + self.$unregisterToggle = function(element) { + var index = self.$toggles.indexOf(element); + // remove toggle from $toggles array + self.$toggles.splice(index, 1); + }; + self.$unregisterTarget = function(element) { + var index = self.$targets.indexOf(element); + + // remove element from $targets array + self.$targets.splice(index, 1); + + if (self.$options.allowMultiple) { + // remove target index from $active array values + deactivateItem(element); + } + + // fix active item indexes + fixActiveItemIndexes(index); + + self.$viewChangeListeners.forEach(function(fn) { + fn(); + }); + }; + + // use array to store all the currently open panels + self.$targets.$active = !self.$options.startCollapsed ? [0] : []; + self.$setActive = $scope.$setActive = function(value) { + if(angular.isArray(value)) { + self.$targets.$active = angular.copy(value); + } + else if(!self.$options.disallowToggle) { + // toogle element active status + isActive(value) ? deactivateItem(value) : activateItem(value); + } else { + activateItem(value); + } + + self.$viewChangeListeners.forEach(function(fn) { + fn(); + }); + }; + + self.$activeIndexes = function() { + return self.$options.allowMultiple ? self.$targets.$active : + self.$targets.$active.length === 1 ? self.$targets.$active[0] : -1; + }; + + function fixActiveItemIndexes(index) { + // item with index was removed, so we + // need to adjust other items index values + var activeIndexes = self.$targets.$active; + for(var i = 0; i < activeIndexes.length; i++) { + if (index < activeIndexes[i]) { + activeIndexes[i] = activeIndexes[i] - 1; + } + + // the last item is active, so we need to + // adjust its index + if (activeIndexes[i] === self.$targets.length) { + activeIndexes[i] = self.$targets.length - 1; + } + } + } + + function isActive(value) { + var activeItems = self.$targets.$active; + return activeItems.indexOf(value) === -1 ? false : true; + } + + function deactivateItem(value) { + var index = self.$targets.$active.indexOf(value); + if (index !== -1) { + self.$targets.$active.splice(index, 1); + } + } + + function activateItem(value) { + if (!self.$options.allowMultiple) { + // remove current selected item + self.$targets.$active.splice(0, 1); + } + + if (self.$targets.$active.indexOf(value) === -1) { + self.$targets.$active.push(value); + } + } + + }; + + this.$get = function() { + var $collapse = {}; + $collapse.defaults = defaults; + $collapse.controller = controller; + return $collapse; + }; + + }) + + .directive('bsCollapse', ["$window", "$animate", "$collapse", function($window, $animate, $collapse) { + + var defaults = $collapse.defaults; + + return { + require: ['?ngModel', 'bsCollapse'], + controller: ['$scope', '$element', '$attrs', $collapse.controller], + link: function postLink(scope, element, attrs, controllers) { + + var ngModelCtrl = controllers[0]; + var bsCollapseCtrl = controllers[1]; + + if(ngModelCtrl) { + + // Update the modelValue following + bsCollapseCtrl.$viewChangeListeners.push(function() { + ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes()); + }); + + // modelValue -> $formatters -> viewValue + ngModelCtrl.$formatters.push(function(modelValue) { + // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue); + if (angular.isArray(modelValue)) { + // model value is an array, so just replace + // the active items directly + bsCollapseCtrl.$setActive(modelValue); + } + else { + var activeIndexes = bsCollapseCtrl.$activeIndexes(); + + if (angular.isArray(activeIndexes)) { + // we have an array of selected indexes + if (activeIndexes.indexOf(modelValue * 1) === -1) { + // item with modelValue index is not active + bsCollapseCtrl.$setActive(modelValue * 1); + } + } + else if (activeIndexes !== modelValue * 1) { + bsCollapseCtrl.$setActive(modelValue * 1); + } + } + return modelValue; + }); + + } + + } + }; + + }]) + + .directive('bsCollapseToggle', function() { + + return { + require: ['^?ngModel', '^bsCollapse'], + link: function postLink(scope, element, attrs, controllers) { + + var ngModelCtrl = controllers[0]; + var bsCollapseCtrl = controllers[1]; + + // Add base attr + element.attr('data-toggle', 'collapse'); + + // Push pane to parent bsCollapse controller + bsCollapseCtrl.$registerToggle(element); + + // remove toggle from collapse controller when toggle is destroyed + scope.$on('$destroy', function() { + bsCollapseCtrl.$unregisterToggle(element); + }); + + element.on('click', function() { + var index = attrs.bsCollapseToggle || bsCollapseCtrl.$toggles.indexOf(element); + bsCollapseCtrl.$setActive(index * 1); + scope.$apply(); + }); + + } + }; + + }) + + .directive('bsCollapseTarget', ["$animate", function($animate) { + + return { + require: ['^?ngModel', '^bsCollapse'], + // scope: true, + link: function postLink(scope, element, attrs, controllers) { + + var ngModelCtrl = controllers[0]; + var bsCollapseCtrl = controllers[1]; + + // Add base class + element.addClass('collapse'); + + // Add animation class + if(bsCollapseCtrl.$options.animation) { + element.addClass(bsCollapseCtrl.$options.animation); + } + + // Push pane to parent bsCollapse controller + bsCollapseCtrl.$registerTarget(element); + + // remove pane target from collapse controller when target is destroyed + scope.$on('$destroy', function() { + bsCollapseCtrl.$unregisterTarget(element); + }); + + function render() { + var index = bsCollapseCtrl.$targets.indexOf(element); + var active = bsCollapseCtrl.$activeIndexes(); + var action = 'removeClass'; + if (angular.isArray(active)) { + if (active.indexOf(index) !== -1) { + action = 'addClass'; + } + } + else if (index === active) { + action = 'addClass'; + } + + $animate[action](element, bsCollapseCtrl.$options.activeClass); + } + + bsCollapseCtrl.$viewChangeListeners.push(function() { + render(); + }); + render(); + + } + }; + + }]); + +// Source: datepicker.js +angular.module('mgcrea.ngStrap.datepicker', [ + 'mgcrea.ngStrap.helpers.dateParser', + 'mgcrea.ngStrap.helpers.dateFormatter', + 'mgcrea.ngStrap.tooltip']) + + .provider('$datepicker', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + prefixClass: 'datepicker', + placement: 'bottom-left', + template: 'datepicker/datepicker.tpl.html', + trigger: 'focus', + container: false, + keyboard: true, + html: false, + delay: 0, + // lang: $locale.id, + useNative: false, + dateType: 'date', + dateFormat: 'shortDate', + modelDateFormat: null, + dayFormat: 'dd', + monthFormat: 'MMM', + yearFormat: 'yyyy', + monthTitleFormat: 'MMMM yyyy', + yearTitleFormat: 'yyyy', + strictFormat: false, + autoclose: false, + minDate: -Infinity, + maxDate: +Infinity, + startView: 0, + minView: 0, + startWeek: 0, + daysOfWeekDisabled: '', + iconLeft: 'glyphicon glyphicon-chevron-left', + iconRight: 'glyphicon glyphicon-chevron-right' + }; + + this.$get = ["$window", "$document", "$rootScope", "$sce", "$dateFormatter", "datepickerViews", "$tooltip", "$timeout", function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) { + + var bodyEl = angular.element($window.document.body); + var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent); + var isTouch = ('createTouch' in $window.document) && isNative; + if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale(); + + function DatepickerFactory(element, controller, config) { + + var $datepicker = $tooltip(element, angular.extend({}, defaults, config)); + var parentScope = config.scope; + var options = $datepicker.$options; + var scope = $datepicker.$scope; + if(options.startView) options.startView -= options.minView; + + // View vars + + var pickerViews = datepickerViews($datepicker); + $datepicker.$views = pickerViews.views; + var viewDate = pickerViews.viewDate; + scope.$mode = options.startView; + scope.$iconLeft = options.iconLeft; + scope.$iconRight = options.iconRight; + var $picker = $datepicker.$views[scope.$mode]; + + // Scope methods + + scope.$select = function(date) { + $datepicker.select(date); + }; + scope.$selectPane = function(value) { + $datepicker.$selectPane(value); + }; + scope.$toggleMode = function() { + $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length); + }; + + // Public methods + + $datepicker.update = function(date) { + // console.warn('$datepicker.update() newValue=%o', date); + if(angular.isDate(date) && !isNaN(date.getTime())) { + $datepicker.$date = date; + $picker.update.call($picker, date); + } + // Build only if pristine + $datepicker.$build(true); + }; + + $datepicker.updateDisabledDates = function(dateRanges) { + options.disabledDateRanges = dateRanges; + for(var i = 0, l = scope.rows.length; i < l; i++) { + angular.forEach(scope.rows[i], $datepicker.$setDisabledEl); + } + }; + + $datepicker.select = function(date, keep) { + // console.warn('$datepicker.select', date, scope.$mode); + if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date); + if(!scope.$mode || keep) { + controller.$setViewValue(angular.copy(date)); + controller.$render(); + if(options.autoclose && !keep) { + $timeout(function() { $datepicker.hide(true); }); + } + } else { + angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()}); + $datepicker.setMode(scope.$mode - 1); + $datepicker.$build(); + } + }; + + $datepicker.setMode = function(mode) { + // console.warn('$datepicker.setMode', mode); + scope.$mode = mode; + $picker = $datepicker.$views[scope.$mode]; + $datepicker.$build(); + }; + + // Protected methods + + $datepicker.$build = function(pristine) { + // console.warn('$datepicker.$build() viewDate=%o', viewDate); + if(pristine === true && $picker.built) return; + if(pristine === false && !$picker.built) return; + $picker.build.call($picker); + }; + + $datepicker.$updateSelected = function() { + for(var i = 0, l = scope.rows.length; i < l; i++) { + angular.forEach(scope.rows[i], updateSelected); + } + }; + + $datepicker.$isSelected = function(date) { + return $picker.isSelected(date); + }; + + $datepicker.$setDisabledEl = function(el) { + el.disabled = $picker.isDisabled(el.date); + }; + + $datepicker.$selectPane = function(value) { + var steps = $picker.steps; + // set targetDate to first day of month to avoid problems with + // date values rollover. This assumes the viewDate does not + // depend on the day of the month + var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1)); + angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()}); + $datepicker.$build(); + }; + + $datepicker.$onMouseDown = function(evt) { + // Prevent blur on mousedown on .dropdown-menu + evt.preventDefault(); + evt.stopPropagation(); + // Emulate click for mobile devices + if(isTouch) { + var targetEl = angular.element(evt.target); + if(targetEl[0].nodeName.toLowerCase() !== 'button') { + targetEl = targetEl.parent(); + } + targetEl.triggerHandler('click'); + } + }; + + $datepicker.$onKeyDown = function(evt) { + if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return; + evt.preventDefault(); + evt.stopPropagation(); + + if(evt.keyCode === 13) { + if(!scope.$mode) { + return $datepicker.hide(true); + } else { + return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); }); + } + } + + // Navigate with keyboard + $picker.onKeyDown(evt); + parentScope.$digest(); + }; + + // Private + + function updateSelected(el) { + el.selected = $datepicker.$isSelected(el.date); + } + + function focusElement() { + element[0].focus(); + } + + // Overrides + + var _init = $datepicker.init; + $datepicker.init = function() { + if(isNative && options.useNative) { + element.prop('type', 'date'); + element.css('-webkit-appearance', 'textfield'); + return; + } else if(isTouch) { + element.prop('type', 'text'); + element.attr('readonly', 'true'); + element.on('click', focusElement); + } + _init(); + }; + + var _destroy = $datepicker.destroy; + $datepicker.destroy = function() { + if(isNative && options.useNative) { + element.off('click', focusElement); + } + _destroy(); + }; + + var _show = $datepicker.show; + $datepicker.show = function() { + _show(); + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. + $timeout(function() { + // if $datepicker is no longer showing, don't setup events + if(!$datepicker.$isShown) return; + $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown); + if(options.keyboard) { + element.on('keydown', $datepicker.$onKeyDown); + } + }, 0, false); + }; + + var _hide = $datepicker.hide; + $datepicker.hide = function(blur) { + if(!$datepicker.$isShown) return; + $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown); + if(options.keyboard) { + element.off('keydown', $datepicker.$onKeyDown); + } + _hide(blur); + }; + + return $datepicker; + + } + + DatepickerFactory.defaults = defaults; + return DatepickerFactory; + + }]; + + }) + + .directive('bsDatepicker', ["$window", "$parse", "$q", "$dateFormatter", "$dateParser", "$datepicker", function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) { + + var defaults = $datepicker.defaults; + var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent); + + return { + restrict: 'EAC', + require: 'ngModel', + link: function postLink(scope, element, attr, controller) { + + // Directive options + var options = {scope: scope, controller: controller}; + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'dateType', 'dateFormat', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled', 'id'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Visibility binding support + attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) { + if(!datepicker || !angular.isDefined(newValue)) return; + if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i); + newValue === true ? datepicker.show() : datepicker.hide(); + }); + + // Initialize datepicker + var datepicker = $datepicker(element, controller, options); + options = datepicker.$options; + // Set expected iOS format + if(isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd'; + + var lang = options.lang; + + var formatDate = function(date, format) { + return $dateFormatter.formatDate(date, format, lang); + }; + + var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat}); + + // Observe attributes for changes + angular.forEach(['minDate', 'maxDate'], function(key) { + // console.warn('attr.$observe(%s)', key, attr[key]); + angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) { + // console.warn('attr.$observe(%s)=%o', key, newValue); + datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue); + // Build only if dirty + !isNaN(datepicker.$options[key]) && datepicker.$build(false); + validateAgainstMinMaxDate(controller.$dateValue); + }); + }); + + // Watch model for changes + scope.$watch(attr.ngModel, function(newValue, oldValue) { + datepicker.update(controller.$dateValue); + }, true); + + // Normalize undefined/null/empty array, + // so that we don't treat changing from undefined->null as a change. + function normalizeDateRanges(ranges) { + if (!ranges || !ranges.length) return null; + return ranges; + } + + if (angular.isDefined(attr.disabledDates)) { + scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) { + disabledRanges = normalizeDateRanges(disabledRanges); + previousValue = normalizeDateRanges(previousValue); + + if (disabledRanges) { + datepicker.updateDisabledDates(disabledRanges); + } + }); + } + + function validateAgainstMinMaxDate(parsedDate) { + if (!angular.isDate(parsedDate)) return; + var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate; + var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate; + var isValid = isMinValid && isMaxValid; + controller.$setValidity('date', isValid); + controller.$setValidity('min', isMinValid); + controller.$setValidity('max', isMaxValid); + // Only update the model when we have a valid date + if(isValid) controller.$dateValue = parsedDate; + } + + // viewValue -> $parsers -> modelValue + controller.$parsers.unshift(function(viewValue) { + // console.warn('$parser("%s"): viewValue=%o', element.attr('ng-model'), viewValue); + // Null values should correctly reset the model value & validity + if(!viewValue) { + controller.$setValidity('date', true); + // BREAKING CHANGE: + // return null (not undefined) when input value is empty, so angularjs 1.3 + // ngModelController can go ahead and run validators, like ngRequired + return null; + } + var parsedDate = dateParser.parse(viewValue, controller.$dateValue); + if(!parsedDate || isNaN(parsedDate.getTime())) { + controller.$setValidity('date', false); + // return undefined, causes ngModelController to + // invalidate model value + return; + } else { + validateAgainstMinMaxDate(parsedDate); + } + if(options.dateType === 'string') { + return formatDate(parsedDate, options.modelDateFormat || options.dateFormat); + } else if(options.dateType === 'number') { + return controller.$dateValue.getTime(); + } else if(options.dateType === 'unix') { + return controller.$dateValue.getTime() / 1000; + } else if(options.dateType === 'iso') { + return controller.$dateValue.toISOString(); + } else { + return new Date(controller.$dateValue); + } + }); + + // modelValue -> $formatters -> viewValue + controller.$formatters.push(function(modelValue) { + // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue); + var date; + if(angular.isUndefined(modelValue) || modelValue === null) { + date = NaN; + } else if(angular.isDate(modelValue)) { + date = modelValue; + } else if(options.dateType === 'string') { + date = dateParser.parse(modelValue, null, options.modelDateFormat); + } else if(options.dateType === 'unix') { + date = new Date(modelValue * 1000); + } else { + date = new Date(modelValue); + } + // Setup default value? + // if(isNaN(date.getTime())) { + // var today = new Date(); + // date = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0); + // } + controller.$dateValue = date; + return getDateFormattedString(); + }); + + // viewValue -> element + controller.$render = function() { + // console.warn('$render("%s"): viewValue=%o', element.attr('ng-model'), controller.$viewValue); + element.val(getDateFormattedString()); + }; + + function getDateFormattedString() { + return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat); + } + + // Garbage collection + scope.$on('$destroy', function() { + if(datepicker) datepicker.destroy(); + options = null; + datepicker = null; + }); + + } + }; + + }]) + + .provider('datepickerViews', function() { + + var defaults = this.defaults = { + dayFormat: 'dd', + daySplit: 7 + }; + + // Split array into smaller arrays + function split(arr, size) { + var arrays = []; + while(arr.length > 0) { + arrays.push(arr.splice(0, size)); + } + return arrays; + } + + // Modulus operator + function mod(n, m) { + return ((n % m) + m) % m; + } + + this.$get = ["$dateFormatter", "$dateParser", "$sce", function($dateFormatter, $dateParser, $sce) { + + return function(picker) { + + var scope = picker.$scope; + var options = picker.$options; + + var lang = options.lang; + var formatDate = function(date, format) { + return $dateFormatter.formatDate(date, format, lang); + }; + var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat}); + + var weekDaysMin = $dateFormatter.weekdaysShort(lang); + var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek)); + var weekDaysLabelsHtml = $sce.trustAsHtml('' + weekDaysLabels.join('') + ''); + + var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date()); + var viewDate = {year: startDate.getFullYear(), month: startDate.getMonth(), date: startDate.getDate()}; + var timezoneOffset = startDate.getTimezoneOffset() * 6e4; + + var views = [{ + format: options.dayFormat, + split: 7, + steps: { month: 1 }, + update: function(date, force) { + if(!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) { + angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()}); + picker.$build(); + } else if(date.getDate() !== viewDate.date) { + viewDate.date = picker.$date.getDate(); + picker.$updateSelected(); + } + }, + build: function() { + var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1), firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset(); + var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5), firstDateOffset = firstDate.getTimezoneOffset(); + var today = new Date().toDateString(); + // Handle daylight time switch + if(firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 60e3); + var days = [], day; + for(var i = 0; i < 42; i++) { // < 7 * 6 + day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i)); + days.push({date: day, isToday: day.toDateString() === today, label: formatDate(day, this.format), selected: picker.$date && this.isSelected(day), muted: day.getMonth() !== viewDate.month, disabled: this.isDisabled(day)}); + } + scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat); + scope.showLabels = true; + scope.labels = weekDaysLabelsHtml; + scope.rows = split(days, this.split); + this.built = true; + }, + isSelected: function(date) { + return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate(); + }, + isDisabled: function(date) { + var time = date.getTime(); + + // Disabled because of min/max date. + if (time < options.minDate || time > options.maxDate) return true; + + // Disabled due to being a disabled day of the week + if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true; + + // Disabled because of disabled date range. + if (options.disabledDateRanges) { + for (var i = 0; i < options.disabledDateRanges.length; i++) { + if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) { + return true; + } + } + } + + return false; + }, + onKeyDown: function(evt) { + if (!picker.$date) { + return; + } + var actualTime = picker.$date.getTime(); + var newDate; + + if(evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5); + else if(evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5); + else if(evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5); + else if(evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5); + + if (!this.isDisabled(newDate)) picker.select(newDate, true); + } + }, { + name: 'month', + format: options.monthFormat, + split: 4, + steps: { year: 1 }, + update: function(date, force) { + if(!this.built || date.getFullYear() !== viewDate.year) { + angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()}); + picker.$build(); + } else if(date.getMonth() !== viewDate.month) { + angular.extend(viewDate, {month: picker.$date.getMonth(), date: picker.$date.getDate()}); + picker.$updateSelected(); + } + }, + build: function() { + var firstMonth = new Date(viewDate.year, 0, 1); + var months = [], month; + for (var i = 0; i < 12; i++) { + month = new Date(viewDate.year, i, 1); + months.push({date: month, label: formatDate(month, this.format), selected: picker.$isSelected(month), disabled: this.isDisabled(month)}); + } + scope.title = formatDate(month, options.yearTitleFormat); + scope.showLabels = false; + scope.rows = split(months, this.split); + this.built = true; + }, + isSelected: function(date) { + return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth(); + }, + isDisabled: function(date) { + var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0); + return lastDate < options.minDate || date.getTime() > options.maxDate; + }, + onKeyDown: function(evt) { + if (!picker.$date) { + return; + } + var actualMonth = picker.$date.getMonth(); + var newDate = new Date(picker.$date); + + if(evt.keyCode === 37) newDate.setMonth(actualMonth - 1); + else if(evt.keyCode === 38) newDate.setMonth(actualMonth - 4); + else if(evt.keyCode === 39) newDate.setMonth(actualMonth + 1); + else if(evt.keyCode === 40) newDate.setMonth(actualMonth + 4); + + if (!this.isDisabled(newDate)) picker.select(newDate, true); + } + }, { + name: 'year', + format: options.yearFormat, + split: 4, + steps: { year: 12 }, + update: function(date, force) { + if(!this.built || force || parseInt(date.getFullYear()/20, 10) !== parseInt(viewDate.year/20, 10)) { + angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()}); + picker.$build(); + } else if(date.getFullYear() !== viewDate.year) { + angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()}); + picker.$updateSelected(); + } + }, + build: function() { + var firstYear = viewDate.year - viewDate.year % (this.split * 3); + var years = [], year; + for (var i = 0; i < 12; i++) { + year = new Date(firstYear + i, 0, 1); + years.push({date: year, label: formatDate(year, this.format), selected: picker.$isSelected(year), disabled: this.isDisabled(year)}); + } + scope.title = years[0].label + '-' + years[years.length - 1].label; + scope.showLabels = false; + scope.rows = split(years, this.split); + this.built = true; + }, + isSelected: function(date) { + return picker.$date && date.getFullYear() === picker.$date.getFullYear(); + }, + isDisabled: function(date) { + var lastDate = +new Date(date.getFullYear() + 1, 0, 0); + return lastDate < options.minDate || date.getTime() > options.maxDate; + }, + onKeyDown: function(evt) { + if (!picker.$date) { + return; + } + var actualYear = picker.$date.getFullYear(), + newDate = new Date(picker.$date); + + if(evt.keyCode === 37) newDate.setYear(actualYear - 1); + else if(evt.keyCode === 38) newDate.setYear(actualYear - 4); + else if(evt.keyCode === 39) newDate.setYear(actualYear + 1); + else if(evt.keyCode === 40) newDate.setYear(actualYear + 4); + + if (!this.isDisabled(newDate)) picker.select(newDate, true); + } + }]; + + return { + views: options.minView ? Array.prototype.slice.call(views, options.minView) : views, + viewDate: viewDate + }; + + }; + + }]; + + }); + +// Source: dropdown.js +angular.module('mgcrea.ngStrap.dropdown', ['mgcrea.ngStrap.tooltip']) + + .provider('$dropdown', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + prefixClass: 'dropdown', + placement: 'bottom-left', + template: 'dropdown/dropdown.tpl.html', + trigger: 'click', + container: false, + keyboard: true, + html: false, + delay: 0 + }; + + this.$get = ["$window", "$rootScope", "$tooltip", "$timeout", function($window, $rootScope, $tooltip, $timeout) { + + var bodyEl = angular.element($window.document.body); + var matchesSelector = Element.prototype.matchesSelector || Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector; + + function DropdownFactory(element, config) { + + var $dropdown = {}; + + // Common vars + var options = angular.extend({}, defaults, config); + var scope = $dropdown.$scope = options.scope && options.scope.$new() || $rootScope.$new(); + + $dropdown = $tooltip(element, options); + var parentEl = element.parent(); + + // Protected methods + + $dropdown.$onKeyDown = function(evt) { + if (!/(38|40)/.test(evt.keyCode)) return; + evt.preventDefault(); + evt.stopPropagation(); + + // Retrieve focused index + var items = angular.element($dropdown.$element[0].querySelectorAll('li:not(.divider) a')); + if(!items.length) return; + var index; + angular.forEach(items, function(el, i) { + if(matchesSelector && matchesSelector.call(el, ':focus')) index = i; + }); + + // Navigate with keyboard + if(evt.keyCode === 38 && index > 0) index--; + else if(evt.keyCode === 40 && index < items.length - 1) index++; + else if(angular.isUndefined(index)) index = 0; + items.eq(index)[0].focus(); + + }; + + // Overrides + + var show = $dropdown.show; + $dropdown.show = function() { + show(); + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. + $timeout(function() { + options.keyboard && $dropdown.$element.on('keydown', $dropdown.$onKeyDown); + bodyEl.on('click', onBodyClick); + }, 0, false); + parentEl.hasClass('dropdown') && parentEl.addClass('open'); + }; + + var hide = $dropdown.hide; + $dropdown.hide = function() { + if(!$dropdown.$isShown) return; + options.keyboard && $dropdown.$element.off('keydown', $dropdown.$onKeyDown); + bodyEl.off('click', onBodyClick); + parentEl.hasClass('dropdown') && parentEl.removeClass('open'); + hide(); + }; + + var destroy = $dropdown.destroy; + $dropdown.destroy = function() { + bodyEl.off('click', onBodyClick); + destroy(); + }; + + // Private functions + + function onBodyClick(evt) { + if(evt.target === element[0]) return; + return evt.target !== element[0] && $dropdown.hide(); + } + + return $dropdown; + + } + + return DropdownFactory; + + }]; + + }) + + .directive('bsDropdown', ["$window", "$sce", "$dropdown", function($window, $sce, $dropdown) { + + return { + restrict: 'EAC', + scope: true, + link: function postLink(scope, element, attr, transclusion) { + + // Directive options + var options = {scope: scope}; + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'id'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Support scope as an object + attr.bsDropdown && scope.$watch(attr.bsDropdown, function(newValue, oldValue) { + scope.content = newValue; + }, true); + + // Visibility binding support + attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) { + if(!dropdown || !angular.isDefined(newValue)) return; + if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(dropdown),?/i); + newValue === true ? dropdown.show() : dropdown.hide(); + }); + + // Initialize dropdown + var dropdown = $dropdown(element, options); + + // Garbage collection + scope.$on('$destroy', function() { + if (dropdown) dropdown.destroy(); + options = null; + dropdown = null; + }); + + } + }; + + }]); + +// Source: date-formatter.js +angular.module('mgcrea.ngStrap.helpers.dateFormatter', []) + + .service('$dateFormatter', ["$locale", "dateFilter", function($locale, dateFilter) { + + // The unused `lang` arguments are on purpose. The default implementation does not + // use them and it always uses the locale loaded into the `$locale` service. + // Custom implementations might use it, thus allowing different directives to + // have different languages. + + this.getDefaultLocale = function() { + return $locale.id; + }; + + // Format is either a data format name, e.g. "shortTime" or "fullDate", or a date format + // Return either the corresponding date format or the given date format. + this.getDatetimeFormat = function(format, lang) { + return $locale.DATETIME_FORMATS[format] || format; + }; + + this.weekdaysShort = function(lang) { + return $locale.DATETIME_FORMATS.SHORTDAY; + }; + + function splitTimeFormat(format) { + return /(h+)([:\.])?(m+)[ ]?(a?)/i.exec(format).slice(1); + } + + // h:mm a => h + this.hoursFormat = function(timeFormat) { + return splitTimeFormat(timeFormat)[0]; + }; + + // h:mm a => mm + this.minutesFormat = function(timeFormat) { + return splitTimeFormat(timeFormat)[2]; + }; + + // h:mm a => : + this.timeSeparator = function(timeFormat) { + return splitTimeFormat(timeFormat)[1]; + }; + + // h:mm a => true, H.mm => false + this.showAM = function(timeFormat) { + return !!splitTimeFormat(timeFormat)[3]; + }; + + this.formatDate = function(date, format, lang){ + return dateFilter(date, format); + }; + + }]); + +// Source: date-parser.js +angular.module('mgcrea.ngStrap.helpers.dateParser', []) + +.provider('$dateParser', ["$localeProvider", function($localeProvider) { + + // define a custom ParseDate object to use instead of native Date + // to avoid date values wrapping when setting date component values + function ParseDate() { + this.year = 1970; + this.month = 0; + this.day = 1; + this.hours = 0; + this.minutes = 0; + this.seconds = 0; + this.milliseconds = 0; + } + + ParseDate.prototype.setMilliseconds = function(value) { this.milliseconds = value; }; + ParseDate.prototype.setSeconds = function(value) { this.seconds = value; }; + ParseDate.prototype.setMinutes = function(value) { this.minutes = value; }; + ParseDate.prototype.setHours = function(value) { this.hours = value; }; + ParseDate.prototype.getHours = function() { return this.hours; }; + ParseDate.prototype.setDate = function(value) { this.day = value; }; + ParseDate.prototype.setMonth = function(value) { this.month = value; }; + ParseDate.prototype.setFullYear = function(value) { this.year = value; }; + ParseDate.prototype.fromDate = function(value) { + this.year = value.getFullYear(); + this.month = value.getMonth(); + this.day = value.getDate(); + this.hours = value.getHours(); + this.minutes = value.getMinutes(); + this.seconds = value.getSeconds(); + this.milliseconds = value.getMilliseconds(); + return this; + }; + + ParseDate.prototype.toDate = function() { + return new Date(this.year, this.month, this.day, this.hours, this.minutes, this.seconds, this.milliseconds); + }; + + var proto = ParseDate.prototype; + + function noop() { + } + + function isNumeric(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + } + + function indexOfCaseInsensitive(array, value) { + var len = array.length, str=value.toString().toLowerCase(); + for (var i=0; i 12 when midnight changeover, but then cannot generate + * midnight datetime, so jump to 1AM, otherwise reset. + * @param date (Date) the date to check + * @return (Date) the corrected date + * + * __ copied from jquery ui datepicker __ + */ + $dateParser.daylightSavingAdjust = function(date) { + if (!date) { + return null; + } + date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); + return date; + }; + + // Private functions + + function setMapForFormat(format) { + var keys = Object.keys(setFnMap), i; + var map = [], sortedMap = []; + // Map to setFn + var clonedFormat = format; + for(i = 0; i < keys.length; i++) { + if(format.split(keys[i]).length > 1) { + var index = clonedFormat.search(keys[i]); + format = format.split(keys[i]).join(''); + if(setFnMap[keys[i]]) { + map[index] = setFnMap[keys[i]]; + } + } + } + // Sort result map + angular.forEach(map, function(v) { + // conditional required since angular.forEach broke around v1.2.21 + // related pr: https://github.com/angular/angular.js/pull/8525 + if(v) sortedMap.push(v); + }); + return sortedMap; + } + + function escapeReservedSymbols(text) { + return text.replace(/\//g, '[\\/]').replace('/-/g', '[-]').replace(/\./g, '[.]').replace(/\\s/g, '[\\s]'); + } + + function regExpForFormat(format) { + var keys = Object.keys(regExpMap), i; + + var re = format; + // Abstract replaces to avoid collisions + for(i = 0; i < keys.length; i++) { + re = re.split(keys[i]).join('${' + i + '}'); + } + // Replace abstracted values + for(i = 0; i < keys.length; i++) { + re = re.split('${' + i + '}').join('(' + regExpMap[keys[i]] + ')'); + } + format = escapeReservedSymbols(format); + + return new RegExp('^' + re + '$', ['i']); + } + + $dateParser.init(); + return $dateParser; + + }; + + return DateParserFactory; + + }]; + +}]); + +// Source: debounce.js +angular.module('mgcrea.ngStrap.helpers.debounce', []) + +// @source jashkenas/underscore +// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L693 +.factory('debounce', ["$timeout", function($timeout) { + return function(func, wait, immediate) { + var timeout = null; + return function() { + var context = this, + args = arguments, + callNow = immediate && !timeout; + if(timeout) { + $timeout.cancel(timeout); + } + timeout = $timeout(function later() { + timeout = null; + if(!immediate) { + func.apply(context, args); + } + }, wait, false); + if(callNow) { + func.apply(context, args); + } + return timeout; + }; + }; +}]) + + +// @source jashkenas/underscore +// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L661 +.factory('throttle', ["$timeout", function($timeout) { + return function(func, wait, options) { + var timeout = null; + options || (options = {}); + return function() { + var context = this, + args = arguments; + if(!timeout) { + if(options.leading !== false) { + func.apply(context, args); + } + timeout = $timeout(function later() { + timeout = null; + if(options.trailing !== false) { + func.apply(context, args); + } + }, wait, false); + } + }; + }; +}]); + +// Source: dimensions.js +angular.module('mgcrea.ngStrap.helpers.dimensions', []) + + .factory('dimensions', ["$document", "$window", function($document, $window) { + + var jqLite = angular.element; + var fn = {}; + + /** + * Test the element nodeName + * @param element + * @param name + */ + var nodeName = fn.nodeName = function(element, name) { + return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase(); + }; + + /** + * Returns the element computed style + * @param element + * @param prop + * @param extra + */ + fn.css = function(element, prop, extra) { + var value; + if (element.currentStyle) { //IE + value = element.currentStyle[prop]; + } else if (window.getComputedStyle) { + value = window.getComputedStyle(element)[prop]; + } else { + value = element.style[prop]; + } + return extra === true ? parseFloat(value) || 0 : value; + }; + + /** + * Provides read-only equivalent of jQuery's offset function: + * @required-by bootstrap-tooltip, bootstrap-affix + * @url http://api.jquery.com/offset/ + * @param element + */ + fn.offset = function(element) { + var boxRect = element.getBoundingClientRect(); + var docElement = element.ownerDocument; + return { + width: boxRect.width || element.offsetWidth, + height: boxRect.height || element.offsetHeight, + top: boxRect.top + (window.pageYOffset || docElement.documentElement.scrollTop) - (docElement.documentElement.clientTop || 0), + left: boxRect.left + (window.pageXOffset || docElement.documentElement.scrollLeft) - (docElement.documentElement.clientLeft || 0) + }; + }; + + /** + * Provides read-only equivalent of jQuery's position function + * @required-by bootstrap-tooltip, bootstrap-affix + * @url http://api.jquery.com/offset/ + * @param element + */ + fn.position = function(element) { + + var offsetParentRect = {top: 0, left: 0}, + offsetParentElement, + offset; + + // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent + if (fn.css(element, 'position') === 'fixed') { + + // We assume that getBoundingClientRect is available when computed position is fixed + offset = element.getBoundingClientRect(); + + } else { + + // Get *real* offsetParentElement + offsetParentElement = offsetParent(element); + + // Get correct offsets + offset = fn.offset(element); + if (!nodeName(offsetParentElement, 'html')) { + offsetParentRect = fn.offset(offsetParentElement); + } + + // Add offsetParent borders + offsetParentRect.top += fn.css(offsetParentElement, 'borderTopWidth', true); + offsetParentRect.left += fn.css(offsetParentElement, 'borderLeftWidth', true); + } + + // Subtract parent offsets and element margins + return { + width: element.offsetWidth, + height: element.offsetHeight, + top: offset.top - offsetParentRect.top - fn.css(element, 'marginTop', true), + left: offset.left - offsetParentRect.left - fn.css(element, 'marginLeft', true) + }; + + }; + + /** + * Returns the closest, non-statically positioned offsetParent of a given element + * @required-by fn.position + * @param element + */ + var offsetParent = function offsetParentElement(element) { + var docElement = element.ownerDocument; + var offsetParent = element.offsetParent || docElement; + if(nodeName(offsetParent, '#document')) return docElement.documentElement; + while(offsetParent && !nodeName(offsetParent, 'html') && fn.css(offsetParent, 'position') === 'static') { + offsetParent = offsetParent.offsetParent; + } + return offsetParent || docElement.documentElement; + }; + + /** + * Provides equivalent of jQuery's height function + * @required-by bootstrap-affix + * @url http://api.jquery.com/height/ + * @param element + * @param outer + */ + fn.height = function(element, outer) { + var value = element.offsetHeight; + if(outer) { + value += fn.css(element, 'marginTop', true) + fn.css(element, 'marginBottom', true); + } else { + value -= fn.css(element, 'paddingTop', true) + fn.css(element, 'paddingBottom', true) + fn.css(element, 'borderTopWidth', true) + fn.css(element, 'borderBottomWidth', true); + } + return value; + }; + + /** + * Provides equivalent of jQuery's width function + * @required-by bootstrap-affix + * @url http://api.jquery.com/width/ + * @param element + * @param outer + */ + fn.width = function(element, outer) { + var value = element.offsetWidth; + if(outer) { + value += fn.css(element, 'marginLeft', true) + fn.css(element, 'marginRight', true); + } else { + value -= fn.css(element, 'paddingLeft', true) + fn.css(element, 'paddingRight', true) + fn.css(element, 'borderLeftWidth', true) + fn.css(element, 'borderRightWidth', true); + } + return value; + }; + + return fn; + + }]); + +// Source: parse-options.js +angular.module('mgcrea.ngStrap.helpers.parseOptions', []) + + .provider('$parseOptions', function() { + + var defaults = this.defaults = { + regexp: /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/ + }; + + this.$get = ["$parse", "$q", function($parse, $q) { + + function ParseOptionsFactory(attr, config) { + + var $parseOptions = {}; + + // Common vars + var options = angular.extend({}, defaults, config); + $parseOptions.$values = []; + + // Private vars + var match, displayFn, valueName, keyName, groupByFn, valueFn, valuesFn; + + $parseOptions.init = function() { + $parseOptions.$match = match = attr.match(options.regexp); + displayFn = $parse(match[2] || match[1]), + valueName = match[4] || match[6], + keyName = match[5], + groupByFn = $parse(match[3] || ''), + valueFn = $parse(match[2] ? match[1] : valueName), + valuesFn = $parse(match[7]); + }; + + $parseOptions.valuesFn = function(scope, controller) { + return $q.when(valuesFn(scope, controller)) + .then(function(values) { + $parseOptions.$values = values ? parseValues(values, scope) : {}; + return $parseOptions.$values; + }); + }; + + $parseOptions.displayValue = function(modelValue) { + var scope = {}; + scope[valueName] = modelValue; + return displayFn(scope); + }; + + // Private functions + + function parseValues(values, scope) { + return values.map(function(match, index) { + var locals = {}, label, value; + locals[valueName] = match; + label = displayFn(scope, locals); + value = valueFn(scope, locals); + return {label: label, value: value, index: index}; + }); + } + + $parseOptions.init(); + return $parseOptions; + + } + + return ParseOptionsFactory; + + }]; + + }); + +// Source: raf.js +(angular.version.minor < 3 && angular.version.dot < 14) && angular.module('ng') + +.factory('$$rAF', ["$window", "$timeout", function($window, $timeout) { + + var requestAnimationFrame = $window.requestAnimationFrame || + $window.webkitRequestAnimationFrame || + $window.mozRequestAnimationFrame; + + var cancelAnimationFrame = $window.cancelAnimationFrame || + $window.webkitCancelAnimationFrame || + $window.mozCancelAnimationFrame || + $window.webkitCancelRequestAnimationFrame; + + var rafSupported = !!requestAnimationFrame; + var raf = rafSupported ? + function(fn) { + var id = requestAnimationFrame(fn); + return function() { + cancelAnimationFrame(id); + }; + } : + function(fn) { + var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666 + return function() { + $timeout.cancel(timer); + }; + }; + + raf.supported = rafSupported; + + return raf; + +}]); + +// .factory('$$animateReflow', function($$rAF, $document) { + +// var bodyEl = $document[0].body; + +// return function(fn) { +// //the returned function acts as the cancellation function +// return $$rAF(function() { +// //the line below will force the browser to perform a repaint +// //so that all the animated elements within the animation frame +// //will be properly updated and drawn on screen. This is +// //required to perform multi-class CSS based animations with +// //Firefox. DO NOT REMOVE THIS LINE. +// var a = bodyEl.offsetWidth + 1; +// fn(); +// }); +// }; + +// }); + +// Source: modal.js +angular.module('mgcrea.ngStrap.modal', ['mgcrea.ngStrap.helpers.dimensions']) + + .provider('$modal', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + backdropAnimation: 'am-fade', + prefixClass: 'modal', + prefixEvent: 'modal', + placement: 'top', + template: 'modal/modal.tpl.html', + contentTemplate: false, + container: false, + element: null, + backdrop: true, + keyboard: true, + html: false, + show: true + }; + + this.$get = ["$window", "$rootScope", "$compile", "$q", "$templateCache", "$http", "$animate", "$timeout", "$sce", "dimensions", function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $timeout, $sce, dimensions) { + + var forEach = angular.forEach; + var trim = String.prototype.trim; + var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; + var bodyElement = angular.element($window.document.body); + var htmlReplaceRegExp = /ng-bind="/ig; + + function ModalFactory(config) { + + var $modal = {}; + + // Common vars + var options = $modal.$options = angular.extend({}, defaults, config); + $modal.$promise = fetchTemplate(options.template); + var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new(); + if(!options.element && !options.container) { + options.container = 'body'; + } + + // store $id to identify the triggering element in events + // give priority to options.id, otherwise, try to use + // element id if defined + $modal.$id = options.id || options.element && options.element.attr('id') || ''; + + // Support scope as string options + forEach(['title', 'content'], function(key) { + if(options[key]) scope[key] = $sce.trustAsHtml(options[key]); + }); + + // Provide scope helpers + scope.$hide = function() { + scope.$$postDigest(function() { + $modal.hide(); + }); + }; + scope.$show = function() { + scope.$$postDigest(function() { + $modal.show(); + }); + }; + scope.$toggle = function() { + scope.$$postDigest(function() { + $modal.toggle(); + }); + }; + // Publish isShown as a protected var on scope + $modal.$isShown = scope.$isShown = false; + + // Support contentTemplate option + if(options.contentTemplate) { + $modal.$promise = $modal.$promise.then(function(template) { + var templateEl = angular.element(template); + return fetchTemplate(options.contentTemplate) + .then(function(contentTemplate) { + var contentEl = findElement('[ng-bind="content"]', templateEl[0]).removeAttr('ng-bind').html(contentTemplate); + // Drop the default footer as you probably don't want it if you use a custom contentTemplate + if(!config.template) contentEl.next().remove(); + return templateEl[0].outerHTML; + }); + }); + } + + // Fetch, compile then initialize modal + var modalLinker, modalElement; + var backdropElement = angular.element('
    '); + $modal.$promise.then(function(template) { + if(angular.isObject(template)) template = template.data; + if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html="'); + template = trim.apply(template); + modalLinker = $compile(template); + $modal.init(); + }); + + $modal.init = function() { + + // Options: show + if(options.show) { + scope.$$postDigest(function() { + $modal.show(); + }); + } + + }; + + $modal.destroy = function() { + + // Remove element + if(modalElement) { + modalElement.remove(); + modalElement = null; + } + if(backdropElement) { + backdropElement.remove(); + backdropElement = null; + } + + // Destroy scope + scope.$destroy(); + + }; + + $modal.show = function() { + if($modal.$isShown) return; + + if(scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) { + return; + } + var parent, after; + if(angular.isElement(options.container)) { + parent = options.container; + after = options.container[0].lastChild ? angular.element(options.container[0].lastChild) : null; + } else { + if (options.container) { + parent = findElement(options.container); + after = parent[0].lastChild ? angular.element(parent[0].lastChild) : null; + } else { + parent = null; + after = options.element; + } + } + + // Fetch a cloned element linked from template + modalElement = $modal.$element = modalLinker(scope, function(clonedElement, scope) {}); + + // Set the initial positioning. + modalElement.css({display: 'block'}).addClass(options.placement); + + // Options: animation + if(options.animation) { + if(options.backdrop) { + backdropElement.addClass(options.backdropAnimation); + } + modalElement.addClass(options.animation); + } + + if(options.backdrop) { + $animate.enter(backdropElement, bodyElement, null); + } + // Support v1.3+ $animate + // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9 + var promise = $animate.enter(modalElement, parent, after, enterAnimateCallback); + if(promise && promise.then) promise.then(enterAnimateCallback); + + $modal.$isShown = scope.$isShown = true; + safeDigest(scope); + // Focus once the enter-animation has started + // Weird PhantomJS bug hack + var el = modalElement[0]; + requestAnimationFrame(function() { + el.focus(); + }); + + bodyElement.addClass(options.prefixClass + '-open'); + if(options.animation) { + bodyElement.addClass(options.prefixClass + '-with-' + options.animation); + } + + // Bind events + if(options.backdrop) { + modalElement.on('click', hideOnBackdropClick); + backdropElement.on('click', hideOnBackdropClick); + backdropElement.on('wheel', preventEventDefault); + } + if(options.keyboard) { + modalElement.on('keyup', $modal.$onKeyUp); + } + }; + + function enterAnimateCallback() { + scope.$emit(options.prefixEvent + '.show', $modal); + } + + $modal.hide = function() { + if(!$modal.$isShown) return; + + if(scope.$emit(options.prefixEvent + '.hide.before', $modal).defaultPrevented) { + return; + } + var promise = $animate.leave(modalElement, leaveAnimateCallback); + // Support v1.3+ $animate + // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9 + if(promise && promise.then) promise.then(leaveAnimateCallback); + + if(options.backdrop) { + $animate.leave(backdropElement); + } + $modal.$isShown = scope.$isShown = false; + safeDigest(scope); + + // Unbind events + if(options.backdrop) { + modalElement.off('click', hideOnBackdropClick); + backdropElement.off('click', hideOnBackdropClick); + backdropElement.off('wheel', preventEventDefault); + } + if(options.keyboard) { + modalElement.off('keyup', $modal.$onKeyUp); + } + }; + + function leaveAnimateCallback() { + scope.$emit(options.prefixEvent + '.hide', $modal); + bodyElement.removeClass(options.prefixClass + '-open'); + if(options.animation) { + bodyElement.removeClass(options.prefixClass + '-with-' + options.animation); + } + } + + $modal.toggle = function() { + + $modal.$isShown ? $modal.hide() : $modal.show(); + + }; + + $modal.focus = function() { + modalElement[0].focus(); + }; + + // Protected methods + + $modal.$onKeyUp = function(evt) { + + if (evt.which === 27 && $modal.$isShown) { + $modal.hide(); + evt.stopPropagation(); + } + + }; + + // Private methods + + function hideOnBackdropClick(evt) { + if(evt.target !== evt.currentTarget) return; + options.backdrop === 'static' ? $modal.focus() : $modal.hide(); + } + + function preventEventDefault(evt) { + evt.preventDefault(); + } + + return $modal; + + } + + // Helper functions + + function safeDigest(scope) { + scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest(); + } + + function findElement(query, element) { + return angular.element((element || document).querySelectorAll(query)); + } + + var fetchPromises = {}; + function fetchTemplate(template) { + if(fetchPromises[template]) return fetchPromises[template]; + return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template)) + .then(function(res) { + if(angular.isObject(res)) { + $templateCache.put(template, res.data); + return res.data; + } + return res; + })); + } + + return ModalFactory; + + }]; + + }) + + .directive('bsModal', ["$window", "$sce", "$modal", function($window, $sce, $modal) { + + return { + restrict: 'EAC', + scope: true, + link: function postLink(scope, element, attr, transclusion) { + + // Directive options + var options = {scope: scope, element: element, show: false}; + angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'id'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Support scope as data-attrs + angular.forEach(['title', 'content'], function(key) { + attr[key] && attr.$observe(key, function(newValue, oldValue) { + scope[key] = $sce.trustAsHtml(newValue); + }); + }); + + // Support scope as an object + attr.bsModal && scope.$watch(attr.bsModal, function(newValue, oldValue) { + if(angular.isObject(newValue)) { + angular.extend(scope, newValue); + } else { + scope.content = newValue; + } + }, true); + + // Initialize modal + var modal = $modal(options); + + // Trigger + element.on(attr.trigger || 'click', modal.toggle); + + // Garbage collection + scope.$on('$destroy', function() { + if (modal) modal.destroy(); + options = null; + modal = null; + }); + + } + }; + + }]); + +// Source: navbar.js +angular.module('mgcrea.ngStrap.navbar', []) + + .provider('$navbar', function() { + + var defaults = this.defaults = { + activeClass: 'active', + routeAttr: 'data-match-route', + strict: false + }; + + this.$get = function() { + return {defaults: defaults}; + }; + + }) + + .directive('bsNavbar', ["$window", "$location", "$navbar", function($window, $location, $navbar) { + + var defaults = $navbar.defaults; + + return { + restrict: 'A', + link: function postLink(scope, element, attr, controller) { + + // Directive options + var options = angular.copy(defaults); + angular.forEach(Object.keys(defaults), function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Watch for the $location + scope.$watch(function() { + + return $location.path(); + + }, function(newValue, oldValue) { + + var liElements = element[0].querySelectorAll('li[' + options.routeAttr + ']'); + + angular.forEach(liElements, function(li) { + + var liElement = angular.element(li); + var pattern = liElement.attr(options.routeAttr).replace('/', '\\/'); + if(options.strict) { + pattern = '^' + pattern + '$'; + } + var regexp = new RegExp(pattern, ['i']); + + if(regexp.test(newValue)) { + liElement.addClass(options.activeClass); + } else { + liElement.removeClass(options.activeClass); + } + + }); + + }); + + } + + }; + + }]); + +// Source: popover.js +angular.module('mgcrea.ngStrap.popover', ['mgcrea.ngStrap.tooltip']) + + .provider('$popover', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + customClass: '', + container: false, + target: false, + placement: 'right', + template: 'popover/popover.tpl.html', + contentTemplate: false, + trigger: 'click', + keyboard: true, + html: false, + title: '', + content: '', + delay: 0, + autoClose: false + }; + + this.$get = ["$tooltip", function($tooltip) { + + function PopoverFactory(element, config) { + + // Common vars + var options = angular.extend({}, defaults, config); + + var $popover = $tooltip(element, options); + + // Support scope as string options [/*title, */content] + if(options.content) { + $popover.$scope.content = options.content; + } + + return $popover; + + } + + return PopoverFactory; + + }]; + + }) + + .directive('bsPopover', ["$window", "$sce", "$popover", function($window, $sce, $popover) { + + var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; + + return { + restrict: 'EAC', + scope: true, + link: function postLink(scope, element, attr) { + + // Directive options + var options = {scope: scope}; + angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'customClass', 'autoClose', 'id'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Support scope as data-attrs + angular.forEach(['title', 'content'], function(key) { + attr[key] && attr.$observe(key, function(newValue, oldValue) { + scope[key] = $sce.trustAsHtml(newValue); + angular.isDefined(oldValue) && requestAnimationFrame(function() { + popover && popover.$applyPlacement(); + }); + }); + }); + + // Support scope as an object + attr.bsPopover && scope.$watch(attr.bsPopover, function(newValue, oldValue) { + if(angular.isObject(newValue)) { + angular.extend(scope, newValue); + } else { + scope.content = newValue; + } + angular.isDefined(oldValue) && requestAnimationFrame(function() { + popover && popover.$applyPlacement(); + }); + }, true); + + // Visibility binding support + attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) { + if(!popover || !angular.isDefined(newValue)) return; + if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(popover),?/i); + newValue === true ? popover.show() : popover.hide(); + }); + + // Initialize popover + var popover = $popover(element, options); + + // Garbage collection + scope.$on('$destroy', function() { + if (popover) popover.destroy(); + options = null; + popover = null; + }); + + } + }; + + }]); + +// Source: select.js +angular.module('mgcrea.ngStrap.select', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions']) + + .provider('$select', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + prefixClass: 'select', + prefixEvent: '$select', + placement: 'bottom-left', + template: 'select/select.tpl.html', + trigger: 'focus', + container: false, + keyboard: true, + html: false, + delay: 0, + multiple: false, + allNoneButtons: false, + sort: true, + caretHtml: ' ', + placeholder: 'Choose among the following...', + allText: 'All', + noneText: 'None', + maxLength: 3, + maxLengthHtml: 'selected', + iconCheckmark: 'glyphicon glyphicon-ok' + }; + + this.$get = ["$window", "$document", "$rootScope", "$tooltip", "$timeout", function($window, $document, $rootScope, $tooltip, $timeout) { + + var bodyEl = angular.element($window.document.body); + var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent); + var isTouch = ('createTouch' in $window.document) && isNative; + + function SelectFactory(element, controller, config) { + + var $select = {}; + + // Common vars + var options = angular.extend({}, defaults, config); + + $select = $tooltip(element, options); + var scope = $select.$scope; + + scope.$matches = []; + scope.$activeIndex = 0; + scope.$isMultiple = options.multiple; + scope.$showAllNoneButtons = options.allNoneButtons && options.multiple; + scope.$iconCheckmark = options.iconCheckmark; + scope.$allText = options.allText; + scope.$noneText = options.noneText; + + scope.$activate = function(index) { + scope.$$postDigest(function() { + $select.activate(index); + }); + }; + + scope.$select = function(index, evt) { + scope.$$postDigest(function() { + $select.select(index); + }); + }; + + scope.$isVisible = function() { + return $select.$isVisible(); + }; + + scope.$isActive = function(index) { + return $select.$isActive(index); + }; + + scope.$selectAll = function () { + for (var i = 0; i < scope.$matches.length; i++) { + if (!scope.$isActive(i)) { + scope.$select(i); + } + } + }; + + scope.$selectNone = function () { + for (var i = 0; i < scope.$matches.length; i++) { + if (scope.$isActive(i)) { + scope.$select(i); + } + } + }; + + // Public methods + + $select.update = function(matches) { + scope.$matches = matches; + $select.$updateActiveIndex(); + }; + + $select.activate = function(index) { + if(options.multiple) { + scope.$activeIndex.sort(); + $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index); + if(options.sort) scope.$activeIndex.sort(); + } else { + scope.$activeIndex = index; + } + return scope.$activeIndex; + }; + + $select.select = function(index) { + var value = scope.$matches[index].value; + scope.$apply(function() { + $select.activate(index); + if(options.multiple) { + controller.$setViewValue(scope.$activeIndex.map(function(index) { + return scope.$matches[index].value; + })); + } else { + controller.$setViewValue(value); + // Hide if single select + $select.hide(); + } + }); + // Emit event + scope.$emit(options.prefixEvent + '.select', value, index, $select); + }; + + // Protected methods + + $select.$updateActiveIndex = function() { + if(controller.$modelValue && scope.$matches.length) { + if(options.multiple && angular.isArray(controller.$modelValue)) { + scope.$activeIndex = controller.$modelValue.map(function(value) { + return $select.$getIndex(value); + }); + } else { + scope.$activeIndex = $select.$getIndex(controller.$modelValue); + } + } else if(scope.$activeIndex >= scope.$matches.length) { + scope.$activeIndex = options.multiple ? [] : 0; + } + }; + + $select.$isVisible = function() { + if(!options.minLength || !controller) { + return scope.$matches.length; + } + // minLength support + return scope.$matches.length && controller.$viewValue.length >= options.minLength; + }; + + $select.$isActive = function(index) { + if(options.multiple) { + return scope.$activeIndex.indexOf(index) !== -1; + } else { + return scope.$activeIndex === index; + } + }; + + $select.$getIndex = function(value) { + var l = scope.$matches.length, i = l; + if(!l) return; + for(i = l; i--;) { + if(scope.$matches[i].value === value) break; + } + if(i < 0) return; + return i; + }; + + $select.$onMouseDown = function(evt) { + // Prevent blur on mousedown on .dropdown-menu + evt.preventDefault(); + evt.stopPropagation(); + // Emulate click for mobile devices + if(isTouch) { + var targetEl = angular.element(evt.target); + targetEl.triggerHandler('click'); + } + }; + + $select.$onKeyDown = function(evt) { + if (!/(9|13|38|40)/.test(evt.keyCode)) return; + evt.preventDefault(); + evt.stopPropagation(); + + // Select with enter + if(!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) { + return $select.select(scope.$activeIndex); + } + + // Navigate with keyboard + if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--; + else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++; + else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0; + scope.$digest(); + }; + + // Overrides + + var _show = $select.show; + $select.show = function() { + _show(); + if(options.multiple) { + $select.$element.addClass('select-multiple'); + } + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. + $timeout(function() { + $select.$element.on(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown); + if(options.keyboard) { + element.on('keydown', $select.$onKeyDown); + } + }, 0, false); + }; + + var _hide = $select.hide; + $select.hide = function() { + $select.$element.off(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown); + if(options.keyboard) { + element.off('keydown', $select.$onKeyDown); + } + _hide(true); + }; + + return $select; + + } + + SelectFactory.defaults = defaults; + return SelectFactory; + + }]; + + }) + + .directive('bsSelect', ["$window", "$parse", "$q", "$select", "$parseOptions", function($window, $parse, $q, $select, $parseOptions) { + + var defaults = $select.defaults; + + return { + restrict: 'EAC', + require: 'ngModel', + link: function postLink(scope, element, attr, controller) { + + // Directive options + var options = {scope: scope, placeholder: defaults.placeholder}; + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'placeholder', 'multiple', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText', 'iconCheckmark', 'autoClose', 'id'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Add support for select markup + if(element[0].nodeName.toLowerCase() === 'select') { + var inputEl = element; + inputEl.css('display', 'none'); + element = angular.element(''); + inputEl.after(element); + } + + // Build proper ngOptions + var parsedOptions = $parseOptions(attr.ngOptions); + + // Initialize select + var select = $select(element, controller, options); + + // Watch ngOptions values before filtering for changes + var watchedOptions = parsedOptions.$match[7].replace(/\|.+/, '').trim(); + scope.$watch(watchedOptions, function(newValue, oldValue) { + // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue); + parsedOptions.valuesFn(scope, controller) + .then(function(values) { + select.update(values); + controller.$render(); + }); + }, true); + + // Watch model for changes + scope.$watch(attr.ngModel, function(newValue, oldValue) { + // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue); + select.$updateActiveIndex(); + controller.$render(); + }, true); + + // Model rendering in view + controller.$render = function () { + // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue); + var selected, index; + if(options.multiple && angular.isArray(controller.$modelValue)) { + selected = controller.$modelValue.map(function(value) { + index = select.$getIndex(value); + return angular.isDefined(index) ? select.$scope.$matches[index].label : false; + }).filter(angular.isDefined); + if(selected.length > (options.maxLength || defaults.maxLength)) { + selected = selected.length + ' ' + (options.maxLengthHtml || defaults.maxLengthHtml); + } else { + selected = selected.join(', '); + } + } else { + index = select.$getIndex(controller.$modelValue); + selected = angular.isDefined(index) ? select.$scope.$matches[index].label : false; + } + element.html((selected ? selected : options.placeholder) + defaults.caretHtml); + }; + + if(options.multiple){ + controller.$isEmpty = function(value){ + return !value || value.length === 0; + }; + } + + // Garbage collection + scope.$on('$destroy', function() { + if (select) select.destroy(); + options = null; + select = null; + }); + + } + }; + + }]); + +// Source: tab.js +angular.module('mgcrea.ngStrap.tab', []) + + .provider('$tab', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + template: 'tab/tab.tpl.html', + navClass: 'nav-tabs', + activeClass: 'active' + }; + + var controller = this.controller = function($scope, $element, $attrs) { + var self = this; + + // Attributes options + self.$options = angular.copy(defaults); + angular.forEach(['animation', 'navClass', 'activeClass'], function(key) { + if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key]; + }); + + // Publish options on scope + $scope.$navClass = self.$options.navClass; + $scope.$activeClass = self.$options.activeClass; + + self.$panes = $scope.$panes = []; + + // DEPRECATED: $viewChangeListeners, please use $activePaneChangeListeners + // Because we deprecated ngModel usage, we rename viewChangeListeners to + // activePaneChangeListeners to make more sense. + self.$activePaneChangeListeners = self.$viewChangeListeners = []; + + self.$push = function(pane) { + self.$panes.push(pane); + }; + + self.$remove = function(pane) { + var index = self.$panes.indexOf(pane); + var activeIndex = self.$panes.$active; + + // remove pane from $panes array + self.$panes.splice(index, 1); + + if (index < activeIndex) { + // we removed a pane before the active pane, so we need to + // decrement the active pane index + activeIndex--; + } + else if (index === activeIndex && activeIndex === self.$panes.length) { + // we remove the active pane and it was the one at the end, + // so select the previous one + activeIndex--; + } + self.$setActive(activeIndex); + }; + + self.$panes.$active = 0; + self.$setActive = $scope.$setActive = function(value) { + self.$panes.$active = value; + self.$activePaneChangeListeners.forEach(function(fn) { + fn(); + }); + }; + + }; + + this.$get = function() { + var $tab = {}; + $tab.defaults = defaults; + $tab.controller = controller; + return $tab; + }; + + }) + + .directive('bsTabs', ["$window", "$animate", "$tab", "$parse", function($window, $animate, $tab, $parse) { + + var defaults = $tab.defaults; + + return { + require: ['?ngModel', 'bsTabs'], + transclude: true, + scope: true, + controller: ['$scope', '$element', '$attrs', $tab.controller], + templateUrl: function(element, attr) { + return attr.template || defaults.template; + }, + link: function postLink(scope, element, attrs, controllers) { + + var ngModelCtrl = controllers[0]; + var bsTabsCtrl = controllers[1]; + + // DEPRECATED: ngModel, please use bsActivePane + // 'ngModel' is deprecated bacause if interferes with form validation + // and status, so avoid using it here. + if(ngModelCtrl) { + console.warn('Usage of ngModel is deprecated, please use bsActivePane instead!'); + + // Update the modelValue following + bsTabsCtrl.$activePaneChangeListeners.push(function() { + ngModelCtrl.$setViewValue(bsTabsCtrl.$panes.$active); + }); + + // modelValue -> $formatters -> viewValue + ngModelCtrl.$formatters.push(function(modelValue) { + // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue); + bsTabsCtrl.$setActive(modelValue * 1); + return modelValue; + }); + + } + + if (attrs.bsActivePane) { + // adapted from angularjs ngModelController bindings + // https://github.com/angular/angular.js/blob/v1.3.1/src%2Fng%2Fdirective%2Finput.js#L1730 + var parsedBsActivePane = $parse(attrs.bsActivePane); + + // Update bsActivePane value with change + bsTabsCtrl.$activePaneChangeListeners.push(function() { + parsedBsActivePane.assign(scope, bsTabsCtrl.$panes.$active); + }); + + // watch bsActivePane for value changes + scope.$watch(attrs.bsActivePane, function(newValue, oldValue) { + bsTabsCtrl.$setActive(newValue * 1); + }, true); + } + } + }; + + }]) + + .directive('bsPane', ["$window", "$animate", "$sce", function($window, $animate, $sce) { + + return { + require: ['^?ngModel', '^bsTabs'], + scope: true, + link: function postLink(scope, element, attrs, controllers) { + + var ngModelCtrl = controllers[0]; + var bsTabsCtrl = controllers[1]; + + // Add base class + element.addClass('tab-pane'); + + // Observe title attribute for change + attrs.$observe('title', function(newValue, oldValue) { + scope.title = $sce.trustAsHtml(newValue); + }); + + // Add animation class + if(bsTabsCtrl.$options.animation) { + element.addClass(bsTabsCtrl.$options.animation); + } + + // Push pane to parent bsTabs controller + bsTabsCtrl.$push(scope); + + // remove pane from tab controller when pane is destroyed + scope.$on('$destroy', function() { + bsTabsCtrl.$remove(scope); + }); + + function render() { + var index = bsTabsCtrl.$panes.indexOf(scope); + var active = bsTabsCtrl.$panes.$active; + $animate[index === active ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass); + } + + bsTabsCtrl.$activePaneChangeListeners.push(function() { + render(); + }); + render(); + + } + }; + + }]); + +// Source: scrollspy.js +angular.module('mgcrea.ngStrap.scrollspy', ['mgcrea.ngStrap.helpers.debounce', 'mgcrea.ngStrap.helpers.dimensions']) + + .provider('$scrollspy', function() { + + // Pool of registered spies + var spies = this.$$spies = {}; + + var defaults = this.defaults = { + debounce: 150, + throttle: 100, + offset: 100 + }; + + this.$get = ["$window", "$document", "$rootScope", "dimensions", "debounce", "throttle", function($window, $document, $rootScope, dimensions, debounce, throttle) { + + var windowEl = angular.element($window); + var docEl = angular.element($document.prop('documentElement')); + var bodyEl = angular.element($window.document.body); + + // Helper functions + + function nodeName(element, name) { + return element[0].nodeName && element[0].nodeName.toLowerCase() === name.toLowerCase(); + } + + function ScrollSpyFactory(config) { + + // Common vars + var options = angular.extend({}, defaults, config); + if(!options.element) options.element = bodyEl; + var isWindowSpy = nodeName(options.element, 'body'); + var scrollEl = isWindowSpy ? windowEl : options.element; + var scrollId = isWindowSpy ? 'window' : options.id; + + // Use existing spy + if(spies[scrollId]) { + spies[scrollId].$$count++; + return spies[scrollId]; + } + + var $scrollspy = {}; + + // Private vars + var unbindViewContentLoaded, unbindIncludeContentLoaded; + var trackedElements = $scrollspy.$trackedElements = []; + var sortedElements = []; + var activeTarget; + var debouncedCheckPosition; + var throttledCheckPosition; + var debouncedCheckOffsets; + var viewportHeight; + var scrollTop; + + $scrollspy.init = function() { + + // Setup internal ref counter + this.$$count = 1; + + // Bind events + debouncedCheckPosition = debounce(this.checkPosition, options.debounce); + throttledCheckPosition = throttle(this.checkPosition, options.throttle); + scrollEl.on('click', this.checkPositionWithEventLoop); + windowEl.on('resize', debouncedCheckPosition); + scrollEl.on('scroll', throttledCheckPosition); + + debouncedCheckOffsets = debounce(this.checkOffsets, options.debounce); + unbindViewContentLoaded = $rootScope.$on('$viewContentLoaded', debouncedCheckOffsets); + unbindIncludeContentLoaded = $rootScope.$on('$includeContentLoaded', debouncedCheckOffsets); + debouncedCheckOffsets(); + + // Register spy for reuse + if(scrollId) { + spies[scrollId] = $scrollspy; + } + + }; + + $scrollspy.destroy = function() { + + // Check internal ref counter + this.$$count--; + if(this.$$count > 0) { + return; + } + + // Unbind events + scrollEl.off('click', this.checkPositionWithEventLoop); + windowEl.off('resize', debouncedCheckPosition); + scrollEl.off('scroll', throttledCheckPosition); + unbindViewContentLoaded(); + unbindIncludeContentLoaded(); + if (scrollId) { + delete spies[scrollId]; + } + }; + + $scrollspy.checkPosition = function() { + + // Not ready yet + if(!sortedElements.length) return; + + // Calculate the scroll position + scrollTop = (isWindowSpy ? $window.pageYOffset : scrollEl.prop('scrollTop')) || 0; + + // Calculate the viewport height for use by the components + viewportHeight = Math.max($window.innerHeight, docEl.prop('clientHeight')); + + // Activate first element if scroll is smaller + if(scrollTop < sortedElements[0].offsetTop && activeTarget !== sortedElements[0].target) { + return $scrollspy.$activateElement(sortedElements[0]); + } + + // Activate proper element + for (var i = sortedElements.length; i--;) { + if(angular.isUndefined(sortedElements[i].offsetTop) || sortedElements[i].offsetTop === null) continue; + if(activeTarget === sortedElements[i].target) continue; + if(scrollTop < sortedElements[i].offsetTop) continue; + if(sortedElements[i + 1] && scrollTop > sortedElements[i + 1].offsetTop) continue; + return $scrollspy.$activateElement(sortedElements[i]); + } + + }; + + $scrollspy.checkPositionWithEventLoop = function() { + // IE 9 throws an error if we use 'this' instead of '$scrollspy' + // in this setTimeout call + setTimeout($scrollspy.checkPosition, 1); + }; + + // Protected methods + + $scrollspy.$activateElement = function(element) { + if(activeTarget) { + var activeElement = $scrollspy.$getTrackedElement(activeTarget); + if(activeElement) { + activeElement.source.removeClass('active'); + if(nodeName(activeElement.source, 'li') && nodeName(activeElement.source.parent().parent(), 'li')) { + activeElement.source.parent().parent().removeClass('active'); + } + } + } + activeTarget = element.target; + element.source.addClass('active'); + if(nodeName(element.source, 'li') && nodeName(element.source.parent().parent(), 'li')) { + element.source.parent().parent().addClass('active'); + } + }; + + $scrollspy.$getTrackedElement = function(target) { + return trackedElements.filter(function(obj) { + return obj.target === target; + })[0]; + }; + + // Track offsets behavior + + $scrollspy.checkOffsets = function() { + + angular.forEach(trackedElements, function(trackedElement) { + var targetElement = document.querySelector(trackedElement.target); + trackedElement.offsetTop = targetElement ? dimensions.offset(targetElement).top : null; + if(options.offset && trackedElement.offsetTop !== null) trackedElement.offsetTop -= options.offset * 1; + }); + + sortedElements = trackedElements + .filter(function(el) { + return el.offsetTop !== null; + }) + .sort(function(a, b) { + return a.offsetTop - b.offsetTop; + }); + + debouncedCheckPosition(); + + }; + + $scrollspy.trackElement = function(target, source) { + trackedElements.push({target: target, source: source}); + }; + + $scrollspy.untrackElement = function(target, source) { + var toDelete; + for (var i = trackedElements.length; i--;) { + if(trackedElements[i].target === target && trackedElements[i].source === source) { + toDelete = i; + break; + } + } + trackedElements = trackedElements.splice(toDelete, 1); + }; + + $scrollspy.activate = function(i) { + trackedElements[i].addClass('active'); + }; + + // Initialize plugin + + $scrollspy.init(); + return $scrollspy; + + } + + return ScrollSpyFactory; + + }]; + + }) + + .directive('bsScrollspy', ["$rootScope", "debounce", "dimensions", "$scrollspy", function($rootScope, debounce, dimensions, $scrollspy) { + + return { + restrict: 'EAC', + link: function postLink(scope, element, attr) { + + var options = {scope: scope}; + angular.forEach(['offset', 'target'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + var scrollspy = $scrollspy(options); + scrollspy.trackElement(options.target, element); + + scope.$on('$destroy', function() { + if (scrollspy) { + scrollspy.untrackElement(options.target, element); + scrollspy.destroy(); + } + options = null; + scrollspy = null; + }); + + } + }; + + }]) + + + .directive('bsScrollspyList', ["$rootScope", "debounce", "dimensions", "$scrollspy", function($rootScope, debounce, dimensions, $scrollspy) { + + return { + restrict: 'A', + compile: function postLink(element, attr) { + var children = element[0].querySelectorAll('li > a[href]'); + angular.forEach(children, function(child) { + var childEl = angular.element(child); + childEl.parent().attr('bs-scrollspy', '').attr('data-target', childEl.attr('href')); + }); + } + + }; + + }]); + +// Source: timepicker.js +angular.module('mgcrea.ngStrap.timepicker', [ + 'mgcrea.ngStrap.helpers.dateParser', + 'mgcrea.ngStrap.helpers.dateFormatter', + 'mgcrea.ngStrap.tooltip']) + + .provider('$timepicker', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + prefixClass: 'timepicker', + placement: 'bottom-left', + template: 'timepicker/timepicker.tpl.html', + trigger: 'focus', + container: false, + keyboard: true, + html: false, + delay: 0, + // lang: $locale.id, + useNative: true, + timeType: 'date', + timeFormat: 'shortTime', + modelTimeFormat: null, + autoclose: false, + minTime: -Infinity, + maxTime: +Infinity, + length: 5, + hourStep: 1, + minuteStep: 5, + iconUp: 'glyphicon glyphicon-chevron-up', + iconDown: 'glyphicon glyphicon-chevron-down', + arrowBehavior: 'pager' + }; + + this.$get = ["$window", "$document", "$rootScope", "$sce", "$dateFormatter", "$tooltip", "$timeout", function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) { + + var bodyEl = angular.element($window.document.body); + var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent); + var isTouch = ('createTouch' in $window.document) && isNative; + if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale(); + + function timepickerFactory(element, controller, config) { + + var $timepicker = $tooltip(element, angular.extend({}, defaults, config)); + var parentScope = config.scope; + var options = $timepicker.$options; + var scope = $timepicker.$scope; + + var lang = options.lang; + var formatDate = function(date, format) { + return $dateFormatter.formatDate(date, format, lang); + }; + + // View vars + + var selectedIndex = 0; + var startDate = controller.$dateValue || new Date(); + var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()}; + + var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang); + + var hoursFormat = $dateFormatter.hoursFormat(format), + timeSeparator = $dateFormatter.timeSeparator(format), + minutesFormat = $dateFormatter.minutesFormat(format), + showAM = $dateFormatter.showAM(format); + + scope.$iconUp = options.iconUp; + scope.$iconDown = options.iconDown; + + // Scope methods + + scope.$select = function(date, index) { + $timepicker.select(date, index); + }; + scope.$moveIndex = function(value, index) { + $timepicker.$moveIndex(value, index); + }; + scope.$switchMeridian = function(date) { + $timepicker.switchMeridian(date); + }; + + // Public methods + + $timepicker.update = function(date) { + // console.warn('$timepicker.update() newValue=%o', date); + if(angular.isDate(date) && !isNaN(date.getTime())) { + $timepicker.$date = date; + angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()}); + $timepicker.$build(); + } else if(!$timepicker.$isBuilt) { + $timepicker.$build(); + } + }; + + $timepicker.select = function(date, index, keep) { + // console.warn('$timepicker.select', date, scope.$mode); + if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1); + if(!angular.isDate(date)) date = new Date(date); + if(index === 0) controller.$dateValue.setHours(date.getHours()); + else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes()); + controller.$setViewValue(angular.copy(controller.$dateValue)); + controller.$render(); + if(options.autoclose && !keep) { + $timeout(function() { $timepicker.hide(true); }); + } + }; + + $timepicker.switchMeridian = function(date) { + if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) { + return; + } + var hours = (date || controller.$dateValue).getHours(); + controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12); + controller.$setViewValue(angular.copy(controller.$dateValue)); + controller.$render(); + }; + + // Protected methods + + $timepicker.$build = function() { + // console.warn('$timepicker.$build() viewDate=%o', viewDate); + var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10); + var hours = [], hour; + for(i = 0; i < options.length; i++) { + hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep); + hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)}); + } + var minutes = [], minute; + for(i = 0; i < options.length; i++) { + minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep); + minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)}); + } + + var rows = []; + for(i = 0; i < options.length; i++) { + rows.push([hours[i], minutes[i]]); + } + scope.rows = rows; + scope.showAM = showAM; + scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12; + scope.timeSeparator = timeSeparator; + $timepicker.$isBuilt = true; + }; + + $timepicker.$isSelected = function(date, index) { + if(!$timepicker.$date) return false; + else if(index === 0) { + return date.getHours() === $timepicker.$date.getHours(); + } else if(index === 1) { + return date.getMinutes() === $timepicker.$date.getMinutes(); + } + }; + + $timepicker.$isDisabled = function(date, index) { + var selectedTime; + if(index === 0) { + selectedTime = date.getTime() + viewDate.minute * 6e4; + } else if(index === 1) { + selectedTime = date.getTime() + viewDate.hour * 36e5; + } + return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1; + }; + + scope.$arrowAction = function (value, index) { + if (options.arrowBehavior === 'picker') { + $timepicker.$setTimeByStep(value,index); + } else { + $timepicker.$moveIndex(value,index); + } + }; + + $timepicker.$setTimeByStep = function(value, index) { + var newDate = new Date($timepicker.$date); + var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length; + var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length; + if (index === 0) { + newDate.setHours(hours - (parseInt(options.hourStep, 10) * value)); + } + else { + newDate.setMinutes(minutes - (parseInt(options.minuteStep, 10) * value)); + } + $timepicker.select(newDate, index, true); + }; + + $timepicker.$moveIndex = function(value, index) { + var targetDate; + if(index === 0) { + targetDate = new Date(1970, 0, 1, viewDate.hour + (value * options.length), viewDate.minute); + angular.extend(viewDate, {hour: targetDate.getHours()}); + } else if(index === 1) { + targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep)); + angular.extend(viewDate, {minute: targetDate.getMinutes()}); + } + $timepicker.$build(); + }; + + $timepicker.$onMouseDown = function(evt) { + // Prevent blur on mousedown on .dropdown-menu + if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault(); + evt.stopPropagation(); + // Emulate click for mobile devices + if(isTouch) { + var targetEl = angular.element(evt.target); + if(targetEl[0].nodeName.toLowerCase() !== 'button') { + targetEl = targetEl.parent(); + } + targetEl.triggerHandler('click'); + } + }; + + $timepicker.$onKeyDown = function(evt) { + if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return; + evt.preventDefault(); + evt.stopPropagation(); + + // Close on enter + if(evt.keyCode === 13) return $timepicker.hide(true); + + // Navigate with keyboard + var newDate = new Date($timepicker.$date); + var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length; + var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length; + var lateralMove = /(37|39)/.test(evt.keyCode); + var count = 2 + showAM * 1; + + // Navigate indexes (left, right) + if (lateralMove) { + if(evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1; + else if(evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0; + } + + // Update values (up, down) + var selectRange = [0, hoursLength]; + if(selectedIndex === 0) { + if(evt.keyCode === 38) newDate.setHours(hours - parseInt(options.hourStep, 10)); + else if(evt.keyCode === 40) newDate.setHours(hours + parseInt(options.hourStep, 10)); + // re-calculate hours length because we have changed hours value + hoursLength = formatDate(newDate, hoursFormat).length; + selectRange = [0, hoursLength]; + } else if(selectedIndex === 1) { + if(evt.keyCode === 38) newDate.setMinutes(minutes - parseInt(options.minuteStep, 10)); + else if(evt.keyCode === 40) newDate.setMinutes(minutes + parseInt(options.minuteStep, 10)); + // re-calculate minutes length because we have changes minutes value + minutesLength = formatDate(newDate, minutesFormat).length; + selectRange = [hoursLength + 1, hoursLength + 1 + minutesLength]; + } else if(selectedIndex === 2) { + if(!lateralMove) $timepicker.switchMeridian(); + selectRange = [hoursLength + 1 + minutesLength + 1, hoursLength + 1 + minutesLength + 3]; + } + $timepicker.select(newDate, selectedIndex, true); + createSelection(selectRange[0], selectRange[1]); + parentScope.$digest(); + }; + + // Private + + function createSelection(start, end) { + if(element[0].createTextRange) { + var selRange = element[0].createTextRange(); + selRange.collapse(true); + selRange.moveStart('character', start); + selRange.moveEnd('character', end); + selRange.select(); + } else if(element[0].setSelectionRange) { + element[0].setSelectionRange(start, end); + } else if(angular.isUndefined(element[0].selectionStart)) { + element[0].selectionStart = start; + element[0].selectionEnd = end; + } + } + + function focusElement() { + element[0].focus(); + } + + // Overrides + + var _init = $timepicker.init; + $timepicker.init = function() { + if(isNative && options.useNative) { + element.prop('type', 'time'); + element.css('-webkit-appearance', 'textfield'); + return; + } else if(isTouch) { + element.prop('type', 'text'); + element.attr('readonly', 'true'); + element.on('click', focusElement); + } + _init(); + }; + + var _destroy = $timepicker.destroy; + $timepicker.destroy = function() { + if(isNative && options.useNative) { + element.off('click', focusElement); + } + _destroy(); + }; + + var _show = $timepicker.show; + $timepicker.show = function() { + _show(); + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. + $timeout(function() { + $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown); + if(options.keyboard) { + element.on('keydown', $timepicker.$onKeyDown); + } + }, 0, false); + }; + + var _hide = $timepicker.hide; + $timepicker.hide = function(blur) { + if(!$timepicker.$isShown) return; + $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown); + if(options.keyboard) { + element.off('keydown', $timepicker.$onKeyDown); + } + _hide(blur); + }; + + return $timepicker; + + } + + timepickerFactory.defaults = defaults; + return timepickerFactory; + + }]; + + }) + + + .directive('bsTimepicker', ["$window", "$parse", "$q", "$dateFormatter", "$dateParser", "$timepicker", function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) { + + var defaults = $timepicker.defaults; + var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent); + var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; + + return { + restrict: 'EAC', + require: 'ngModel', + link: function postLink(scope, element, attr, controller) { + + // Directive options + var options = {scope: scope, controller: controller}; + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'timeType', 'timeFormat', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'id'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Visibility binding support + attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) { + if(!timepicker || !angular.isDefined(newValue)) return; + if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i); + newValue === true ? timepicker.show() : timepicker.hide(); + }); + + // Initialize timepicker + if(isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm'; + var timepicker = $timepicker(element, controller, options); + options = timepicker.$options; + + var lang = options.lang; + var formatDate = function(date, format) { + return $dateFormatter.formatDate(date, format, lang); + }; + + // Initialize parser + var dateParser = $dateParser({format: options.timeFormat, lang: lang}); + + // Observe attributes for changes + angular.forEach(['minTime', 'maxTime'], function(key) { + // console.warn('attr.$observe(%s)', key, attr[key]); + angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) { + timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue); + !isNaN(timepicker.$options[key]) && timepicker.$build(); + validateAgainstMinMaxTime(controller.$dateValue); + }); + }); + + // Watch model for changes + scope.$watch(attr.ngModel, function(newValue, oldValue) { + // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue); + timepicker.update(controller.$dateValue); + }, true); + + function validateAgainstMinMaxTime(parsedTime) { + if (!angular.isDate(parsedTime)) return; + var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime; + var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime; + var isValid = isMinValid && isMaxValid; + controller.$setValidity('date', isValid); + controller.$setValidity('min', isMinValid); + controller.$setValidity('max', isMaxValid); + // Only update the model when we have a valid date + if(!isValid) { + return; + } + controller.$dateValue = parsedTime; + } + + // viewValue -> $parsers -> modelValue + controller.$parsers.unshift(function(viewValue) { + // console.warn('$parser("%s"): viewValue=%o', element.attr('ng-model'), viewValue); + // Null values should correctly reset the model value & validity + if(!viewValue) { + // BREAKING CHANGE: + // return null (not undefined) when input value is empty, so angularjs 1.3 + // ngModelController can go ahead and run validators, like ngRequired + controller.$setValidity('date', true); + return null; + } + var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue); + if(!parsedTime || isNaN(parsedTime.getTime())) { + controller.$setValidity('date', false); + // return undefined, causes ngModelController to + // invalidate model value + return; + } else { + validateAgainstMinMaxTime(parsedTime); + } + if(options.timeType === 'string') { + return formatDate(parsedTime, options.modelTimeFormat || options.timeFormat); + } else if(options.timeType === 'number') { + return controller.$dateValue.getTime(); + } else if(options.timeType === 'unix') { + return controller.$dateValue.getTime() / 1000; + } else if(options.timeType === 'iso') { + return controller.$dateValue.toISOString(); + } else { + return new Date(controller.$dateValue); + } + }); + + // modelValue -> $formatters -> viewValue + controller.$formatters.push(function(modelValue) { + // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue); + var date; + if(angular.isUndefined(modelValue) || modelValue === null) { + date = NaN; + } else if(angular.isDate(modelValue)) { + date = modelValue; + } else if(options.timeType === 'string') { + date = dateParser.parse(modelValue, null, options.modelTimeFormat); + } else if(options.timeType === 'unix') { + date = new Date(modelValue * 1000); + } else { + date = new Date(modelValue); + } + // Setup default value? + // if(isNaN(date.getTime())) date = new Date(new Date().setMinutes(0) + 36e5); + controller.$dateValue = date; + return getTimeFormattedString(); + }); + + // viewValue -> element + controller.$render = function() { + // console.warn('$render("%s"): viewValue=%o', element.attr('ng-model'), controller.$viewValue); + element.val(getTimeFormattedString()); + }; + + function getTimeFormattedString() { + return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat); + } + + // Garbage collection + scope.$on('$destroy', function() { + if (timepicker) timepicker.destroy(); + options = null; + timepicker = null; + }); + + } + }; + + }]); + +// Source: tooltip.js +angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions']) + + .provider('$tooltip', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + customClass: '', + prefixClass: 'tooltip', + prefixEvent: 'tooltip', + container: false, + target: false, + placement: 'top', + template: 'tooltip/tooltip.tpl.html', + contentTemplate: false, + trigger: 'hover focus', + keyboard: false, + html: false, + show: false, + title: '', + type: '', + delay: 0, + autoClose: false, + bsEnabled: true + }; + + this.$get = ["$window", "$rootScope", "$compile", "$q", "$templateCache", "$http", "$animate", "$sce", "dimensions", "$$rAF", "$timeout", function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) { + + var trim = String.prototype.trim; + var isTouch = 'createTouch' in $window.document; + var htmlReplaceRegExp = /ng-bind="/ig; + var $body = angular.element($window.document); + + function TooltipFactory(element, config) { + + var $tooltip = {}; + + // Common vars + var nodeName = element[0].nodeName.toLowerCase(); + var options = $tooltip.$options = angular.extend({}, defaults, config); + $tooltip.$promise = fetchTemplate(options.template); + var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new(); + if(options.delay && angular.isString(options.delay)) { + var split = options.delay.split(',').map(parseFloat); + options.delay = split.length > 1 ? {show: split[0], hide: split[1]} : split[0]; + } + + // store $id to identify the triggering element in events + // give priority to options.id, otherwise, try to use + // element id if defined + $tooltip.$id = options.id || element.attr('id') || ''; + + // Support scope as string options + if(options.title) { + scope.title = $sce.trustAsHtml(options.title); + } + + // Provide scope helpers + scope.$setEnabled = function(isEnabled) { + scope.$$postDigest(function() { + $tooltip.setEnabled(isEnabled); + }); + }; + scope.$hide = function() { + scope.$$postDigest(function() { + $tooltip.hide(); + }); + }; + scope.$show = function() { + scope.$$postDigest(function() { + $tooltip.show(); + }); + }; + scope.$toggle = function() { + scope.$$postDigest(function() { + $tooltip.toggle(); + }); + }; + // Publish isShown as a protected var on scope + $tooltip.$isShown = scope.$isShown = false; + + // Private vars + var timeout, hoverState; + + // Support contentTemplate option + if(options.contentTemplate) { + $tooltip.$promise = $tooltip.$promise.then(function(template) { + var templateEl = angular.element(template); + return fetchTemplate(options.contentTemplate) + .then(function(contentTemplate) { + var contentEl = findElement('[ng-bind="content"]', templateEl[0]); + if(!contentEl.length) contentEl = findElement('[ng-bind="title"]', templateEl[0]); + contentEl.removeAttr('ng-bind').html(contentTemplate); + return templateEl[0].outerHTML; + }); + }); + } + + // Fetch, compile then initialize tooltip + var tipLinker, tipElement, tipTemplate, tipContainer, tipScope; + $tooltip.$promise.then(function(template) { + if(angular.isObject(template)) template = template.data; + if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html="'); + template = trim.apply(template); + tipTemplate = template; + tipLinker = $compile(template); + $tooltip.init(); + }); + + $tooltip.init = function() { + + // Options: delay + if (options.delay && angular.isNumber(options.delay)) { + options.delay = { + show: options.delay, + hide: options.delay + }; + } + + // Replace trigger on touch devices ? + // if(isTouch && options.trigger === defaults.trigger) { + // options.trigger.replace(/hover/g, 'click'); + // } + + // Options : container + if(options.container === 'self') { + tipContainer = element; + } else if(angular.isElement(options.container)) { + tipContainer = options.container; + } else if(options.container) { + tipContainer = findElement(options.container); + } + + // Options: trigger + bindTriggerEvents(); + + // Options: target + if(options.target) { + options.target = angular.isElement(options.target) ? options.target : findElement(options.target); + } + + // Options: show + if(options.show) { + scope.$$postDigest(function() { + options.trigger === 'focus' ? element[0].focus() : $tooltip.show(); + }); + } + + }; + + $tooltip.destroy = function() { + + // Unbind events + unbindTriggerEvents(); + + // Remove element + destroyTipElement(); + + // Destroy scope + scope.$destroy(); + + }; + + $tooltip.enter = function() { + + clearTimeout(timeout); + hoverState = 'in'; + if (!options.delay || !options.delay.show) { + return $tooltip.show(); + } + + timeout = setTimeout(function() { + if (hoverState ==='in') $tooltip.show(); + }, options.delay.show); + + }; + + $tooltip.show = function() { + if (!options.bsEnabled || $tooltip.$isShown) return; + + scope.$emit(options.prefixEvent + '.show.before', $tooltip); + var parent, after; + if (options.container) { + parent = tipContainer; + if (tipContainer[0].lastChild) { + after = angular.element(tipContainer[0].lastChild); + } else { + after = null; + } + } else { + parent = null; + after = element; + } + + + // Hide any existing tipElement + if(tipElement) destroyTipElement(); + // Fetch a cloned element linked from template + tipScope = $tooltip.$scope.$new(); + tipElement = $tooltip.$element = tipLinker(tipScope, function(clonedElement, scope) {}); + + // Set the initial positioning. Make the tooltip invisible + // so IE doesn't try to focus on it off screen. + tipElement.css({top: '-9999px', left: '-9999px', display: 'block', visibility: 'hidden'}); + + // Options: animation + if(options.animation) tipElement.addClass(options.animation); + // Options: type + if(options.type) tipElement.addClass(options.prefixClass + '-' + options.type); + // Options: custom classes + if(options.customClass) tipElement.addClass(options.customClass); + + // Support v1.3+ $animate + // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9 + var promise = $animate.enter(tipElement, parent, after, enterAnimateCallback); + if(promise && promise.then) promise.then(enterAnimateCallback); + + $tooltip.$isShown = scope.$isShown = true; + safeDigest(scope); + $$rAF(function () { + $tooltip.$applyPlacement(); + + // Once placed, make the tooltip visible + if(tipElement) tipElement.css({visibility: 'visible'}); + }); // var a = bodyEl.offsetWidth + 1; ? + + // Bind events + if(options.keyboard) { + if(options.trigger !== 'focus') { + $tooltip.focus(); + } + bindKeyboardEvents(); + } + + if(options.autoClose) { + bindAutoCloseEvents(); + } + + }; + + function enterAnimateCallback() { + scope.$emit(options.prefixEvent + '.show', $tooltip); + } + + $tooltip.leave = function() { + + clearTimeout(timeout); + hoverState = 'out'; + if (!options.delay || !options.delay.hide) { + return $tooltip.hide(); + } + timeout = setTimeout(function () { + if (hoverState === 'out') { + $tooltip.hide(); + } + }, options.delay.hide); + + }; + + var _blur; + var _tipToHide; + $tooltip.hide = function(blur) { + + if(!$tooltip.$isShown) return; + scope.$emit(options.prefixEvent + '.hide.before', $tooltip); + + // store blur value for leaveAnimateCallback to use + _blur = blur; + + // store current tipElement reference to use + // in leaveAnimateCallback + _tipToHide = tipElement; + + // Support v1.3+ $animate + // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9 + var promise = $animate.leave(tipElement, leaveAnimateCallback); + if(promise && promise.then) promise.then(leaveAnimateCallback); + + $tooltip.$isShown = scope.$isShown = false; + safeDigest(scope); + + // Unbind events + if(options.keyboard && tipElement !== null) { + unbindKeyboardEvents(); + } + + if(options.autoClose && tipElement !== null) { + unbindAutoCloseEvents(); + } + }; + + function leaveAnimateCallback() { + scope.$emit(options.prefixEvent + '.hide', $tooltip); + + // check if current tipElement still references + // the same element when hide was called + if (tipElement === _tipToHide) { + // Allow to blur the input when hidden, like when pressing enter key + if(_blur && options.trigger === 'focus') { + return element[0].blur(); + } + + // clean up child scopes + destroyTipElement(); + } + } + + $tooltip.toggle = function() { + $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter(); + }; + + $tooltip.focus = function() { + tipElement[0].focus(); + }; + + $tooltip.setEnabled = function(isEnabled) { + options.bsEnabled = isEnabled; + }; + + // Protected methods + + $tooltip.$applyPlacement = function() { + if(!tipElement) return; + + // Determine if we're doing an auto or normal placement + var placement = options.placement, + autoToken = /\s?auto?\s?/i, + autoPlace = autoToken.test(placement); + + if (autoPlace) { + placement = placement.replace(autoToken, '') || defaults.placement; + } + + // Need to add the position class before we get + // the offsets + tipElement.addClass(options.placement); + + // Get the position of the target element + // and the height and width of the tooltip so we can center it. + var elementPosition = getPosition(), + tipWidth = tipElement.prop('offsetWidth'), + tipHeight = tipElement.prop('offsetHeight'); + + // If we're auto placing, we need to check the positioning + if (autoPlace) { + var originalPlacement = placement; + var container = options.container ? angular.element(document.querySelector(options.container)) : element.parent(); + var containerPosition = getPosition(container); + + // Determine if the vertical placement + if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) { + placement = originalPlacement.replace('bottom', 'top'); + } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) { + placement = originalPlacement.replace('top', 'bottom'); + } + + // Determine the horizontal placement + // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right + // and flow in the opposite direction of their placement. + if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') && + elementPosition.right + tipWidth > containerPosition.width) { + + placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right'); + } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') && + elementPosition.left - tipWidth < containerPosition.left) { + + placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left'); + } + + tipElement.removeClass(originalPlacement).addClass(placement); + } + + // Get the tooltip's top and left coordinates to center it with this directive. + var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight); + applyPlacementCss(tipPosition.top, tipPosition.left); + }; + + $tooltip.$onKeyUp = function(evt) { + if (evt.which === 27 && $tooltip.$isShown) { + $tooltip.hide(); + evt.stopPropagation(); + } + }; + + $tooltip.$onFocusKeyUp = function(evt) { + if (evt.which === 27) { + element[0].blur(); + evt.stopPropagation(); + } + }; + + $tooltip.$onFocusElementMouseDown = function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + // Some browsers do not auto-focus buttons (eg. Safari) + $tooltip.$isShown ? element[0].blur() : element[0].focus(); + }; + + // bind/unbind events + function bindTriggerEvents() { + var triggers = options.trigger.split(' '); + angular.forEach(triggers, function(trigger) { + if(trigger === 'click') { + element.on('click', $tooltip.toggle); + } else if(trigger !== 'manual') { + element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter); + element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave); + nodeName === 'button' && trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown); + } + }); + } + + function unbindTriggerEvents() { + var triggers = options.trigger.split(' '); + for (var i = triggers.length; i--;) { + var trigger = triggers[i]; + if(trigger === 'click') { + element.off('click', $tooltip.toggle); + } else if(trigger !== 'manual') { + element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter); + element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave); + nodeName === 'button' && trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown); + } + } + } + + function bindKeyboardEvents() { + if(options.trigger !== 'focus') { + tipElement.on('keyup', $tooltip.$onKeyUp); + } else { + element.on('keyup', $tooltip.$onFocusKeyUp); + } + } + + function unbindKeyboardEvents() { + if(options.trigger !== 'focus') { + tipElement.off('keyup', $tooltip.$onKeyUp); + } else { + element.off('keyup', $tooltip.$onFocusKeyUp); + } + } + + var _autoCloseEventsBinded = false; + function bindAutoCloseEvents() { + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. + $timeout(function() { + // Stop propagation when clicking inside tooltip + tipElement.on('click', stopEventPropagation); + + // Hide when clicking outside tooltip + $body.on('click', $tooltip.hide); + + _autoCloseEventsBinded = true; + }, 0, false); + } + + function unbindAutoCloseEvents() { + if (_autoCloseEventsBinded) { + tipElement.off('click', stopEventPropagation); + $body.off('click', $tooltip.hide); + _autoCloseEventsBinded = false; + } + } + + function stopEventPropagation(event) { + event.stopPropagation(); + } + + // Private methods + + function getPosition($element) { + $element = $element || (options.target || element); + + var el = $element[0]; + + var elRect = el.getBoundingClientRect(); + if (elRect.width === null) { + // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093 + elRect = angular.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top }); + } + + var elPos; + if (options.container === 'body') { + elPos = dimensions.offset(el); + } else { + elPos = dimensions.position(el); + } + + return angular.extend({}, elRect, elPos); + } + + function getCalculatedOffset(placement, position, actualWidth, actualHeight) { + var offset; + var split = placement.split('-'); + + switch (split[0]) { + case 'right': + offset = { + top: position.top + position.height / 2 - actualHeight / 2, + left: position.left + position.width + }; + break; + case 'bottom': + offset = { + top: position.top + position.height, + left: position.left + position.width / 2 - actualWidth / 2 + }; + break; + case 'left': + offset = { + top: position.top + position.height / 2 - actualHeight / 2, + left: position.left - actualWidth + }; + break; + default: + offset = { + top: position.top - actualHeight, + left: position.left + position.width / 2 - actualWidth / 2 + }; + break; + } + + if(!split[1]) { + return offset; + } + + // Add support for corners @todo css + if(split[0] === 'top' || split[0] === 'bottom') { + switch (split[1]) { + case 'left': + offset.left = position.left; + break; + case 'right': + offset.left = position.left + position.width - actualWidth; + } + } else if(split[0] === 'left' || split[0] === 'right') { + switch (split[1]) { + case 'top': + offset.top = position.top - actualHeight; + break; + case 'bottom': + offset.top = position.top + position.height; + } + } + + return offset; + } + + function applyPlacementCss(top, left) { + tipElement.css({ top: top + 'px', left: left + 'px' }); + } + + function destroyTipElement() { + // Cancel pending callbacks + clearTimeout(timeout); + + if($tooltip.$isShown && tipElement !== null) { + if(options.autoClose) { + unbindAutoCloseEvents(); + } + + if(options.keyboard) { + unbindKeyboardEvents(); + } + } + + if(tipScope) { + tipScope.$destroy(); + tipScope = null; + } + + if(tipElement) { + tipElement.remove(); + tipElement = $tooltip.$element = null; + } + } + + return $tooltip; + + } + + // Helper functions + + function safeDigest(scope) { + scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest(); + } + + function findElement(query, element) { + return angular.element((element || document).querySelectorAll(query)); + } + + var fetchPromises = {}; + function fetchTemplate(template) { + if(fetchPromises[template]) return fetchPromises[template]; + return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template)) + .then(function(res) { + if(angular.isObject(res)) { + $templateCache.put(template, res.data); + return res.data; + } + return res; + })); + } + + return TooltipFactory; + + }]; + + }) + + .directive('bsTooltip', ["$window", "$location", "$sce", "$tooltip", "$$rAF", function($window, $location, $sce, $tooltip, $$rAF) { + + return { + restrict: 'EAC', + scope: true, + link: function postLink(scope, element, attr, transclusion) { + + // Directive options + var options = {scope: scope}; + angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // overwrite inherited title value when no value specified + // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11 + if (!scope.hasOwnProperty('title')){ + scope.title = ''; + } + + // Observe scope attributes for change + attr.$observe('title', function(newValue) { + if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) { + var oldValue = scope.title; + scope.title = $sce.trustAsHtml(newValue); + angular.isDefined(oldValue) && $$rAF(function() { + tooltip && tooltip.$applyPlacement(); + }); + } + }); + + // Support scope as an object + attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) { + if(angular.isObject(newValue)) { + angular.extend(scope, newValue); + } else { + scope.title = newValue; + } + angular.isDefined(oldValue) && $$rAF(function() { + tooltip && tooltip.$applyPlacement(); + }); + }, true); + + // Visibility binding support + attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) { + if(!tooltip || !angular.isDefined(newValue)) return; + if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i); + newValue === true ? tooltip.show() : tooltip.hide(); + }); + + // Enabled binding support + attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) { + // console.warn('scope.$watch(%s)', attr.bsEnabled, newValue, oldValue); + if(!tooltip || !angular.isDefined(newValue)) return; + if(angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i); + newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true); + }); + + // Initialize popover + var tooltip = $tooltip(element, options); + + // Garbage collection + scope.$on('$destroy', function() { + if(tooltip) tooltip.destroy(); + options = null; + tooltip = null; + }); + + } + }; + + }]); + +// Source: typeahead.js +angular.module('mgcrea.ngStrap.typeahead', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions']) + + .provider('$typeahead', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + prefixClass: 'typeahead', + prefixEvent: '$typeahead', + placement: 'bottom-left', + template: 'typeahead/typeahead.tpl.html', + trigger: 'focus', + container: false, + keyboard: true, + html: false, + delay: 0, + minLength: 1, + filter: 'filter', + limit: 6, + comparator: '' + }; + + this.$get = ["$window", "$rootScope", "$tooltip", "$timeout", function($window, $rootScope, $tooltip, $timeout) { + + var bodyEl = angular.element($window.document.body); + + function TypeaheadFactory(element, controller, config) { + + var $typeahead = {}; + + // Common vars + var options = angular.extend({}, defaults, config); + + $typeahead = $tooltip(element, options); + var parentScope = config.scope; + var scope = $typeahead.$scope; + + scope.$resetMatches = function(){ + scope.$matches = []; + scope.$activeIndex = 0; + }; + scope.$resetMatches(); + + scope.$activate = function(index) { + scope.$$postDigest(function() { + $typeahead.activate(index); + }); + }; + + scope.$select = function(index, evt) { + scope.$$postDigest(function() { + $typeahead.select(index); + }); + }; + + scope.$isVisible = function() { + return $typeahead.$isVisible(); + }; + + // Public methods + + $typeahead.update = function(matches) { + scope.$matches = matches; + if(scope.$activeIndex >= matches.length) { + scope.$activeIndex = 0; + } + }; + + $typeahead.activate = function(index) { + scope.$activeIndex = index; + }; + + $typeahead.select = function(index) { + var value = scope.$matches[index].value; + // console.log('$setViewValue', value); + controller.$setViewValue(value); + controller.$render(); + scope.$resetMatches(); + if(parentScope) parentScope.$digest(); + // Emit event + scope.$emit(options.prefixEvent + '.select', value, index, $typeahead); + }; + + // Protected methods + + $typeahead.$isVisible = function() { + if(!options.minLength || !controller) { + return !!scope.$matches.length; + } + // minLength support + return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength; + }; + + $typeahead.$getIndex = function(value) { + var l = scope.$matches.length, i = l; + if(!l) return; + for(i = l; i--;) { + if(scope.$matches[i].value === value) break; + } + if(i < 0) return; + return i; + }; + + $typeahead.$onMouseDown = function(evt) { + // Prevent blur on mousedown + evt.preventDefault(); + evt.stopPropagation(); + }; + + $typeahead.$onKeyDown = function(evt) { + if(!/(38|40|13)/.test(evt.keyCode)) return; + + // Let ngSubmit pass if the typeahead tip is hidden + if($typeahead.$isVisible()) { + evt.preventDefault(); + evt.stopPropagation(); + } + + // Select with enter + if(evt.keyCode === 13 && scope.$matches.length) { + $typeahead.select(scope.$activeIndex); + } + + // Navigate with keyboard + else if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--; + else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++; + else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0; + scope.$digest(); + }; + + // Overrides + + var show = $typeahead.show; + $typeahead.show = function() { + show(); + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. + $timeout(function() { + $typeahead.$element.on('mousedown', $typeahead.$onMouseDown); + if(options.keyboard) { + element.on('keydown', $typeahead.$onKeyDown); + } + }, 0, false); + }; + + var hide = $typeahead.hide; + $typeahead.hide = function() { + $typeahead.$element.off('mousedown', $typeahead.$onMouseDown); + if(options.keyboard) { + element.off('keydown', $typeahead.$onKeyDown); + } + hide(); + }; + + return $typeahead; + + } + + TypeaheadFactory.defaults = defaults; + return TypeaheadFactory; + + }]; + + }) + + .directive('bsTypeahead', ["$window", "$parse", "$q", "$typeahead", "$parseOptions", function($window, $parse, $q, $typeahead, $parseOptions) { + + var defaults = $typeahead.defaults; + + return { + restrict: 'EAC', + require: 'ngModel', + link: function postLink(scope, element, attr, controller) { + + // Directive options + var options = {scope: scope}; + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'comparator', 'id'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Build proper ngOptions + var filter = options.filter || defaults.filter; + var limit = options.limit || defaults.limit; + var comparator = options.comparator || defaults.comparator; + + var ngOptions = attr.ngOptions; + if(filter) ngOptions += ' | ' + filter + ':$viewValue'; + if (comparator) ngOptions += ':' + comparator; + if(limit) ngOptions += ' | limitTo:' + limit; + var parsedOptions = $parseOptions(ngOptions); + + // Initialize typeahead + var typeahead = $typeahead(element, controller, options); + + // Watch options on demand + if(options.watchOptions) { + // Watch ngOptions values before filtering for changes, drop function calls + var watchedOptions = parsedOptions.$match[7].replace(/\|.+/, '').replace(/\(.*\)/g, '').trim(); + scope.$watch(watchedOptions, function (newValue, oldValue) { + // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue); + parsedOptions.valuesFn(scope, controller).then(function (values) { + typeahead.update(values); + controller.$render(); + }); + }, true); + } + + // Watch model for changes + scope.$watch(attr.ngModel, function(newValue, oldValue) { + // console.warn('$watch', element.attr('ng-model'), newValue); + scope.$modelValue = newValue; // Publish modelValue on scope for custom templates + parsedOptions.valuesFn(scope, controller) + .then(function(values) { + // Prevent input with no future prospect if selectMode is truthy + // @TODO test selectMode + if(options.selectMode && !values.length && newValue.length > 0) { + controller.$setViewValue(controller.$viewValue.substring(0, controller.$viewValue.length - 1)); + return; + } + if(values.length > limit) values = values.slice(0, limit); + var isVisible = typeahead.$isVisible(); + isVisible && typeahead.update(values); + // Do not re-queue an update if a correct value has been selected + if(values.length === 1 && values[0].value === newValue) return; + !isVisible && typeahead.update(values); + // Queue a new rendering that will leverage collection loading + controller.$render(); + }); + }); + + // modelValue -> $formatters -> viewValue + controller.$formatters.push(function(modelValue) { + // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue); + var displayValue = parsedOptions.displayValue(modelValue); + return displayValue === undefined ? '' : displayValue; + }); + + // Model rendering in view + controller.$render = function () { + // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue); + if(controller.$isEmpty(controller.$viewValue)) return element.val(''); + var index = typeahead.$getIndex(controller.$modelValue); + var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue; + selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected; + element.val(selected ? selected.toString().replace(/<(?:.|\n)*?>/gm, '').trim() : ''); + }; + + // Garbage collection + scope.$on('$destroy', function() { + if (typeahead) typeahead.destroy(); + options = null; + typeahead = null; + }); + + } + }; + + }]); + +})(window, document); diff --git a/snow-flowable/src/main/resources/static/libs/angular-strap_2.1.6/angular-strap.min.js b/snow-flowable/src/main/resources/static/libs/angular-strap_2.1.6/angular-strap.min.js new file mode 100644 index 0000000..4ec9e14 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-strap_2.1.6/angular-strap.min.js @@ -0,0 +1,11 @@ +/** + * angular-strap + * @version v2.1.6 - 2015-01-11 + * @link http://mgcrea.github.io/angular-strap + * @author Olivier Louvignes (olivier@mg-crea.com) + * @license MIT License, http://www.opensource.org/licenses/MIT + */ +!function(e,t,n){"use strict";angular.module("mgcrea.ngStrap",["mgcrea.ngStrap.modal","mgcrea.ngStrap.aside","mgcrea.ngStrap.alert","mgcrea.ngStrap.button","mgcrea.ngStrap.select","mgcrea.ngStrap.datepicker","mgcrea.ngStrap.timepicker","mgcrea.ngStrap.navbar","mgcrea.ngStrap.tooltip","mgcrea.ngStrap.popover","mgcrea.ngStrap.dropdown","mgcrea.ngStrap.typeahead","mgcrea.ngStrap.scrollspy","mgcrea.ngStrap.affix","mgcrea.ngStrap.tab","mgcrea.ngStrap.collapse"]),angular.module("mgcrea.ngStrap.affix",["mgcrea.ngStrap.helpers.dimensions","mgcrea.ngStrap.helpers.debounce"]).provider("$affix",function(){var e=this.defaults={offsetTop:"auto"};this.$get=["$window","debounce","dimensions",function(t,n,a){function o(o,s){function l(e,t,n){var a=u(),o=c();return v>=a?"top":null!==e&&a+e<=t.top?"middle":null!==y&&t.top+n+$>=o-y?"bottom":"middle"}function u(){return p[0]===t?t.pageYOffset:p[0].scrollTop}function c(){return p[0]===t?t.document.body.scrollHeight:p[0].scrollHeight}var d={},f=angular.extend({},e,s),p=f.target,g="affix affix-top affix-bottom",m=!1,$=0,h=0,v=0,y=0,w=null,b=null,D=o.parent();if(f.offsetParent)if(f.offsetParent.match(/^\d+$/))for(var k=0;k<1*f.offsetParent-1;k++)D=D.parent();else D=angular.element(f.offsetParent);return d.init=function(){this.$parseOffsets(),h=a.offset(o[0]).top+$,m=!o[0].style.width,p.on("scroll",this.checkPosition),p.on("click",this.checkPositionWithEventLoop),r.on("resize",this.$debouncedOnResize),this.checkPosition(),this.checkPositionWithEventLoop()},d.destroy=function(){p.off("scroll",this.checkPosition),p.off("click",this.checkPositionWithEventLoop),r.off("resize",this.$debouncedOnResize)},d.checkPositionWithEventLoop=function(){setTimeout(d.checkPosition,1)},d.checkPosition=function(){var e=u(),t=a.offset(o[0]),n=a.height(o[0]),r=l(b,t,n);w!==r&&(w=r,o.removeClass(g).addClass("affix"+("middle"!==r?"-"+r:"")),"top"===r?(b=null,o.css("position",f.offsetParent?"":"relative"),m&&o.css("width",""),o.css("top","")):"bottom"===r?(b=f.offsetUnpin?-(1*f.offsetUnpin):t.top-e,m&&o.css("width",""),o.css("position",f.offsetParent?"":"relative"),o.css("top",f.offsetParent?"":i[0].offsetHeight-y-n-h+"px")):(b=null,m&&o.css("width",o[0].offsetWidth+"px"),o.css("position","fixed"),o.css("top",$+"px")))},d.$onResize=function(){d.$parseOffsets(),d.checkPosition()},d.$debouncedOnResize=n(d.$onResize,50),d.$parseOffsets=function(){var e=o.css("position");o.css("position",f.offsetParent?"":"relative"),f.offsetTop&&("auto"===f.offsetTop&&(f.offsetTop="+0"),f.offsetTop.match(/^[-+]\d+$/)?($=1*-f.offsetTop,v=f.offsetParent?a.offset(D[0]).top+1*f.offsetTop:a.offset(o[0]).top-a.css(o[0],"marginTop",!0)+1*f.offsetTop):v=1*f.offsetTop),f.offsetBottom&&(y=f.offsetParent&&f.offsetBottom.match(/^[-+]\d+$/)?c()-(a.offset(D[0]).top+a.height(D[0]))+1*f.offsetBottom+1:1*f.offsetBottom),o.css("position",e)},d.init(),d}var i=angular.element(t.document.body),r=angular.element(t);return o}]}).directive("bsAffix",["$affix","$window",function(e,t){return{restrict:"EAC",require:"^?bsAffixTarget",link:function(n,a,o,i){var r={scope:n,offsetTop:"auto",target:i?i.$element:angular.element(t)};angular.forEach(["offsetTop","offsetBottom","offsetParent","offsetUnpin"],function(e){angular.isDefined(o[e])&&(r[e]=o[e])});var s=e(a,r);n.$on("$destroy",function(){s&&s.destroy(),r=null,s=null})}}}]).directive("bsAffixTarget",function(){return{controller:["$element",function(e){this.$element=e}]}}),angular.module("mgcrea.ngStrap.alert",["mgcrea.ngStrap.modal"]).provider("$alert",function(){var e=this.defaults={animation:"am-fade",prefixClass:"alert",prefixEvent:"alert",placement:null,template:"alert/alert.tpl.html",container:!1,element:null,backdrop:!1,keyboard:!0,show:!0,duration:!1,type:!1,dismissable:!0};this.$get=["$modal","$timeout",function(t,n){function a(a){var o={},i=angular.extend({},e,a);o=t(i),o.$scope.dismissable=!!i.dismissable,i.type&&(o.$scope.type=i.type);var r=o.show;return i.duration&&(o.show=function(){r(),n(function(){o.hide()},1e3*i.duration)}),o}return a}]}).directive("bsAlert",["$window","$sce","$alert",function(e,t,n){e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","placement","keyboard","html","container","animation","duration","dismissable"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content","type"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsAlert&&e.$watch(o.bsAlert,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.aside",["mgcrea.ngStrap.modal"]).provider("$aside",function(){var e=this.defaults={animation:"am-fade-and-slide-right",prefixClass:"aside",prefixEvent:"aside",placement:"right",template:"aside/aside.tpl.html",contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0};this.$get=["$modal",function(t){function n(n){var a={},o=angular.extend({},e,n);return a=t(o)}return n}]}).directive("bsAside",["$window","$sce","$aside",function(e,t,n){e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","contentTemplate","placement","backdrop","keyboard","html","container","animation"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsAside&&e.$watch(o.bsAside,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.button",[]).provider("$button",function(){var e=this.defaults={activeClass:"active",toggleEvent:"click"};this.$get=function(){return{defaults:e}}}).directive("bsCheckboxGroup",function(){return{restrict:"A",require:"ngModel",compile:function(e,t){e.attr("data-toggle","buttons"),e.removeAttr("ng-model");var n=e[0].querySelectorAll('input[type="checkbox"]');angular.forEach(n,function(e){var n=angular.element(e);n.attr("bs-checkbox",""),n.attr("ng-model",t.ngModel+"."+n.attr("value"))})}}}).directive("bsCheckbox",["$button","$$rAF",function(e,t){var n=e.defaults,a=/^(true|false|\d+)$/;return{restrict:"A",require:"ngModel",link:function(e,o,i,r){var s=n,l="INPUT"===o[0].nodeName,u=l?o.parent():o,c=angular.isDefined(i.trueValue)?i.trueValue:!0;a.test(i.trueValue)&&(c=e.$eval(i.trueValue));var d=angular.isDefined(i.falseValue)?i.falseValue:!1;a.test(i.falseValue)&&(d=e.$eval(i.falseValue));var f="boolean"!=typeof c||"boolean"!=typeof d;f&&(r.$parsers.push(function(e){return e?c:d}),r.$formatters.push(function(e){return angular.equals(e,c)}),e.$watch(i.ngModel,function(){r.$render()})),r.$render=function(){var e=angular.equals(r.$modelValue,c);t(function(){l&&(o[0].checked=e),u.toggleClass(s.activeClass,e)})},o.bind(s.toggleEvent,function(){e.$apply(function(){l||r.$setViewValue(!u.hasClass("active")),f||r.$render()})})}}}]).directive("bsRadioGroup",function(){return{restrict:"A",require:"ngModel",compile:function(e,t){e.attr("data-toggle","buttons"),e.removeAttr("ng-model");var n=e[0].querySelectorAll('input[type="radio"]');angular.forEach(n,function(e){angular.element(e).attr("bs-radio",""),angular.element(e).attr("ng-model",t.ngModel)})}}}).directive("bsRadio",["$button","$$rAF",function(e,t){var n=e.defaults,a=/^(true|false|\d+)$/;return{restrict:"A",require:"ngModel",link:function(e,o,i,r){var s=n,l="INPUT"===o[0].nodeName,u=l?o.parent():o,c=a.test(i.value)?e.$eval(i.value):i.value;r.$render=function(){var e=angular.equals(r.$modelValue,c);t(function(){l&&(o[0].checked=e),u.toggleClass(s.activeClass,e)})},o.bind(s.toggleEvent,function(){e.$apply(function(){r.$setViewValue(c),r.$render()})})}}}]),angular.module("mgcrea.ngStrap.collapse",[]).provider("$collapse",function(){var e=this.defaults={animation:"am-collapse",disallowToggle:!1,activeClass:"in",startCollapsed:!1,allowMultiple:!1},t=this.controller=function(t,n,a){function o(e){for(var t=l.$targets.$active,n=0;nt;t++)angular.forEach(g.rows[t],u.$setDisabledEl)},u.select=function(e,t){angular.isDate(n.$dateValue)||(n.$dateValue=new Date(e)),!g.$mode||t?(n.$setViewValue(angular.copy(e)),n.$render(),p.autoclose&&!t&&l(function(){u.hide(!0)})):(angular.extend($,{year:e.getFullYear(),month:e.getMonth(),date:e.getDate()}),u.setMode(g.$mode-1),u.$build())},u.setMode=function(e){g.$mode=e,h=u.$views[g.$mode],u.$build()},u.$build=function(e){e===!0&&h.built||(e!==!1||h.built)&&h.build.call(h)},u.$updateSelected=function(){for(var e=0,t=g.rows.length;t>e;e++)angular.forEach(g.rows[e],o)},u.$isSelected=function(e){return h.isSelected(e)},u.$setDisabledEl=function(e){e.disabled=h.isDisabled(e.date)},u.$selectPane=function(e){var t=h.steps,n=new Date(Date.UTC($.year+(t.year||0)*e,$.month+(t.month||0)*e,1));angular.extend($,{year:n.getUTCFullYear(),month:n.getUTCMonth(),date:n.getUTCDate()}),u.$build()},u.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),d){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},u.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return g.$mode?g.$apply(function(){u.setMode(g.$mode-1)}):u.hide(!0);h.onKeyDown(e),f.$digest()}};var v=u.init;u.init=function(){return c&&p.useNative?(t.prop("type","date"),void t.css("-webkit-appearance","textfield")):(d&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",i)),void v())};var y=u.destroy;u.destroy=function(){c&&p.useNative&&t.off("click",i),y()};var w=u.show;u.show=function(){w(),l(function(){u.$isShown&&(u.$element.on(d?"touchstart":"mousedown",u.$onMouseDown),p.keyboard&&t.on("keydown",u.$onKeyDown))},0,!1)};var b=u.hide;return u.hide=function(e){u.$isShown&&(u.$element.off(d?"touchstart":"mousedown",u.$onMouseDown),p.keyboard&&t.off("keydown",u.$onKeyDown),b(e))},u}var c=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),d="createTouch"in t.document&&c;return e.lang||(e.lang=i.getDefaultLocale()),u.defaults=e,u}]}).directive("bsDatepicker",["$window","$parse","$q","$dateFormatter","$dateParser","$datepicker",function(e,t,n,a,o,i){var r=(i.defaults,/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent));return{restrict:"EAC",require:"ngModel",link:function(e,t,n,s){function l(e){return e&&e.length?e:null}function u(e){if(angular.isDate(e)){var t=isNaN(f.$options.minDate)||e.getTime()>=f.$options.minDate,n=isNaN(f.$options.maxDate)||e.getTime()<=f.$options.maxDate,a=t&&n;s.$setValidity("date",a),s.$setValidity("min",t),s.$setValidity("max",n),a&&(s.$dateValue=e)}}function c(){return!s.$dateValue||isNaN(s.$dateValue.getTime())?"":g(s.$dateValue,d.dateFormat)}var d={scope:e,controller:s};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","dateType","dateFormat","modelDateFormat","dayFormat","strictFormat","startWeek","startDate","useNative","lang","startView","minView","iconLeft","iconRight","daysOfWeekDisabled","id"],function(e){angular.isDefined(n[e])&&(d[e]=n[e])}),n.bsShow&&e.$watch(n.bsShow,function(e){f&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(datepicker),?/i)),e===!0?f.show():f.hide())});var f=i(t,s,d);d=f.$options,r&&d.useNative&&(d.dateFormat="yyyy-MM-dd");var p=d.lang,g=function(e,t){return a.formatDate(e,t,p)},m=o({format:d.dateFormat,lang:p,strict:d.strictFormat});angular.forEach(["minDate","maxDate"],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){f.$options[e]=m.getDateForAttribute(e,t),!isNaN(f.$options[e])&&f.$build(!1),u(s.$dateValue)})}),e.$watch(n.ngModel,function(){f.update(s.$dateValue)},!0),angular.isDefined(n.disabledDates)&&e.$watch(n.disabledDates,function(e,t){e=l(e),t=l(t),e&&f.updateDisabledDates(e)}),s.$parsers.unshift(function(e){if(!e)return s.$setValidity("date",!0),null;var t=m.parse(e,s.$dateValue);return!t||isNaN(t.getTime())?void s.$setValidity("date",!1):(u(t),"string"===d.dateType?g(t,d.modelDateFormat||d.dateFormat):"number"===d.dateType?s.$dateValue.getTime():"unix"===d.dateType?s.$dateValue.getTime()/1e3:"iso"===d.dateType?s.$dateValue.toISOString():new Date(s.$dateValue))}),s.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===d.dateType?m.parse(e,null,d.modelDateFormat):new Date("unix"===d.dateType?1e3*e:e),s.$dateValue=t,c()}),s.$render=function(){t.val(c())},e.$on("$destroy",function(){f&&f.destroy(),d=null,f=null})}}}]).provider("datepickerViews",function(){function e(e,t){for(var n=[];e.length>0;)n.push(e.splice(0,t));return n}function t(e,t){return(e%t+t)%t}this.defaults={dayFormat:"dd",daySplit:7};this.$get=["$dateFormatter","$dateParser","$sce",function(n,a,o){return function(i){var r=i.$scope,s=i.$options,l=s.lang,u=function(e,t){return n.formatDate(e,t,l)},c=a({format:s.dateFormat,lang:l,strict:s.strictFormat}),d=n.weekdaysShort(l),f=d.slice(s.startWeek).concat(d.slice(0,s.startWeek)),p=o.trustAsHtml(''+f.join('')+""),g=i.$date||(s.startDate?c.getDateForAttribute("startDate",s.startDate):new Date),m={year:g.getFullYear(),month:g.getMonth(),date:g.getDate()},$=(6e4*g.getTimezoneOffset(),[{format:s.dayFormat,split:7,steps:{month:1},update:function(e,t){!this.built||t||e.getFullYear()!==m.year||e.getMonth()!==m.month?(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build()):e.getDate()!==m.date&&(m.date=i.$date.getDate(),i.$updateSelected())},build:function(){var n=new Date(m.year,m.month,1),a=n.getTimezoneOffset(),o=new Date(+n-864e5*t(n.getDay()-s.startWeek,7)),l=o.getTimezoneOffset(),d=(new Date).toDateString();l!==a&&(o=new Date(+o+6e4*(l-a)));for(var f,g=[],$=0;42>$;$++)f=c.daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth(),o.getDate()+$)),g.push({date:f,isToday:f.toDateString()===d,label:u(f,this.format),selected:i.$date&&this.isSelected(f),muted:f.getMonth()!==m.month,disabled:this.isDisabled(f)});r.title=u(n,s.monthTitleFormat),r.showLabels=!0,r.labels=p,r.rows=e(g,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()&&e.getMonth()===i.$date.getMonth()&&e.getDate()===i.$date.getDate()},isDisabled:function(e){var t=e.getTime();if(ts.maxDate)return!0;if(-1!==s.daysOfWeekDisabled.indexOf(e.getDay()))return!0;if(s.disabledDateRanges)for(var n=0;n=s.disabledDateRanges[n].start&&t<=s.disabledDateRanges[n].end)return!0;return!1},onKeyDown:function(e){if(i.$date){var t,n=i.$date.getTime();37===e.keyCode?t=new Date(n-864e5):38===e.keyCode?t=new Date(n-6048e5):39===e.keyCode?t=new Date(n+864e5):40===e.keyCode&&(t=new Date(n+6048e5)),this.isDisabled(t)||i.select(t,!0)}}},{name:"month",format:s.monthFormat,split:4,steps:{year:1},update:function(e){this.built&&e.getFullYear()===m.year?e.getMonth()!==m.month&&(angular.extend(m,{month:i.$date.getMonth(),date:i.$date.getDate()}),i.$updateSelected()):(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build())},build:function(){for(var t,n=(new Date(m.year,0,1),[]),a=0;12>a;a++)t=new Date(m.year,a,1),n.push({date:t,label:u(t,this.format),selected:i.$isSelected(t),disabled:this.isDisabled(t)});r.title=u(t,s.yearTitleFormat),r.showLabels=!1,r.rows=e(n,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()&&e.getMonth()===i.$date.getMonth()},isDisabled:function(e){var t=+new Date(e.getFullYear(),e.getMonth()+1,0);return ts.maxDate},onKeyDown:function(e){if(i.$date){var t=i.$date.getMonth(),n=new Date(i.$date);37===e.keyCode?n.setMonth(t-1):38===e.keyCode?n.setMonth(t-4):39===e.keyCode?n.setMonth(t+1):40===e.keyCode&&n.setMonth(t+4),this.isDisabled(n)||i.select(n,!0)}}},{name:"year",format:s.yearFormat,split:4,steps:{year:12},update:function(e,t){!this.built||t||parseInt(e.getFullYear()/20,10)!==parseInt(m.year/20,10)?(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build()):e.getFullYear()!==m.year&&(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$updateSelected())},build:function(){for(var t,n=m.year-m.year%(3*this.split),a=[],o=0;12>o;o++)t=new Date(n+o,0,1),a.push({date:t,label:u(t,this.format),selected:i.$isSelected(t),disabled:this.isDisabled(t)});r.title=a[0].label+"-"+a[a.length-1].label,r.showLabels=!1,r.rows=e(a,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()},isDisabled:function(e){var t=+new Date(e.getFullYear()+1,0,0);return ts.maxDate},onKeyDown:function(e){if(i.$date){var t=i.$date.getFullYear(),n=new Date(i.$date);37===e.keyCode?n.setYear(t-1):38===e.keyCode?n.setYear(t-4):39===e.keyCode?n.setYear(t+1):40===e.keyCode&&n.setYear(t+4),this.isDisabled(n)||i.select(n,!0)}}}]);return{views:s.minView?Array.prototype.slice.call($,s.minView):$,viewDate:m}}}]}),angular.module("mgcrea.ngStrap.dropdown",["mgcrea.ngStrap.tooltip"]).provider("$dropdown",function(){var e=this.defaults={animation:"am-fade",prefixClass:"dropdown",placement:"bottom-left",template:"dropdown/dropdown.tpl.html",trigger:"click",container:!1,keyboard:!0,html:!1,delay:0};this.$get=["$window","$rootScope","$tooltip","$timeout",function(t,n,a,o){function i(t,i){function l(e){return e.target!==t[0]?e.target!==t[0]&&u.hide():void 0}{var u={},c=angular.extend({},e,i);u.$scope=c.scope&&c.scope.$new()||n.$new()}u=a(t,c);var d=t.parent();u.$onKeyDown=function(e){if(/(38|40)/.test(e.keyCode)){e.preventDefault(),e.stopPropagation();var t=angular.element(u.$element[0].querySelectorAll("li:not(.divider) a"));if(t.length){var n;angular.forEach(t,function(e,t){s&&s.call(e,":focus")&&(n=t)}),38===e.keyCode&&n>0?n--:40===e.keyCode&&no;o++)if(e[o].toLowerCase()===a)return o;return-1}e.prototype.setMilliseconds=function(e){this.milliseconds=e},e.prototype.setSeconds=function(e){this.seconds=e},e.prototype.setMinutes=function(e){this.minutes=e},e.prototype.setHours=function(e){this.hours=e},e.prototype.getHours=function(){return this.hours},e.prototype.setDate=function(e){this.day=e},e.prototype.setMonth=function(e){this.month=e},e.prototype.setFullYear=function(e){this.year=e},e.prototype.fromDate=function(e){return this.year=e.getFullYear(),this.month=e.getMonth(),this.day=e.getDate(),this.hours=e.getHours(),this.minutes=e.getMinutes(),this.seconds=e.getSeconds(),this.milliseconds=e.getMilliseconds(),this},e.prototype.toDate=function(){return new Date(this.year,this.month,this.day,this.hours,this.minutes,this.seconds,this.milliseconds)};var o=e.prototype,i=this.defaults={format:"shortDate",strict:!1};this.$get=["$locale","dateFilter",function(r,s){var l=function(l){function u(e){var t,n=Object.keys(h),a=[],o=[],i=e;for(t=0;t1){var r=i.search(n[t]);e=e.split(n[t]).join(""),h[n[t]]&&(a[r]=h[n[t]])}return angular.forEach(a,function(e){e&&o.push(e)}),o}function c(e){return e.replace(/\//g,"[\\/]").replace("/-/g","[-]").replace(/\./g,"[.]").replace(/\\s/g,"[\\s]")}function d(e){var t,n=Object.keys($),a=e;for(t=0;t12?e.getHours()+2:0),e):null},m.init(),m};return l}]}]),angular.module("mgcrea.ngStrap.helpers.debounce",[]).factory("debounce",["$timeout",function(e){return function(t,n,a){var o=null;return function(){var i=this,r=arguments,s=a&&!o;return o&&e.cancel(o),o=e(function(){o=null,a||t.apply(i,r)},n,!1),s&&t.apply(i,r),o}}}]).factory("throttle",["$timeout",function(e){return function(t,n,a){var o=null;return a||(a={}),function(){var i=this,r=arguments;o||(a.leading!==!1&&t.apply(i,r),o=e(function(){o=null,a.trailing!==!1&&t.apply(i,r)},n,!1))}}}]),angular.module("mgcrea.ngStrap.helpers.dimensions",[]).factory("dimensions",["$document","$window",function(){var t=(angular.element,{}),n=t.nodeName=function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()};t.css=function(t,n,a){var o;return o=t.currentStyle?t.currentStyle[n]:e.getComputedStyle?e.getComputedStyle(t)[n]:t.style[n],a===!0?parseFloat(o)||0:o},t.offset=function(t){var n=t.getBoundingClientRect(),a=t.ownerDocument;return{width:n.width||t.offsetWidth,height:n.height||t.offsetHeight,top:n.top+(e.pageYOffset||a.documentElement.scrollTop)-(a.documentElement.clientTop||0),left:n.left+(e.pageXOffset||a.documentElement.scrollLeft)-(a.documentElement.clientLeft||0)}},t.position=function(e){var o,i,r={top:0,left:0};return"fixed"===t.css(e,"position")?i=e.getBoundingClientRect():(o=a(e),i=t.offset(e),n(o,"html")||(r=t.offset(o)),r.top+=t.css(o,"borderTopWidth",!0),r.left+=t.css(o,"borderLeftWidth",!0)),{width:e.offsetWidth,height:e.offsetHeight,top:i.top-r.top-t.css(e,"marginTop",!0),left:i.left-r.left-t.css(e,"marginLeft",!0)}};var a=function(e){var a=e.ownerDocument,o=e.offsetParent||a;if(n(o,"#document"))return a.documentElement;for(;o&&!n(o,"html")&&"static"===t.css(o,"position");)o=o.offsetParent;return o||a.documentElement};return t.height=function(e,n){var a=e.offsetHeight;return n?a+=t.css(e,"marginTop",!0)+t.css(e,"marginBottom",!0):a-=t.css(e,"paddingTop",!0)+t.css(e,"paddingBottom",!0)+t.css(e,"borderTopWidth",!0)+t.css(e,"borderBottomWidth",!0),a},t.width=function(e,n){var a=e.offsetWidth;return n?a+=t.css(e,"marginLeft",!0)+t.css(e,"marginRight",!0):a-=t.css(e,"paddingLeft",!0)+t.css(e,"paddingRight",!0)+t.css(e,"borderLeftWidth",!0)+t.css(e,"borderRightWidth",!0),a},t}]),angular.module("mgcrea.ngStrap.helpers.parseOptions",[]).provider("$parseOptions",function(){var e=this.defaults={regexp:/^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/};this.$get=["$parse","$q",function(t,n){function a(a,o){function i(e,t){return e.map(function(e,n){var a,o,i={};return i[c]=e,a=u(t,i),o=p(t,i),{label:a,value:o,index:n}})}var r={},s=angular.extend({},e,o);r.$values=[];var l,u,c,d,f,p,g;return r.init=function(){r.$match=l=a.match(s.regexp),u=t(l[2]||l[1]),c=l[4]||l[6],d=l[5],f=t(l[3]||""),p=t(l[2]?l[1]:c),g=t(l[7])},r.valuesFn=function(e,t){return n.when(g(e,t)).then(function(t){return r.$values=t?i(t,e):{},r.$values +})},r.displayValue=function(e){var t={};return t[c]=e,u(t)},r.init(),r}return a}]}),angular.version.minor<3&&angular.version.dot<14&&angular.module("ng").factory("$$rAF",["$window","$timeout",function(e,t){var n=e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame,a=e.cancelAnimationFrame||e.webkitCancelAnimationFrame||e.mozCancelAnimationFrame||e.webkitCancelRequestAnimationFrame,o=!!n,i=o?function(e){var t=n(e);return function(){a(t)}}:function(e){var n=t(e,16.66,!1);return function(){t.cancel(n)}};return i.supported=o,i}]),angular.module("mgcrea.ngStrap.modal",["mgcrea.ngStrap.helpers.dimensions"]).provider("$modal",function(){var e=this.defaults={animation:"am-fade",backdropAnimation:"am-fade",prefixClass:"modal",prefixEvent:"modal",placement:"top",template:"modal/modal.tpl.html",contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0};this.$get=["$window","$rootScope","$compile","$q","$templateCache","$http","$animate","$timeout","$sce","dimensions",function(n,a,o,i,r,s,l,u,c){function d(t){function n(){w.$emit(d.prefixEvent+".show",u)}function i(){w.$emit(d.prefixEvent+".hide",u),v.removeClass(d.prefixClass+"-open"),d.animation&&v.removeClass(d.prefixClass+"-with-"+d.animation)}function r(e){e.target===e.currentTarget&&("static"===d.backdrop?u.focus():u.hide())}function s(e){e.preventDefault()}var u={},d=u.$options=angular.extend({},e,t);u.$promise=g(d.template);var w=u.$scope=d.scope&&d.scope.$new()||a.$new();d.element||d.container||(d.container="body"),u.$id=d.id||d.element&&d.element.attr("id")||"",m(["title","content"],function(e){d[e]&&(w[e]=c.trustAsHtml(d[e]))}),w.$hide=function(){w.$$postDigest(function(){u.hide()})},w.$show=function(){w.$$postDigest(function(){u.show()})},w.$toggle=function(){w.$$postDigest(function(){u.toggle()})},u.$isShown=w.$isShown=!1,d.contentTemplate&&(u.$promise=u.$promise.then(function(e){var n=angular.element(e);return g(d.contentTemplate).then(function(e){var a=p('[ng-bind="content"]',n[0]).removeAttr("ng-bind").html(e);return t.template||a.next().remove(),n[0].outerHTML})}));var b,D,k=angular.element('
    ');return u.$promise.then(function(e){angular.isObject(e)&&(e=e.data),d.html&&(e=e.replace(y,'ng-bind-html="')),e=$.apply(e),b=o(e),u.init()}),u.init=function(){d.show&&w.$$postDigest(function(){u.show()})},u.destroy=function(){D&&(D.remove(),D=null),k&&(k.remove(),k=null),w.$destroy()},u.show=function(){if(!u.$isShown&&!w.$emit(d.prefixEvent+".show.before",u).defaultPrevented){var e,t;angular.isElement(d.container)?(e=d.container,t=d.container[0].lastChild?angular.element(d.container[0].lastChild):null):d.container?(e=p(d.container),t=e[0].lastChild?angular.element(e[0].lastChild):null):(e=null,t=d.element),D=u.$element=b(w,function(){}),D.css({display:"block"}).addClass(d.placement),d.animation&&(d.backdrop&&k.addClass(d.backdropAnimation),D.addClass(d.animation)),d.backdrop&&l.enter(k,v,null);var a=l.enter(D,e,t,n);a&&a.then&&a.then(n),u.$isShown=w.$isShown=!0,f(w);var o=D[0];h(function(){o.focus()}),v.addClass(d.prefixClass+"-open"),d.animation&&v.addClass(d.prefixClass+"-with-"+d.animation),d.backdrop&&(D.on("click",r),k.on("click",r),k.on("wheel",s)),d.keyboard&&D.on("keyup",u.$onKeyUp)}},u.hide=function(){if(u.$isShown&&!w.$emit(d.prefixEvent+".hide.before",u).defaultPrevented){var e=l.leave(D,i);e&&e.then&&e.then(i),d.backdrop&&l.leave(k),u.$isShown=w.$isShown=!1,f(w),d.backdrop&&(D.off("click",r),k.off("click",r),k.off("wheel",s)),d.keyboard&&D.off("keyup",u.$onKeyUp)}},u.toggle=function(){u.$isShown?u.hide():u.show()},u.focus=function(){D[0].focus()},u.$onKeyUp=function(e){27===e.which&&u.$isShown&&(u.hide(),e.stopPropagation())},u}function f(e){e.$$phase||e.$root&&e.$root.$$phase||e.$digest()}function p(e,n){return angular.element((n||t).querySelectorAll(e))}function g(e){return w[e]?w[e]:w[e]=i.when(r.get(e)||s.get(e)).then(function(t){return angular.isObject(t)?(r.put(e,t.data),t.data):t})}var m=angular.forEach,$=String.prototype.trim,h=n.requestAnimationFrame||n.setTimeout,v=angular.element(n.document.body),y=/ng-bind="/gi,w={};return d}]}).directive("bsModal",["$window","$sce","$modal",function(e,t,n){return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","contentTemplate","placement","backdrop","keyboard","html","container","animation","id"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsModal&&e.$watch(o.bsModal,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.navbar",[]).provider("$navbar",function(){var e=this.defaults={activeClass:"active",routeAttr:"data-match-route",strict:!1};this.$get=function(){return{defaults:e}}}).directive("bsNavbar",["$window","$location","$navbar",function(e,t,n){var a=n.defaults;return{restrict:"A",link:function(e,n,o){var i=angular.copy(a);angular.forEach(Object.keys(a),function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),e.$watch(function(){return t.path()},function(e){var t=n[0].querySelectorAll("li["+i.routeAttr+"]");angular.forEach(t,function(t){var n=angular.element(t),a=n.attr(i.routeAttr).replace("/","\\/");i.strict&&(a="^"+a+"$");var o=new RegExp(a,["i"]);o.test(e)?n.addClass(i.activeClass):n.removeClass(i.activeClass)})})}}}]),angular.module("mgcrea.ngStrap.popover",["mgcrea.ngStrap.tooltip"]).provider("$popover",function(){var e=this.defaults={animation:"am-fade",customClass:"",container:!1,target:!1,placement:"right",template:"popover/popover.tpl.html",contentTemplate:!1,trigger:"click",keyboard:!0,html:!1,title:"",content:"",delay:0,autoClose:!1};this.$get=["$tooltip",function(t){function n(n,a){var o=angular.extend({},e,a),i=t(n,o);return o.content&&(i.$scope.content=o.content),i}return n}]}).directive("bsPopover",["$window","$sce","$popover",function(e,t,n){var a=e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,o,i){var r={scope:e};angular.forEach(["template","contentTemplate","placement","container","target","delay","trigger","keyboard","html","animation","customClass","autoClose","id"],function(e){angular.isDefined(i[e])&&(r[e]=i[e])}),angular.forEach(["title","content"],function(n){i[n]&&i.$observe(n,function(o,i){e[n]=t.trustAsHtml(o),angular.isDefined(i)&&a(function(){s&&s.$applyPlacement()})})}),i.bsPopover&&e.$watch(i.bsPopover,function(t,n){angular.isObject(t)?angular.extend(e,t):e.content=t,angular.isDefined(n)&&a(function(){s&&s.$applyPlacement()})},!0),i.bsShow&&e.$watch(i.bsShow,function(e){s&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(popover),?/i)),e===!0?s.show():s.hide())});var s=n(o,r);e.$on("$destroy",function(){s&&s.destroy(),r=null,s=null})}}}]),angular.module("mgcrea.ngStrap.select",["mgcrea.ngStrap.tooltip","mgcrea.ngStrap.helpers.parseOptions"]).provider("$select",function(){var e=this.defaults={animation:"am-fade",prefixClass:"select",prefixEvent:"$select",placement:"bottom-left",template:"select/select.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,multiple:!1,allNoneButtons:!1,sort:!0,caretHtml:' ',placeholder:"Choose among the following...",allText:"All",noneText:"None",maxLength:3,maxLengthHtml:"selected",iconCheckmark:"glyphicon glyphicon-ok"};this.$get=["$window","$document","$rootScope","$tooltip","$timeout",function(t,n,a,o,i){function r(t,n,a){var r={},s=angular.extend({},e,a);r=o(t,s);var u=r.$scope;u.$matches=[],u.$activeIndex=0,u.$isMultiple=s.multiple,u.$showAllNoneButtons=s.allNoneButtons&&s.multiple,u.$iconCheckmark=s.iconCheckmark,u.$allText=s.allText,u.$noneText=s.noneText,u.$activate=function(e){u.$$postDigest(function(){r.activate(e)})},u.$select=function(e){u.$$postDigest(function(){r.select(e)})},u.$isVisible=function(){return r.$isVisible()},u.$isActive=function(e){return r.$isActive(e)},u.$selectAll=function(){for(var e=0;e=u.$matches.length&&(u.$activeIndex=s.multiple?[]:0)},r.$isVisible=function(){return s.minLength&&n?u.$matches.length&&n.$viewValue.length>=s.minLength:u.$matches.length},r.$isActive=function(e){return s.multiple?-1!==u.$activeIndex.indexOf(e):u.$activeIndex===e},r.$getIndex=function(e){var t=u.$matches.length,n=t;if(t){for(n=t;n--&&u.$matches[n].value!==e;);if(!(0>n))return n}},r.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),l){var t=angular.element(e.target);t.triggerHandler("click")}},r.$onKeyDown=function(e){if(/(9|13|38|40)/.test(e.keyCode)){if(e.preventDefault(),e.stopPropagation(),!s.multiple&&(13===e.keyCode||9===e.keyCode))return r.select(u.$activeIndex);38===e.keyCode&&u.$activeIndex>0?u.$activeIndex--:40===e.keyCode&&u.$activeIndex'),l.after(t)}var u=o(n.ngOptions),c=a(t,r,s),d=u.$match[7].replace(/\|.+/,"").trim();e.$watch(d,function(){u.valuesFn(e,r).then(function(e){c.update(e),r.$render()})},!0),e.$watch(n.ngModel,function(){c.$updateActiveIndex(),r.$render()},!0),r.$render=function(){var e,n;s.multiple&&angular.isArray(r.$modelValue)?(e=r.$modelValue.map(function(e){return n=c.$getIndex(e),angular.isDefined(n)?c.$scope.$matches[n].label:!1}).filter(angular.isDefined),e=e.length>(s.maxLength||i.maxLength)?e.length+" "+(s.maxLengthHtml||i.maxLengthHtml):e.join(", ")):(n=c.$getIndex(r.$modelValue),e=angular.isDefined(n)?c.$scope.$matches[n].label:!1),t.html((e?e:s.placeholder)+i.caretHtml)},s.multiple&&(r.$isEmpty=function(e){return!e||0===e.length}),e.$on("$destroy",function(){c&&c.destroy(),s=null,c=null})}}}]),angular.module("mgcrea.ngStrap.tab",[]).provider("$tab",function(){var e=this.defaults={animation:"am-fade",template:"tab/tab.tpl.html",navClass:"nav-tabs",activeClass:"active"},t=this.controller=function(t,n,a){var o=this;o.$options=angular.copy(e),angular.forEach(["animation","navClass","activeClass"],function(e){angular.isDefined(a[e])&&(o.$options[e]=a[e])}),t.$navClass=o.$options.navClass,t.$activeClass=o.$options.activeClass,o.$panes=t.$panes=[],o.$activePaneChangeListeners=o.$viewChangeListeners=[],o.$push=function(e){o.$panes.push(e)},o.$remove=function(e){var t=o.$panes.indexOf(e),n=o.$panes.$active;o.$panes.splice(t,1),n>t?n--:t===n&&n===o.$panes.length&&n--,o.$setActive(n)},o.$panes.$active=0,o.$setActive=t.$setActive=function(e){o.$panes.$active=e,o.$activePaneChangeListeners.forEach(function(e){e()})}};this.$get=function(){var n={};return n.defaults=e,n.controller=t,n}}).directive("bsTabs",["$window","$animate","$tab","$parse",function(e,t,n,a){var o=n.defaults;return{require:["?ngModel","bsTabs"],transclude:!0,scope:!0,controller:["$scope","$element","$attrs",n.controller],templateUrl:function(e,t){return t.template||o.template},link:function(e,t,n,o){var i=o[0],r=o[1];if(i&&(console.warn("Usage of ngModel is deprecated, please use bsActivePane instead!"),r.$activePaneChangeListeners.push(function(){i.$setViewValue(r.$panes.$active)}),i.$formatters.push(function(e){return r.$setActive(1*e),e})),n.bsActivePane){var s=a(n.bsActivePane);r.$activePaneChangeListeners.push(function(){s.assign(e,r.$panes.$active)}),e.$watch(n.bsActivePane,function(e){r.$setActive(1*e)},!0)}}}}]).directive("bsPane",["$window","$animate","$sce",function(e,t,n){return{require:["^?ngModel","^bsTabs"],scope:!0,link:function(e,a,o,i){function r(){var n=s.$panes.indexOf(e),o=s.$panes.$active;t[n===o?"addClass":"removeClass"](a,s.$options.activeClass)}var s=(i[0],i[1]);a.addClass("tab-pane"),o.$observe("title",function(t){e.title=n.trustAsHtml(t)}),s.$options.animation&&a.addClass(s.$options.animation),s.$push(e),e.$on("$destroy",function(){s.$remove(e)}),s.$activePaneChangeListeners.push(function(){r()}),r()}}}]),angular.module("mgcrea.ngStrap.scrollspy",["mgcrea.ngStrap.helpers.debounce","mgcrea.ngStrap.helpers.dimensions"]).provider("$scrollspy",function(){var e=this.$$spies={},n=this.defaults={debounce:150,throttle:100,offset:100};this.$get=["$window","$document","$rootScope","dimensions","debounce","throttle",function(a,o,i,r,s,l){function u(e,t){return e[0].nodeName&&e[0].nodeName.toLowerCase()===t.toLowerCase()}function c(o){var c=angular.extend({},n,o);c.element||(c.element=p);var g=u(c.element,"body"),m=g?d:c.element,$=g?"window":c.id;if(e[$])return e[$].$$count++,e[$];var h,v,y,w,b,D,k,T,S={},x=S.$trackedElements=[],C=[];return S.init=function(){this.$$count=1,w=s(this.checkPosition,c.debounce),b=l(this.checkPosition,c.throttle),m.on("click",this.checkPositionWithEventLoop),d.on("resize",w),m.on("scroll",b),D=s(this.checkOffsets,c.debounce),h=i.$on("$viewContentLoaded",D),v=i.$on("$includeContentLoaded",D),D(),$&&(e[$]=S)},S.destroy=function(){this.$$count--,this.$$count>0||(m.off("click",this.checkPositionWithEventLoop),d.off("resize",w),m.off("scroll",b),h(),v(),$&&delete e[$])},S.checkPosition=function(){if(C.length){if(T=(g?a.pageYOffset:m.prop("scrollTop"))||0,k=Math.max(a.innerHeight,f.prop("clientHeight")),TC[e+1].offsetTop))return S.$activateElement(C[e])}},S.checkPositionWithEventLoop=function(){setTimeout(S.checkPosition,1)},S.$activateElement=function(e){if(y){var t=S.$getTrackedElement(y);t&&(t.source.removeClass("active"),u(t.source,"li")&&u(t.source.parent().parent(),"li")&&t.source.parent().parent().removeClass("active"))}y=e.target,e.source.addClass("active"),u(e.source,"li")&&u(e.source.parent().parent(),"li")&&e.source.parent().parent().addClass("active")},S.$getTrackedElement=function(e){return x.filter(function(t){return t.target===e})[0]},S.checkOffsets=function(){angular.forEach(x,function(e){var n=t.querySelector(e.target);e.offsetTop=n?r.offset(n).top:null,c.offset&&null!==e.offsetTop&&(e.offsetTop-=1*c.offset)}),C=x.filter(function(e){return null!==e.offsetTop}).sort(function(e,t){return e.offsetTop-t.offsetTop}),w()},S.trackElement=function(e,t){x.push({target:e,source:t})},S.untrackElement=function(e,t){for(var n,a=x.length;a--;)if(x[a].target===e&&x[a].source===t){n=a;break}x=x.splice(n,1)},S.activate=function(e){x[e].addClass("active")},S.init(),S}var d=angular.element(a),f=angular.element(o.prop("documentElement")),p=angular.element(a.document.body);return c}]}).directive("bsScrollspy",["$rootScope","debounce","dimensions","$scrollspy",function(e,t,n,a){return{restrict:"EAC",link:function(e,t,n){var o={scope:e};angular.forEach(["offset","target"],function(e){angular.isDefined(n[e])&&(o[e]=n[e])});var i=a(o);i.trackElement(o.target,t),e.$on("$destroy",function(){i&&(i.untrackElement(o.target,t),i.destroy()),o=null,i=null})}}}]).directive("bsScrollspyList",["$rootScope","debounce","dimensions","$scrollspy",function(){return{restrict:"A",compile:function(e){var t=e[0].querySelectorAll("li > a[href]");angular.forEach(t,function(e){var t=angular.element(e);t.parent().attr("bs-scrollspy","").attr("data-target",t.attr("href"))})}}}]),angular.module("mgcrea.ngStrap.timepicker",["mgcrea.ngStrap.helpers.dateParser","mgcrea.ngStrap.helpers.dateFormatter","mgcrea.ngStrap.tooltip"]).provider("$timepicker",function(){var e=this.defaults={animation:"am-fade",prefixClass:"timepicker",placement:"bottom-left",template:"timepicker/timepicker.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,useNative:!0,timeType:"date",timeFormat:"shortTime",modelTimeFormat:null,autoclose:!1,minTime:-1/0,maxTime:+1/0,length:5,hourStep:1,minuteStep:5,iconUp:"glyphicon glyphicon-chevron-up",iconDown:"glyphicon glyphicon-chevron-down",arrowBehavior:"pager"};this.$get=["$window","$document","$rootScope","$sce","$dateFormatter","$tooltip","$timeout",function(t,n,a,o,i,r,s){function l(t,n,a){function o(e,n){if(t[0].createTextRange){var a=t[0].createTextRange();a.collapse(!0),a.moveStart("character",e),a.moveEnd("character",n),a.select()}else t[0].setSelectionRange?t[0].setSelectionRange(e,n):angular.isUndefined(t[0].selectionStart)&&(t[0].selectionStart=e,t[0].selectionEnd=n)}function l(){t[0].focus()}var d=r(t,angular.extend({},e,a)),f=a.scope,p=d.$options,g=d.$scope,m=p.lang,$=function(e,t){return i.formatDate(e,t,m)},h=0,v=n.$dateValue||new Date,y={hour:v.getHours(),meridian:v.getHours()<12,minute:v.getMinutes(),second:v.getSeconds(),millisecond:v.getMilliseconds()},w=i.getDatetimeFormat(p.timeFormat,m),b=i.hoursFormat(w),D=i.timeSeparator(w),k=i.minutesFormat(w),T=i.showAM(w);g.$iconUp=p.iconUp,g.$iconDown=p.iconDown,g.$select=function(e,t){d.select(e,t)},g.$moveIndex=function(e,t){d.$moveIndex(e,t)},g.$switchMeridian=function(e){d.switchMeridian(e)},d.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())?(d.$date=e,angular.extend(y,{hour:e.getHours(),minute:e.getMinutes(),second:e.getSeconds(),millisecond:e.getMilliseconds()}),d.$build()):d.$isBuilt||d.$build()},d.select=function(e,t,a){(!n.$dateValue||isNaN(n.$dateValue.getTime()))&&(n.$dateValue=new Date(1970,0,1)),angular.isDate(e)||(e=new Date(e)),0===t?n.$dateValue.setHours(e.getHours()):1===t&&n.$dateValue.setMinutes(e.getMinutes()),n.$setViewValue(angular.copy(n.$dateValue)),n.$render(),p.autoclose&&!a&&s(function(){d.hide(!0)})},d.switchMeridian=function(e){if(n.$dateValue&&!isNaN(n.$dateValue.getTime())){var t=(e||n.$dateValue).getHours();n.$dateValue.setHours(12>t?t+12:t-12),n.$setViewValue(angular.copy(n.$dateValue)),n.$render()}},d.$build=function(){var e,t,n=g.midIndex=parseInt(p.length/2,10),a=[];for(e=0;e1*p.maxTime},g.$arrowAction=function(e,t){"picker"===p.arrowBehavior?d.$setTimeByStep(e,t):d.$moveIndex(e,t)},d.$setTimeByStep=function(e,t){{var n=new Date(d.$date),a=n.getHours(),o=($(n,b).length,n.getMinutes());$(n,k).length}0===t?n.setHours(a-parseInt(p.hourStep,10)*e):n.setMinutes(o-parseInt(p.minuteStep,10)*e),d.select(n,t,!0)},d.$moveIndex=function(e,t){var n;0===t?(n=new Date(1970,0,1,y.hour+e*p.length,y.minute),angular.extend(y,{hour:n.getHours()})):1===t&&(n=new Date(1970,0,1,y.hour,y.minute+e*p.length*p.minuteStep),angular.extend(y,{minute:n.getMinutes()})),d.$build()},d.$onMouseDown=function(e){if("input"!==e.target.nodeName.toLowerCase()&&e.preventDefault(),e.stopPropagation(),c){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},d.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return d.hide(!0);var t=new Date(d.$date),n=t.getHours(),a=$(t,b).length,i=t.getMinutes(),r=$(t,k).length,s=/(37|39)/.test(e.keyCode),l=2+1*T;s&&(37===e.keyCode?h=1>h?l-1:h-1:39===e.keyCode&&(h=l-1>h?h+1:0));var u=[0,a];0===h?(38===e.keyCode?t.setHours(n-parseInt(p.hourStep,10)):40===e.keyCode&&t.setHours(n+parseInt(p.hourStep,10)),a=$(t,b).length,u=[0,a]):1===h?(38===e.keyCode?t.setMinutes(i-parseInt(p.minuteStep,10)):40===e.keyCode&&t.setMinutes(i+parseInt(p.minuteStep,10)),r=$(t,k).length,u=[a+1,a+1+r]):2===h&&(s||d.switchMeridian(),u=[a+1+r+1,a+1+r+3]),d.select(t,h,!0),o(u[0],u[1]),f.$digest()}};var S=d.init;d.init=function(){return u&&p.useNative?(t.prop("type","time"),void t.css("-webkit-appearance","textfield")):(c&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",l)),void S())};var x=d.destroy;d.destroy=function(){u&&p.useNative&&t.off("click",l),x()};var C=d.show;d.show=function(){C(),s(function(){d.$element.on(c?"touchstart":"mousedown",d.$onMouseDown),p.keyboard&&t.on("keydown",d.$onKeyDown)},0,!1)};var M=d.hide;return d.hide=function(e){d.$isShown&&(d.$element.off(c?"touchstart":"mousedown",d.$onMouseDown),p.keyboard&&t.off("keydown",d.$onKeyDown),M(e))},d}var u=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),c="createTouch"in t.document&&u;return e.lang||(e.lang=i.getDefaultLocale()),l.defaults=e,l}]}).directive("bsTimepicker",["$window","$parse","$q","$dateFormatter","$dateParser","$timepicker",function(e,t,n,a,o,i){{var r=i.defaults,s=/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent);e.requestAnimationFrame||e.setTimeout}return{restrict:"EAC",require:"ngModel",link:function(e,t,n,l){function u(e){if(angular.isDate(e)){var t=isNaN(d.minTime)||new Date(e.getTime()).setFullYear(1970,0,1)>=d.minTime,n=isNaN(d.maxTime)||new Date(e.getTime()).setFullYear(1970,0,1)<=d.maxTime,a=t&&n;l.$setValidity("date",a),l.$setValidity("min",t),l.$setValidity("max",n),a&&(l.$dateValue=e)}}function c(){return!l.$dateValue||isNaN(l.$dateValue.getTime())?"":g(l.$dateValue,d.timeFormat)}var d={scope:e,controller:l};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","timeType","timeFormat","modelTimeFormat","useNative","hourStep","minuteStep","length","arrowBehavior","iconUp","iconDown","id"],function(e){angular.isDefined(n[e])&&(d[e]=n[e])}),n.bsShow&&e.$watch(n.bsShow,function(e){f&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(timepicker),?/i)),e===!0?f.show():f.hide())}),s&&(d.useNative||r.useNative)&&(d.timeFormat="HH:mm");var f=i(t,l,d);d=f.$options;var p=d.lang,g=function(e,t){return a.formatDate(e,t,p)},m=o({format:d.timeFormat,lang:p});angular.forEach(["minTime","maxTime"],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){f.$options[e]=m.getTimeForAttribute(e,t),!isNaN(f.$options[e])&&f.$build(),u(l.$dateValue)})}),e.$watch(n.ngModel,function(){f.update(l.$dateValue)},!0),l.$parsers.unshift(function(e){if(!e)return l.$setValidity("date",!0),null;var t=angular.isDate(e)?e:m.parse(e,l.$dateValue);return!t||isNaN(t.getTime())?void l.$setValidity("date",!1):(u(t),"string"===d.timeType?g(t,d.modelTimeFormat||d.timeFormat):"number"===d.timeType?l.$dateValue.getTime():"unix"===d.timeType?l.$dateValue.getTime()/1e3:"iso"===d.timeType?l.$dateValue.toISOString():new Date(l.$dateValue))}),l.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===d.timeType?m.parse(e,null,d.modelTimeFormat):new Date("unix"===d.timeType?1e3*e:e),l.$dateValue=t,c()}),l.$render=function(){t.val(c())},e.$on("$destroy",function(){f&&f.destroy(),d=null,f=null})}}}]),angular.module("mgcrea.ngStrap.tooltip",["mgcrea.ngStrap.helpers.dimensions"]).provider("$tooltip",function(){var e=this.defaults={animation:"am-fade",customClass:"",prefixClass:"tooltip",prefixEvent:"tooltip",container:!1,target:!1,placement:"top",template:"tooltip/tooltip.tpl.html",contentTemplate:!1,trigger:"hover focus",keyboard:!1,html:!1,show:!1,title:"",type:"",delay:0,autoClose:!1,bsEnabled:!0};this.$get=["$window","$rootScope","$compile","$q","$templateCache","$http","$animate","$sce","dimensions","$$rAF","$timeout",function(n,a,o,i,r,s,l,u,c,d,f){function p(n,i){function r(){O.$emit(P.prefixEvent+".show",F)}function s(){if(O.$emit(P.prefixEvent+".hide",F),R===W){if(U&&"focus"===P.trigger)return n[0].blur();A()}}function p(){var e=P.trigger.split(" ");angular.forEach(e,function(e){"click"===e?n.on("click",F.toggle):"manual"!==e&&(n.on("hover"===e?"mouseenter":"focus",F.enter),n.on("hover"===e?"mouseleave":"blur",F.leave),"button"===V&&"hover"!==e&&n.on(v?"touchstart":"mousedown",F.$onFocusElementMouseDown))})}function b(){for(var e=P.trigger.split(" "),t=e.length;t--;){var a=e[t];"click"===a?n.off("click",F.toggle):"manual"!==a&&(n.off("hover"===a?"mouseenter":"focus",F.enter),n.off("hover"===a?"mouseleave":"blur",F.leave),"button"===V&&"hover"!==a&&n.off(v?"touchstart":"mousedown",F.$onFocusElementMouseDown))}}function D(){"focus"!==P.trigger?R.on("keyup",F.$onKeyUp):n.on("keyup",F.$onFocusKeyUp)}function k(){"focus"!==P.trigger?R.off("keyup",F.$onKeyUp):n.off("keyup",F.$onFocusKeyUp)}function T(){f(function(){R.on("click",x),w.on("click",F.hide),j=!0},0,!1)}function S(){j&&(R.off("click",x),w.off("click",F.hide),j=!1)}function x(e){e.stopPropagation()}function C(e){e=e||P.target||n;var t=e[0],a=t.getBoundingClientRect();null===a.width&&(a=angular.extend({},a,{width:a.right-a.left,height:a.bottom-a.top}));var o;return o="body"===P.container?c.offset(t):c.position(t),angular.extend({},a,o)}function M(e,t,n,a){var o,i=e.split("-");switch(i[0]){case"right":o={top:t.top+t.height/2-a/2,left:t.left+t.width};break;case"bottom":o={top:t.top+t.height,left:t.left+t.width/2-n/2};break;case"left":o={top:t.top+t.height/2-a/2,left:t.left-n};break;default:o={top:t.top-a,left:t.left+t.width/2-n/2}}if(!i[1])return o;if("top"===i[0]||"bottom"===i[0])switch(i[1]){case"left":o.left=t.left;break;case"right":o.left=t.left+t.width-n}else if("left"===i[0]||"right"===i[0])switch(i[1]){case"top":o.top=t.top-a;break;case"bottom":o.top=t.top+t.height}return o}function E(e,t){R.css({top:e+"px",left:t+"px"})}function A(){clearTimeout(H),F.$isShown&&null!==R&&(P.autoClose&&S(),P.keyboard&&k()),K&&(K.$destroy(),K=null),R&&(R.remove(),R=F.$element=null)}var F={},V=n[0].nodeName.toLowerCase(),P=F.$options=angular.extend({},e,i);F.$promise=$(P.template);var O=F.$scope=P.scope&&P.scope.$new()||a.$new();if(P.delay&&angular.isString(P.delay)){var I=P.delay.split(",").map(parseFloat);P.delay=I.length>1?{show:I[0],hide:I[1]}:I[0]}F.$id=P.id||n.attr("id")||"",P.title&&(O.title=u.trustAsHtml(P.title)),O.$setEnabled=function(e){O.$$postDigest(function(){F.setEnabled(e)})},O.$hide=function(){O.$$postDigest(function(){F.hide()})},O.$show=function(){O.$$postDigest(function(){F.show()})},O.$toggle=function(){O.$$postDigest(function(){F.toggle()})},F.$isShown=O.$isShown=!1;var H,N;P.contentTemplate&&(F.$promise=F.$promise.then(function(e){var t=angular.element(e);return $(P.contentTemplate).then(function(e){var n=m('[ng-bind="content"]',t[0]);return n.length||(n=m('[ng-bind="title"]',t[0])),n.removeAttr("ng-bind").html(e),t[0].outerHTML})}));var L,R,q,Y,K;F.$promise.then(function(e){angular.isObject(e)&&(e=e.data),P.html&&(e=e.replace(y,'ng-bind-html="')),e=h.apply(e),q=e,L=o(e),F.init()}),F.init=function(){P.delay&&angular.isNumber(P.delay)&&(P.delay={show:P.delay,hide:P.delay}),"self"===P.container?Y=n:angular.isElement(P.container)?Y=P.container:P.container&&(Y=m(P.container)),p(),P.target&&(P.target=angular.isElement(P.target)?P.target:m(P.target)),P.show&&O.$$postDigest(function(){"focus"===P.trigger?n[0].focus():F.show()})},F.destroy=function(){b(),A(),O.$destroy()},F.enter=function(){return clearTimeout(H),N="in",P.delay&&P.delay.show?void(H=setTimeout(function(){"in"===N&&F.show()},P.delay.show)):F.show()},F.show=function(){if(P.bsEnabled&&!F.$isShown){O.$emit(P.prefixEvent+".show.before",F);var e,t;P.container?(e=Y,t=Y[0].lastChild?angular.element(Y[0].lastChild):null):(e=null,t=n),R&&A(),K=F.$scope.$new(),R=F.$element=L(K,function(){}),R.css({top:"-9999px",left:"-9999px",display:"block",visibility:"hidden"}),P.animation&&R.addClass(P.animation),P.type&&R.addClass(P.prefixClass+"-"+P.type),P.customClass&&R.addClass(P.customClass);var a=l.enter(R,e,t,r);a&&a.then&&a.then(r),F.$isShown=O.$isShown=!0,g(O),d(function(){F.$applyPlacement(),R&&R.css({visibility:"visible"})}),P.keyboard&&("focus"!==P.trigger&&F.focus(),D()),P.autoClose&&T()}},F.leave=function(){return clearTimeout(H),N="out",P.delay&&P.delay.hide?void(H=setTimeout(function(){"out"===N&&F.hide()},P.delay.hide)):F.hide()};var U,W;F.hide=function(e){if(F.$isShown){O.$emit(P.prefixEvent+".hide.before",F),U=e,W=R;var t=l.leave(R,s);t&&t.then&&t.then(s),F.$isShown=O.$isShown=!1,g(O),P.keyboard&&null!==R&&k(),P.autoClose&&null!==R&&S()}},F.toggle=function(){F.$isShown?F.leave():F.enter()},F.focus=function(){R[0].focus()},F.setEnabled=function(e){P.bsEnabled=e},F.$applyPlacement=function(){if(R){var a=P.placement,o=/\s?auto?\s?/i,i=o.test(a);i&&(a=a.replace(o,"")||e.placement),R.addClass(P.placement);var r=C(),s=R.prop("offsetWidth"),l=R.prop("offsetHeight");if(i){var u=a,c=P.container?angular.element(t.querySelector(P.container)):n.parent(),d=C(c);u.indexOf("bottom")>=0&&r.bottom+l>d.bottom?a=u.replace("bottom","top"):u.indexOf("top")>=0&&r.top-ld.width?a="right"===u?"left":a.replace("left","right"):("left"===u||"bottom-right"===u||"top-right"===u)&&r.left-s=e.length&&(u.$activeIndex=0)},r.activate=function(e){u.$activeIndex=e},r.select=function(e){var t=u.$matches[e].value;n.$setViewValue(t),n.$render(),u.$resetMatches(),l&&l.$digest(),u.$emit(s.prefixEvent+".select",t,e,r)},r.$isVisible=function(){return s.minLength&&n?u.$matches.length&&angular.isString(n.$viewValue)&&n.$viewValue.length>=s.minLength:!!u.$matches.length},r.$getIndex=function(e){var t=u.$matches.length,n=t;if(t){for(n=t;n--&&u.$matches[n].value!==e;);if(!(0>n))return n}},r.$onMouseDown=function(e){e.preventDefault(),e.stopPropagation()},r.$onKeyDown=function(e){/(38|40|13)/.test(e.keyCode)&&(r.$isVisible()&&(e.preventDefault(),e.stopPropagation()),13===e.keyCode&&u.$matches.length?r.select(u.$activeIndex):38===e.keyCode&&u.$activeIndex>0?u.$activeIndex--:40===e.keyCode&&u.$activeIndex0)return void s.$setViewValue(s.$viewValue.substring(0,s.$viewValue.length-1));e.length>c&&(e=e.slice(0,c));var n=g.$isVisible();n&&g.update(e),(1!==e.length||e[0].value!==t)&&(!n&&g.update(e),s.$render())})}),s.$formatters.push(function(e){var t=p.displayValue(e);return t===n?"":t}),s.$render=function(){if(s.$isEmpty(s.$viewValue))return t.val("");var e=g.$getIndex(s.$modelValue),n=angular.isDefined(e)?g.$scope.$matches[e].label:s.$viewValue;n=angular.isObject(n)?p.displayValue(n):n,t.val(n?n.toString().replace(/<(?:.|\n)*?>/gm,"").trim():"")},e.$on("$destroy",function(){g&&g.destroy(),l=null,g=null})}}}])}(window,document); +//# sourceMappingURL=angular-strap.min.js.map \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/libs/angular-strap_2.1.6/angular-strap.min.js.map b/snow-flowable/src/main/resources/static/libs/angular-strap_2.1.6/angular-strap.min.js.map new file mode 100644 index 0000000..94d507a --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-strap_2.1.6/angular-strap.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["module.js","affix/affix.js","alert/alert.js","aside/aside.js","button/button.js","collapse/collapse.js","datepicker/datepicker.js","dropdown/dropdown.js","helpers/date-formatter.js","helpers/date-parser.js","helpers/debounce.js","helpers/dimensions.js","helpers/parse-options.js","helpers/raf.js","modal/modal.js","navbar/navbar.js","popover/popover.js","select/select.js","tab/tab.js","scrollspy/scrollspy.js","timepicker/timepicker.js","tooltip/tooltip.js","typeahead/typeahead.js"],"names":[],"mappings":"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","file":"angular-strap.min.js","sourcesContent":["\nangular.module('mgcrea.ngStrap', [\n 'mgcrea.ngStrap.modal',\n 'mgcrea.ngStrap.aside',\n 'mgcrea.ngStrap.alert',\n 'mgcrea.ngStrap.button',\n 'mgcrea.ngStrap.select',\n 'mgcrea.ngStrap.datepicker',\n 'mgcrea.ngStrap.timepicker',\n 'mgcrea.ngStrap.navbar',\n 'mgcrea.ngStrap.tooltip',\n 'mgcrea.ngStrap.popover',\n 'mgcrea.ngStrap.dropdown',\n 'mgcrea.ngStrap.typeahead',\n 'mgcrea.ngStrap.scrollspy',\n 'mgcrea.ngStrap.affix',\n 'mgcrea.ngStrap.tab',\n 'mgcrea.ngStrap.collapse'\n]);\n","'use strict';\n\nangular.module('mgcrea.ngStrap.affix', ['mgcrea.ngStrap.helpers.dimensions', 'mgcrea.ngStrap.helpers.debounce'])\n\n .provider('$affix', function() {\n\n var defaults = this.defaults = {\n offsetTop: 'auto'\n };\n\n this.$get = function($window, debounce, dimensions) {\n\n var bodyEl = angular.element($window.document.body);\n var windowEl = angular.element($window);\n\n function AffixFactory(element, config) {\n\n var $affix = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n var targetEl = options.target;\n\n // Initial private vars\n var reset = 'affix affix-top affix-bottom',\n setWidth = false,\n initialAffixTop = 0,\n initialOffsetTop = 0,\n offsetTop = 0,\n offsetBottom = 0,\n affixed = null,\n unpin = null;\n\n var parent = element.parent();\n // Options: custom parent\n if (options.offsetParent) {\n if (options.offsetParent.match(/^\\d+$/)) {\n for (var i = 0; i < (options.offsetParent * 1) - 1; i++) {\n parent = parent.parent();\n }\n }\n else {\n parent = angular.element(options.offsetParent);\n }\n }\n\n $affix.init = function() {\n\n this.$parseOffsets();\n initialOffsetTop = dimensions.offset(element[0]).top + initialAffixTop;\n setWidth = !element[0].style.width;\n\n // Bind events\n targetEl.on('scroll', this.checkPosition);\n targetEl.on('click', this.checkPositionWithEventLoop);\n windowEl.on('resize', this.$debouncedOnResize);\n\n // Both of these checkPosition() calls are necessary for the case where\n // the user hits refresh after scrolling to the bottom of the page.\n this.checkPosition();\n this.checkPositionWithEventLoop();\n\n };\n\n $affix.destroy = function() {\n\n // Unbind events\n targetEl.off('scroll', this.checkPosition);\n targetEl.off('click', this.checkPositionWithEventLoop);\n windowEl.off('resize', this.$debouncedOnResize);\n\n };\n\n $affix.checkPositionWithEventLoop = function() {\n\n // IE 9 throws an error if we use 'this' instead of '$affix'\n // in this setTimeout call\n setTimeout($affix.checkPosition, 1);\n\n };\n\n $affix.checkPosition = function() {\n // if (!this.$element.is(':visible')) return\n\n var scrollTop = getScrollTop();\n var position = dimensions.offset(element[0]);\n var elementHeight = dimensions.height(element[0]);\n\n // Get required affix class according to position\n var affix = getRequiredAffixClass(unpin, position, elementHeight);\n\n // Did affix status changed this last check?\n if(affixed === affix) return;\n affixed = affix;\n\n // Add proper affix class\n element.removeClass(reset).addClass('affix' + ((affix !== 'middle') ? '-' + affix : ''));\n\n if(affix === 'top') {\n unpin = null;\n element.css('position', (options.offsetParent) ? '' : 'relative');\n if(setWidth) {\n element.css('width', '');\n }\n element.css('top', '');\n } else if(affix === 'bottom') {\n if (options.offsetUnpin) {\n unpin = -(options.offsetUnpin * 1);\n }\n else {\n // Calculate unpin threshold when affixed to bottom.\n // Hopefully the browser scrolls pixel by pixel.\n unpin = position.top - scrollTop;\n }\n if(setWidth) {\n element.css('width', '');\n }\n element.css('position', (options.offsetParent) ? '' : 'relative');\n element.css('top', (options.offsetParent) ? '' : ((bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop) + 'px'));\n } else { // affix === 'middle'\n unpin = null;\n if(setWidth) {\n element.css('width', element[0].offsetWidth + 'px');\n }\n element.css('position', 'fixed');\n element.css('top', initialAffixTop + 'px');\n }\n\n };\n\n $affix.$onResize = function() {\n $affix.$parseOffsets();\n $affix.checkPosition();\n };\n $affix.$debouncedOnResize = debounce($affix.$onResize, 50);\n\n $affix.$parseOffsets = function() {\n var initialPosition = element.css('position');\n // Reset position to calculate correct offsetTop\n element.css('position', (options.offsetParent) ? '' : 'relative');\n\n if(options.offsetTop) {\n if(options.offsetTop === 'auto') {\n options.offsetTop = '+0';\n }\n if(options.offsetTop.match(/^[-+]\\d+$/)) {\n initialAffixTop = - options.offsetTop * 1;\n if(options.offsetParent) {\n offsetTop = dimensions.offset(parent[0]).top + (options.offsetTop * 1);\n }\n else {\n offsetTop = dimensions.offset(element[0]).top - dimensions.css(element[0], 'marginTop', true) + (options.offsetTop * 1);\n }\n }\n else {\n offsetTop = options.offsetTop * 1;\n }\n }\n\n if(options.offsetBottom) {\n if(options.offsetParent && options.offsetBottom.match(/^[-+]\\d+$/)) {\n // add 1 pixel due to rounding problems...\n offsetBottom = getScrollHeight() - (dimensions.offset(parent[0]).top + dimensions.height(parent[0])) + (options.offsetBottom * 1) + 1;\n }\n else {\n offsetBottom = options.offsetBottom * 1;\n }\n }\n\n // Bring back the element's position after calculations\n element.css('position', initialPosition);\n };\n\n // Private methods\n\n function getRequiredAffixClass(unpin, position, elementHeight) {\n\n var scrollTop = getScrollTop();\n var scrollHeight = getScrollHeight();\n\n if(scrollTop <= offsetTop) {\n return 'top';\n } else if(unpin !== null && (scrollTop + unpin <= position.top)) {\n return 'middle';\n } else if(offsetBottom !== null && (position.top + elementHeight + initialAffixTop >= scrollHeight - offsetBottom)) {\n return 'bottom';\n } else {\n return 'middle';\n }\n\n }\n\n function getScrollTop() {\n return targetEl[0] === $window ? $window.pageYOffset : targetEl[0].scrollTop;\n }\n\n function getScrollHeight() {\n return targetEl[0] === $window ? $window.document.body.scrollHeight : targetEl[0].scrollHeight;\n }\n\n $affix.init();\n return $affix;\n\n }\n\n return AffixFactory;\n\n };\n\n })\n\n .directive('bsAffix', function($affix, $window) {\n\n return {\n restrict: 'EAC',\n require: '^?bsAffixTarget',\n link: function postLink(scope, element, attr, affixTarget) {\n\n var options = {scope: scope, offsetTop: 'auto', target: affixTarget ? affixTarget.$element : angular.element($window)};\n angular.forEach(['offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n var affix = $affix(element, options);\n scope.$on('$destroy', function() {\n affix && affix.destroy();\n options = null;\n affix = null;\n });\n\n }\n };\n\n })\n\n .directive('bsAffixTarget', function() {\n return {\n controller: function($element) {\n this.$element = $element;\n }\n };\n });\n","'use strict';\n\n// @BUG: following snippet won't compile correctly\n// @TODO: submit issue to core\n// ' ' +\n\nangular.module('mgcrea.ngStrap.alert', ['mgcrea.ngStrap.modal'])\n\n .provider('$alert', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'alert',\n prefixEvent: 'alert',\n placement: null,\n template: 'alert/alert.tpl.html',\n container: false,\n element: null,\n backdrop: false,\n keyboard: true,\n show: true,\n // Specific options\n duration: false,\n type: false,\n dismissable: true\n };\n\n this.$get = function($modal, $timeout) {\n\n function AlertFactory(config) {\n\n var $alert = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $alert = $modal(options);\n\n // Support scope as string options [/*title, content, */ type, dismissable]\n $alert.$scope.dismissable = !!options.dismissable;\n if(options.type) {\n $alert.$scope.type = options.type;\n }\n\n // Support auto-close duration\n var show = $alert.show;\n if(options.duration) {\n $alert.show = function() {\n show();\n $timeout(function() {\n $alert.hide();\n }, options.duration * 1000);\n };\n }\n\n return $alert;\n\n }\n\n return AlertFactory;\n\n };\n\n })\n\n .directive('bsAlert', function($window, $sce, $alert) {\n\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope, element: element, show: false};\n angular.forEach(['template', 'placement', 'keyboard', 'html', 'container', 'animation', 'duration', 'dismissable'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content', 'type'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n });\n });\n\n // Support scope as an object\n attr.bsAlert && scope.$watch(attr.bsAlert, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n }, true);\n\n // Initialize alert\n var alert = $alert(options);\n\n // Trigger\n element.on(attr.trigger || 'click', alert.toggle);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (alert) alert.destroy();\n options = null;\n alert = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.aside', ['mgcrea.ngStrap.modal'])\n\n .provider('$aside', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade-and-slide-right',\n prefixClass: 'aside',\n prefixEvent: 'aside',\n placement: 'right',\n template: 'aside/aside.tpl.html',\n contentTemplate: false,\n container: false,\n element: null,\n backdrop: true,\n keyboard: true,\n html: false,\n show: true\n };\n\n this.$get = function($modal) {\n\n function AsideFactory(config) {\n\n var $aside = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $aside = $modal(options);\n\n return $aside;\n\n }\n\n return AsideFactory;\n\n };\n\n })\n\n .directive('bsAside', function($window, $sce, $aside) {\n\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n // Directive options\n var options = {scope: scope, element: element, show: false};\n angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n });\n });\n\n // Support scope as an object\n attr.bsAside && scope.$watch(attr.bsAside, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n }, true);\n\n // Initialize aside\n var aside = $aside(options);\n\n // Trigger\n element.on(attr.trigger || 'click', aside.toggle);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (aside) aside.destroy();\n options = null;\n aside = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.button', [])\n\n .provider('$button', function() {\n\n var defaults = this.defaults = {\n activeClass:'active',\n toggleEvent:'click'\n };\n\n this.$get = function() {\n return {defaults: defaults};\n };\n\n })\n\n .directive('bsCheckboxGroup', function() {\n\n return {\n restrict: 'A',\n require: 'ngModel',\n compile: function postLink(element, attr) {\n element.attr('data-toggle', 'buttons');\n element.removeAttr('ng-model');\n var children = element[0].querySelectorAll('input[type=\"checkbox\"]');\n angular.forEach(children, function(child) {\n var childEl = angular.element(child);\n childEl.attr('bs-checkbox', '');\n childEl.attr('ng-model', attr.ngModel + '.' + childEl.attr('value'));\n });\n }\n\n };\n\n })\n\n .directive('bsCheckbox', function($button, $$rAF) {\n\n var defaults = $button.defaults;\n var constantValueRegExp = /^(true|false|\\d+)$/;\n\n return {\n restrict: 'A',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n var options = defaults;\n\n // Support label > input[type=\"checkbox\"]\n var isInput = element[0].nodeName === 'INPUT';\n var activeElement = isInput ? element.parent() : element;\n\n var trueValue = angular.isDefined(attr.trueValue) ? attr.trueValue : true;\n if(constantValueRegExp.test(attr.trueValue)) {\n trueValue = scope.$eval(attr.trueValue);\n }\n var falseValue = angular.isDefined(attr.falseValue) ? attr.falseValue : false;\n if(constantValueRegExp.test(attr.falseValue)) {\n falseValue = scope.$eval(attr.falseValue);\n }\n\n // Parse exotic values\n var hasExoticValues = typeof trueValue !== 'boolean' || typeof falseValue !== 'boolean';\n if(hasExoticValues) {\n controller.$parsers.push(function(viewValue) {\n // console.warn('$parser', element.attr('ng-model'), 'viewValue', viewValue);\n return viewValue ? trueValue : falseValue;\n });\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n return angular.equals(modelValue, trueValue);\n });\n // Fix rendering for exotic values\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n controller.$render();\n });\n }\n\n // model -> view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n var isActive = angular.equals(controller.$modelValue, trueValue);\n $$rAF(function() {\n if(isInput) element[0].checked = isActive;\n activeElement.toggleClass(options.activeClass, isActive);\n });\n };\n\n // view -> model\n element.bind(options.toggleEvent, function() {\n scope.$apply(function () {\n // console.warn('!click', element.attr('ng-model'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue);\n if(!isInput) {\n controller.$setViewValue(!activeElement.hasClass('active'));\n }\n if(!hasExoticValues) {\n controller.$render();\n }\n });\n });\n\n }\n\n };\n\n })\n\n .directive('bsRadioGroup', function() {\n\n return {\n restrict: 'A',\n require: 'ngModel',\n compile: function postLink(element, attr) {\n element.attr('data-toggle', 'buttons');\n element.removeAttr('ng-model');\n var children = element[0].querySelectorAll('input[type=\"radio\"]');\n angular.forEach(children, function(child) {\n angular.element(child).attr('bs-radio', '');\n angular.element(child).attr('ng-model', attr.ngModel);\n });\n }\n\n };\n\n })\n\n .directive('bsRadio', function($button, $$rAF) {\n\n var defaults = $button.defaults;\n var constantValueRegExp = /^(true|false|\\d+)$/;\n\n return {\n restrict: 'A',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n var options = defaults;\n\n // Support `label > input[type=\"radio\"]` markup\n var isInput = element[0].nodeName === 'INPUT';\n var activeElement = isInput ? element.parent() : element;\n\n var value = constantValueRegExp.test(attr.value) ? scope.$eval(attr.value) : attr.value;\n\n // model -> view\n controller.$render = function () {\n // console.warn('$render', element.attr('value'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n var isActive = angular.equals(controller.$modelValue, value);\n $$rAF(function() {\n if(isInput) element[0].checked = isActive;\n activeElement.toggleClass(options.activeClass, isActive);\n });\n };\n\n // view -> model\n element.bind(options.toggleEvent, function() {\n scope.$apply(function () {\n // console.warn('!click', element.attr('value'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue);\n controller.$setViewValue(value);\n controller.$render();\n });\n });\n\n }\n\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.collapse', [])\n\n .provider('$collapse', function() {\n\n var defaults = this.defaults = {\n animation: 'am-collapse',\n disallowToggle: false,\n activeClass: 'in',\n startCollapsed: false,\n allowMultiple: false\n };\n\n var controller = this.controller = function($scope, $element, $attrs) {\n var self = this;\n\n // Attributes options\n self.$options = angular.copy(defaults);\n angular.forEach(['animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple'], function (key) {\n if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];\n });\n\n self.$toggles = [];\n self.$targets = [];\n\n self.$viewChangeListeners = [];\n\n self.$registerToggle = function(element) {\n self.$toggles.push(element);\n };\n self.$registerTarget = function(element) {\n self.$targets.push(element);\n };\n\n self.$unregisterToggle = function(element) {\n var index = self.$toggles.indexOf(element);\n // remove toggle from $toggles array\n self.$toggles.splice(index, 1);\n };\n self.$unregisterTarget = function(element) {\n var index = self.$targets.indexOf(element);\n\n // remove element from $targets array\n self.$targets.splice(index, 1);\n\n if (self.$options.allowMultiple) {\n // remove target index from $active array values\n deactivateItem(element);\n }\n\n // fix active item indexes\n fixActiveItemIndexes(index);\n\n self.$viewChangeListeners.forEach(function(fn) {\n fn();\n });\n };\n\n // use array to store all the currently open panels\n self.$targets.$active = !self.$options.startCollapsed ? [0] : [];\n self.$setActive = $scope.$setActive = function(value) {\n if(angular.isArray(value)) {\n self.$targets.$active = angular.copy(value);\n }\n else if(!self.$options.disallowToggle) {\n // toogle element active status\n isActive(value) ? deactivateItem(value) : activateItem(value);\n } else {\n activateItem(value);\n }\n\n self.$viewChangeListeners.forEach(function(fn) {\n fn();\n });\n };\n\n self.$activeIndexes = function() {\n return self.$options.allowMultiple ? self.$targets.$active :\n self.$targets.$active.length === 1 ? self.$targets.$active[0] : -1;\n };\n\n function fixActiveItemIndexes(index) {\n // item with index was removed, so we\n // need to adjust other items index values\n var activeIndexes = self.$targets.$active;\n for(var i = 0; i < activeIndexes.length; i++) {\n if (index < activeIndexes[i]) {\n activeIndexes[i] = activeIndexes[i] - 1;\n }\n\n // the last item is active, so we need to\n // adjust its index\n if (activeIndexes[i] === self.$targets.length) {\n activeIndexes[i] = self.$targets.length - 1;\n }\n }\n }\n\n function isActive(value) {\n var activeItems = self.$targets.$active;\n return activeItems.indexOf(value) === -1 ? false : true;\n }\n\n function deactivateItem(value) {\n var index = self.$targets.$active.indexOf(value);\n if (index !== -1) {\n self.$targets.$active.splice(index, 1);\n }\n }\n\n function activateItem(value) {\n if (!self.$options.allowMultiple) {\n // remove current selected item\n self.$targets.$active.splice(0, 1);\n }\n\n if (self.$targets.$active.indexOf(value) === -1) {\n self.$targets.$active.push(value);\n }\n }\n\n };\n\n this.$get = function() {\n var $collapse = {};\n $collapse.defaults = defaults;\n $collapse.controller = controller;\n return $collapse;\n };\n\n })\n\n .directive('bsCollapse', function($window, $animate, $collapse) {\n\n var defaults = $collapse.defaults;\n\n return {\n require: ['?ngModel', 'bsCollapse'],\n controller: ['$scope', '$element', '$attrs', $collapse.controller],\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsCollapseCtrl = controllers[1];\n\n if(ngModelCtrl) {\n\n // Update the modelValue following\n bsCollapseCtrl.$viewChangeListeners.push(function() {\n ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes());\n });\n\n // modelValue -> $formatters -> viewValue\n ngModelCtrl.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n if (angular.isArray(modelValue)) {\n // model value is an array, so just replace\n // the active items directly\n bsCollapseCtrl.$setActive(modelValue);\n }\n else {\n var activeIndexes = bsCollapseCtrl.$activeIndexes();\n\n if (angular.isArray(activeIndexes)) {\n // we have an array of selected indexes\n if (activeIndexes.indexOf(modelValue * 1) === -1) {\n // item with modelValue index is not active\n bsCollapseCtrl.$setActive(modelValue * 1);\n }\n }\n else if (activeIndexes !== modelValue * 1) {\n bsCollapseCtrl.$setActive(modelValue * 1);\n }\n }\n return modelValue;\n });\n\n }\n\n }\n };\n\n })\n\n .directive('bsCollapseToggle', function() {\n\n return {\n require: ['^?ngModel', '^bsCollapse'],\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsCollapseCtrl = controllers[1];\n\n // Add base attr\n element.attr('data-toggle', 'collapse');\n\n // Push pane to parent bsCollapse controller\n bsCollapseCtrl.$registerToggle(element);\n\n // remove toggle from collapse controller when toggle is destroyed\n scope.$on('$destroy', function() {\n bsCollapseCtrl.$unregisterToggle(element);\n });\n\n element.on('click', function() {\n var index = attrs.bsCollapseToggle || bsCollapseCtrl.$toggles.indexOf(element);\n bsCollapseCtrl.$setActive(index * 1);\n scope.$apply();\n });\n\n }\n };\n\n })\n\n .directive('bsCollapseTarget', function($animate) {\n\n return {\n require: ['^?ngModel', '^bsCollapse'],\n // scope: true,\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsCollapseCtrl = controllers[1];\n\n // Add base class\n element.addClass('collapse');\n\n // Add animation class\n if(bsCollapseCtrl.$options.animation) {\n element.addClass(bsCollapseCtrl.$options.animation);\n }\n\n // Push pane to parent bsCollapse controller\n bsCollapseCtrl.$registerTarget(element);\n\n // remove pane target from collapse controller when target is destroyed\n scope.$on('$destroy', function() {\n bsCollapseCtrl.$unregisterTarget(element);\n });\n\n function render() {\n var index = bsCollapseCtrl.$targets.indexOf(element);\n var active = bsCollapseCtrl.$activeIndexes();\n var action = 'removeClass';\n if (angular.isArray(active)) {\n if (active.indexOf(index) !== -1) {\n action = 'addClass';\n }\n }\n else if (index === active) {\n action = 'addClass';\n }\n\n $animate[action](element, bsCollapseCtrl.$options.activeClass);\n }\n\n bsCollapseCtrl.$viewChangeListeners.push(function() {\n render();\n });\n render();\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.datepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$datepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'datepicker',\n placement: 'bottom-left',\n template: 'datepicker/datepicker.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n // lang: $locale.id,\n useNative: false,\n dateType: 'date',\n dateFormat: 'shortDate',\n modelDateFormat: null,\n dayFormat: 'dd',\n monthFormat: 'MMM',\n yearFormat: 'yyyy',\n monthTitleFormat: 'MMMM yyyy',\n yearTitleFormat: 'yyyy',\n strictFormat: false,\n autoclose: false,\n minDate: -Infinity,\n maxDate: +Infinity,\n startView: 0,\n minView: 0,\n startWeek: 0,\n daysOfWeekDisabled: '',\n iconLeft: 'glyphicon glyphicon-chevron-left',\n iconRight: 'glyphicon glyphicon-chevron-right'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function DatepickerFactory(element, controller, config) {\n\n var $datepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $datepicker.$options;\n var scope = $datepicker.$scope;\n if(options.startView) options.startView -= options.minView;\n\n // View vars\n\n var pickerViews = datepickerViews($datepicker);\n $datepicker.$views = pickerViews.views;\n var viewDate = pickerViews.viewDate;\n scope.$mode = options.startView;\n scope.$iconLeft = options.iconLeft;\n scope.$iconRight = options.iconRight;\n var $picker = $datepicker.$views[scope.$mode];\n\n // Scope methods\n\n scope.$select = function(date) {\n $datepicker.select(date);\n };\n scope.$selectPane = function(value) {\n $datepicker.$selectPane(value);\n };\n scope.$toggleMode = function() {\n $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);\n };\n\n // Public methods\n\n $datepicker.update = function(date) {\n // console.warn('$datepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $datepicker.$date = date;\n $picker.update.call($picker, date);\n }\n // Build only if pristine\n $datepicker.$build(true);\n };\n\n $datepicker.updateDisabledDates = function(dateRanges) {\n options.disabledDateRanges = dateRanges;\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);\n }\n };\n\n $datepicker.select = function(date, keep) {\n // console.warn('$datepicker.select', date, scope.$mode);\n if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);\n if(!scope.$mode || keep) {\n controller.$setViewValue(angular.copy(date));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $datepicker.hide(true); });\n }\n } else {\n angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()});\n $datepicker.setMode(scope.$mode - 1);\n $datepicker.$build();\n }\n };\n\n $datepicker.setMode = function(mode) {\n // console.warn('$datepicker.setMode', mode);\n scope.$mode = mode;\n $picker = $datepicker.$views[scope.$mode];\n $datepicker.$build();\n };\n\n // Protected methods\n\n $datepicker.$build = function(pristine) {\n // console.warn('$datepicker.$build() viewDate=%o', viewDate);\n if(pristine === true && $picker.built) return;\n if(pristine === false && !$picker.built) return;\n $picker.build.call($picker);\n };\n\n $datepicker.$updateSelected = function() {\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], updateSelected);\n }\n };\n\n $datepicker.$isSelected = function(date) {\n return $picker.isSelected(date);\n };\n\n $datepicker.$setDisabledEl = function(el) {\n el.disabled = $picker.isDisabled(el.date);\n };\n\n $datepicker.$selectPane = function(value) {\n var steps = $picker.steps;\n // set targetDate to first day of month to avoid problems with\n // date values rollover. This assumes the viewDate does not\n // depend on the day of the month\n var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1));\n angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()});\n $datepicker.$build();\n };\n\n $datepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $datepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n if(evt.keyCode === 13) {\n if(!scope.$mode) {\n return $datepicker.hide(true);\n } else {\n return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); });\n }\n }\n\n // Navigate with keyboard\n $picker.onKeyDown(evt);\n parentScope.$digest();\n };\n\n // Private\n\n function updateSelected(el) {\n el.selected = $datepicker.$isSelected(el.date);\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $datepicker.init;\n $datepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'date');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $datepicker.destroy;\n $datepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $datepicker.show;\n $datepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n // if $datepicker is no longer showing, don't setup events\n if(!$datepicker.$isShown) return;\n $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $datepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $datepicker.hide;\n $datepicker.hide = function(blur) {\n if(!$datepicker.$isShown) return;\n $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $datepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $datepicker;\n\n }\n\n DatepickerFactory.defaults = defaults;\n return DatepickerFactory;\n\n };\n\n })\n\n .directive('bsDatepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) {\n\n var defaults = $datepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope, controller: controller};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'dateType', 'dateFormat', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!datepicker || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i);\n newValue === true ? datepicker.show() : datepicker.hide();\n });\n\n // Initialize datepicker\n var datepicker = $datepicker(element, controller, options);\n options = datepicker.$options;\n // Set expected iOS format\n if(isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd';\n\n var lang = options.lang;\n\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\n\n // Observe attributes for changes\n angular.forEach(['minDate', 'maxDate'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n // console.warn('attr.$observe(%s)=%o', key, newValue);\n datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue);\n // Build only if dirty\n !isNaN(datepicker.$options[key]) && datepicker.$build(false);\n validateAgainstMinMaxDate(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n datepicker.update(controller.$dateValue);\n }, true);\n\n // Normalize undefined/null/empty array,\n // so that we don't treat changing from undefined->null as a change.\n function normalizeDateRanges(ranges) {\n if (!ranges || !ranges.length) return null;\n return ranges;\n }\n\n if (angular.isDefined(attr.disabledDates)) {\n scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) {\n disabledRanges = normalizeDateRanges(disabledRanges);\n previousValue = normalizeDateRanges(previousValue);\n\n if (disabledRanges) {\n datepicker.updateDisabledDates(disabledRanges);\n }\n });\n }\n\n function validateAgainstMinMaxDate(parsedDate) {\n if (!angular.isDate(parsedDate)) return;\n var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate;\n var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if(isValid) controller.$dateValue = parsedDate;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n // Null values should correctly reset the model value & validity\n if(!viewValue) {\n controller.$setValidity('date', true);\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n return null;\n }\n var parsedDate = dateParser.parse(viewValue, controller.$dateValue);\n if(!parsedDate || isNaN(parsedDate.getTime())) {\n controller.$setValidity('date', false);\n // return undefined, causes ngModelController to\n // invalidate model value\n return;\n } else {\n validateAgainstMinMaxDate(parsedDate);\n }\n if(options.dateType === 'string') {\n return formatDate(parsedDate, options.modelDateFormat || options.dateFormat);\n } else if(options.dateType === 'number') {\n return controller.$dateValue.getTime();\n } else if(options.dateType === 'unix') {\n return controller.$dateValue.getTime() / 1000;\n } else if(options.dateType === 'iso') {\n return controller.$dateValue.toISOString();\n } else {\n return new Date(controller.$dateValue);\n }\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var date;\n if(angular.isUndefined(modelValue) || modelValue === null) {\n date = NaN;\n } else if(angular.isDate(modelValue)) {\n date = modelValue;\n } else if(options.dateType === 'string') {\n date = dateParser.parse(modelValue, null, options.modelDateFormat);\n } else if(options.dateType === 'unix') {\n date = new Date(modelValue * 1000);\n } else {\n date = new Date(modelValue);\n }\n // Setup default value?\n // if(isNaN(date.getTime())) {\n // var today = new Date();\n // date = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0);\n // }\n controller.$dateValue = date;\n return getDateFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getDateFormattedString());\n };\n\n function getDateFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if(datepicker) datepicker.destroy();\n options = null;\n datepicker = null;\n });\n\n }\n };\n\n })\n\n .provider('datepickerViews', function() {\n\n var defaults = this.defaults = {\n dayFormat: 'dd',\n daySplit: 7\n };\n\n // Split array into smaller arrays\n function split(arr, size) {\n var arrays = [];\n while(arr.length > 0) {\n arrays.push(arr.splice(0, size));\n }\n return arrays;\n }\n\n // Modulus operator\n function mod(n, m) {\n return ((n % m) + m) % m;\n }\n\n this.$get = function($dateFormatter, $dateParser, $sce) {\n\n return function(picker) {\n\n var scope = picker.$scope;\n var options = picker.$options;\n\n var lang = options.lang;\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\n\n var weekDaysMin = $dateFormatter.weekdaysShort(lang);\n var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek));\n var weekDaysLabelsHtml = $sce.trustAsHtml('' + weekDaysLabels.join('') + '');\n\n var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date());\n var viewDate = {year: startDate.getFullYear(), month: startDate.getMonth(), date: startDate.getDate()};\n var timezoneOffset = startDate.getTimezoneOffset() * 6e4;\n\n var views = [{\n format: options.dayFormat,\n split: 7,\n steps: { month: 1 },\n update: function(date, force) {\n if(!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getDate() !== viewDate.date) {\n viewDate.date = picker.$date.getDate();\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1), firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset();\n var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5), firstDateOffset = firstDate.getTimezoneOffset();\n var today = new Date().toDateString();\n // Handle daylight time switch\n if(firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 60e3);\n var days = [], day;\n for(var i = 0; i < 42; i++) { // < 7 * 6\n day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i));\n days.push({date: day, isToday: day.toDateString() === today, label: formatDate(day, this.format), selected: picker.$date && this.isSelected(day), muted: day.getMonth() !== viewDate.month, disabled: this.isDisabled(day)});\n }\n scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat);\n scope.showLabels = true;\n scope.labels = weekDaysLabelsHtml;\n scope.rows = split(days, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate();\n },\n isDisabled: function(date) {\n var time = date.getTime();\n\n // Disabled because of min/max date.\n if (time < options.minDate || time > options.maxDate) return true;\n\n // Disabled due to being a disabled day of the week\n if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true;\n\n // Disabled because of disabled date range.\n if (options.disabledDateRanges) {\n for (var i = 0; i < options.disabledDateRanges.length; i++) {\n if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) {\n return true;\n }\n }\n }\n\n return false;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualTime = picker.$date.getTime();\n var newDate;\n\n if(evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5);\n else if(evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5);\n else if(evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5);\n else if(evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'month',\n format: options.monthFormat,\n split: 4,\n steps: { year: 1 },\n update: function(date, force) {\n if(!this.built || date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getMonth() !== viewDate.month) {\n angular.extend(viewDate, {month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstMonth = new Date(viewDate.year, 0, 1);\n var months = [], month;\n for (var i = 0; i < 12; i++) {\n month = new Date(viewDate.year, i, 1);\n months.push({date: month, label: formatDate(month, this.format), selected: picker.$isSelected(month), disabled: this.isDisabled(month)});\n }\n scope.title = formatDate(month, options.yearTitleFormat);\n scope.showLabels = false;\n scope.rows = split(months, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualMonth = picker.$date.getMonth();\n var newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setMonth(actualMonth - 1);\n else if(evt.keyCode === 38) newDate.setMonth(actualMonth - 4);\n else if(evt.keyCode === 39) newDate.setMonth(actualMonth + 1);\n else if(evt.keyCode === 40) newDate.setMonth(actualMonth + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'year',\n format: options.yearFormat,\n split: 4,\n steps: { year: 12 },\n update: function(date, force) {\n if(!this.built || force || parseInt(date.getFullYear()/20, 10) !== parseInt(viewDate.year/20, 10)) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstYear = viewDate.year - viewDate.year % (this.split * 3);\n var years = [], year;\n for (var i = 0; i < 12; i++) {\n year = new Date(firstYear + i, 0, 1);\n years.push({date: year, label: formatDate(year, this.format), selected: picker.$isSelected(year), disabled: this.isDisabled(year)});\n }\n scope.title = years[0].label + '-' + years[years.length - 1].label;\n scope.showLabels = false;\n scope.rows = split(years, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear() + 1, 0, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualYear = picker.$date.getFullYear(),\n newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setYear(actualYear - 1);\n else if(evt.keyCode === 38) newDate.setYear(actualYear - 4);\n else if(evt.keyCode === 39) newDate.setYear(actualYear + 1);\n else if(evt.keyCode === 40) newDate.setYear(actualYear + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }];\n\n return {\n views: options.minView ? Array.prototype.slice.call(views, options.minView) : views,\n viewDate: viewDate\n };\n\n };\n\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.dropdown', ['mgcrea.ngStrap.tooltip'])\n\n .provider('$dropdown', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'dropdown',\n placement: 'bottom-left',\n template: 'dropdown/dropdown.tpl.html',\n trigger: 'click',\n container: false,\n keyboard: true,\n html: false,\n delay: 0\n };\n\n this.$get = function($window, $rootScope, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var matchesSelector = Element.prototype.matchesSelector || Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector;\n\n function DropdownFactory(element, config) {\n\n var $dropdown = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n var scope = $dropdown.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n\n $dropdown = $tooltip(element, options);\n var parentEl = element.parent();\n\n // Protected methods\n\n $dropdown.$onKeyDown = function(evt) {\n if (!/(38|40)/.test(evt.keyCode)) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Retrieve focused index\n var items = angular.element($dropdown.$element[0].querySelectorAll('li:not(.divider) a'));\n if(!items.length) return;\n var index;\n angular.forEach(items, function(el, i) {\n if(matchesSelector && matchesSelector.call(el, ':focus')) index = i;\n });\n\n // Navigate with keyboard\n if(evt.keyCode === 38 && index > 0) index--;\n else if(evt.keyCode === 40 && index < items.length - 1) index++;\n else if(angular.isUndefined(index)) index = 0;\n items.eq(index)[0].focus();\n\n };\n\n // Overrides\n\n var show = $dropdown.show;\n $dropdown.show = function() {\n show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n options.keyboard && $dropdown.$element.on('keydown', $dropdown.$onKeyDown);\n bodyEl.on('click', onBodyClick);\n }, 0, false);\n parentEl.hasClass('dropdown') && parentEl.addClass('open');\n };\n\n var hide = $dropdown.hide;\n $dropdown.hide = function() {\n if(!$dropdown.$isShown) return;\n options.keyboard && $dropdown.$element.off('keydown', $dropdown.$onKeyDown);\n bodyEl.off('click', onBodyClick);\n parentEl.hasClass('dropdown') && parentEl.removeClass('open');\n hide();\n };\n\n var destroy = $dropdown.destroy;\n $dropdown.destroy = function() {\n bodyEl.off('click', onBodyClick);\n destroy();\n };\n\n // Private functions\n\n function onBodyClick(evt) {\n if(evt.target === element[0]) return;\n return evt.target !== element[0] && $dropdown.hide();\n }\n\n return $dropdown;\n\n }\n\n return DropdownFactory;\n\n };\n\n })\n\n .directive('bsDropdown', function($window, $sce, $dropdown) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Support scope as an object\n attr.bsDropdown && scope.$watch(attr.bsDropdown, function(newValue, oldValue) {\n scope.content = newValue;\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!dropdown || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(dropdown),?/i);\n newValue === true ? dropdown.show() : dropdown.hide();\n });\n\n // Initialize dropdown\n var dropdown = $dropdown(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (dropdown) dropdown.destroy();\n options = null;\n dropdown = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.dateFormatter', [])\n\n .service('$dateFormatter', function($locale, dateFilter) {\n\n // The unused `lang` arguments are on purpose. The default implementation does not\n // use them and it always uses the locale loaded into the `$locale` service.\n // Custom implementations might use it, thus allowing different directives to\n // have different languages.\n\n this.getDefaultLocale = function() {\n return $locale.id;\n };\n\n // Format is either a data format name, e.g. \"shortTime\" or \"fullDate\", or a date format\n // Return either the corresponding date format or the given date format.\n this.getDatetimeFormat = function(format, lang) {\n return $locale.DATETIME_FORMATS[format] || format;\n };\n\n this.weekdaysShort = function(lang) {\n return $locale.DATETIME_FORMATS.SHORTDAY;\n };\n\n function splitTimeFormat(format) {\n return /(h+)([:\\.])?(m+)[ ]?(a?)/i.exec(format).slice(1);\n }\n\n // h:mm a => h\n this.hoursFormat = function(timeFormat) {\n return splitTimeFormat(timeFormat)[0];\n };\n\n // h:mm a => mm\n this.minutesFormat = function(timeFormat) {\n return splitTimeFormat(timeFormat)[2];\n };\n\n // h:mm a => :\n this.timeSeparator = function(timeFormat) {\n return splitTimeFormat(timeFormat)[1];\n };\n\n // h:mm a => true, H.mm => false\n this.showAM = function(timeFormat) {\n return !!splitTimeFormat(timeFormat)[3];\n };\n\n this.formatDate = function(date, format, lang){\n return dateFilter(date, format);\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.dateParser', [])\n\n.provider('$dateParser', function($localeProvider) {\n\n // define a custom ParseDate object to use instead of native Date\n // to avoid date values wrapping when setting date component values\n function ParseDate() {\n this.year = 1970;\n this.month = 0;\n this.day = 1;\n this.hours = 0;\n this.minutes = 0;\n this.seconds = 0;\n this.milliseconds = 0;\n }\n\n ParseDate.prototype.setMilliseconds = function(value) { this.milliseconds = value; };\n ParseDate.prototype.setSeconds = function(value) { this.seconds = value; };\n ParseDate.prototype.setMinutes = function(value) { this.minutes = value; };\n ParseDate.prototype.setHours = function(value) { this.hours = value; };\n ParseDate.prototype.getHours = function() { return this.hours; };\n ParseDate.prototype.setDate = function(value) { this.day = value; };\n ParseDate.prototype.setMonth = function(value) { this.month = value; };\n ParseDate.prototype.setFullYear = function(value) { this.year = value; };\n ParseDate.prototype.fromDate = function(value) {\n this.year = value.getFullYear();\n this.month = value.getMonth();\n this.day = value.getDate();\n this.hours = value.getHours();\n this.minutes = value.getMinutes();\n this.seconds = value.getSeconds();\n this.milliseconds = value.getMilliseconds();\n return this;\n };\n\n ParseDate.prototype.toDate = function() {\n return new Date(this.year, this.month, this.day, this.hours, this.minutes, this.seconds, this.milliseconds);\n };\n\n var proto = ParseDate.prototype;\n\n function noop() {\n }\n\n function isNumeric(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n\n function indexOfCaseInsensitive(array, value) {\n var len = array.length, str=value.toString().toLowerCase();\n for (var i=0; i 12 when midnight changeover, but then cannot generate\n * midnight datetime, so jump to 1AM, otherwise reset.\n * @param date (Date) the date to check\n * @return (Date) the corrected date\n *\n * __ copied from jquery ui datepicker __\n */\n $dateParser.daylightSavingAdjust = function(date) {\n if (!date) {\n return null;\n }\n date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);\n return date;\n };\n\n // Private functions\n\n function setMapForFormat(format) {\n var keys = Object.keys(setFnMap), i;\n var map = [], sortedMap = [];\n // Map to setFn\n var clonedFormat = format;\n for(i = 0; i < keys.length; i++) {\n if(format.split(keys[i]).length > 1) {\n var index = clonedFormat.search(keys[i]);\n format = format.split(keys[i]).join('');\n if(setFnMap[keys[i]]) {\n map[index] = setFnMap[keys[i]];\n }\n }\n }\n // Sort result map\n angular.forEach(map, function(v) {\n // conditional required since angular.forEach broke around v1.2.21\n // related pr: https://github.com/angular/angular.js/pull/8525\n if(v) sortedMap.push(v);\n });\n return sortedMap;\n }\n\n function escapeReservedSymbols(text) {\n return text.replace(/\\//g, '[\\\\/]').replace('/-/g', '[-]').replace(/\\./g, '[.]').replace(/\\\\s/g, '[\\\\s]');\n }\n\n function regExpForFormat(format) {\n var keys = Object.keys(regExpMap), i;\n\n var re = format;\n // Abstract replaces to avoid collisions\n for(i = 0; i < keys.length; i++) {\n re = re.split(keys[i]).join('${' + i + '}');\n }\n // Replace abstracted values\n for(i = 0; i < keys.length; i++) {\n re = re.split('${' + i + '}').join('(' + regExpMap[keys[i]] + ')');\n }\n format = escapeReservedSymbols(format);\n\n return new RegExp('^' + re + '$', ['i']);\n }\n\n $dateParser.init();\n return $dateParser;\n\n };\n\n return DateParserFactory;\n\n };\n\n});\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.debounce', [])\n\n// @source jashkenas/underscore\n// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L693\n.factory('debounce', function($timeout) {\n return function(func, wait, immediate) {\n var timeout = null;\n return function() {\n var context = this,\n args = arguments,\n callNow = immediate && !timeout;\n if(timeout) {\n $timeout.cancel(timeout);\n }\n timeout = $timeout(function later() {\n timeout = null;\n if(!immediate) {\n func.apply(context, args);\n }\n }, wait, false);\n if(callNow) {\n func.apply(context, args);\n }\n return timeout;\n };\n };\n})\n\n\n// @source jashkenas/underscore\n// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L661\n.factory('throttle', function($timeout) {\n return function(func, wait, options) {\n var timeout = null;\n options || (options = {});\n return function() {\n var context = this,\n args = arguments;\n if(!timeout) {\n if(options.leading !== false) {\n func.apply(context, args);\n }\n timeout = $timeout(function later() {\n timeout = null;\n if(options.trailing !== false) {\n func.apply(context, args);\n }\n }, wait, false);\n }\n };\n };\n});\n\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.dimensions', [])\n\n .factory('dimensions', function($document, $window) {\n\n var jqLite = angular.element;\n var fn = {};\n\n /**\n * Test the element nodeName\n * @param element\n * @param name\n */\n var nodeName = fn.nodeName = function(element, name) {\n return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase();\n };\n\n /**\n * Returns the element computed style\n * @param element\n * @param prop\n * @param extra\n */\n fn.css = function(element, prop, extra) {\n var value;\n if (element.currentStyle) { //IE\n value = element.currentStyle[prop];\n } else if (window.getComputedStyle) {\n value = window.getComputedStyle(element)[prop];\n } else {\n value = element.style[prop];\n }\n return extra === true ? parseFloat(value) || 0 : value;\n };\n\n /**\n * Provides read-only equivalent of jQuery's offset function:\n * @required-by bootstrap-tooltip, bootstrap-affix\n * @url http://api.jquery.com/offset/\n * @param element\n */\n fn.offset = function(element) {\n var boxRect = element.getBoundingClientRect();\n var docElement = element.ownerDocument;\n return {\n width: boxRect.width || element.offsetWidth,\n height: boxRect.height || element.offsetHeight,\n top: boxRect.top + (window.pageYOffset || docElement.documentElement.scrollTop) - (docElement.documentElement.clientTop || 0),\n left: boxRect.left + (window.pageXOffset || docElement.documentElement.scrollLeft) - (docElement.documentElement.clientLeft || 0)\n };\n };\n\n /**\n * Provides read-only equivalent of jQuery's position function\n * @required-by bootstrap-tooltip, bootstrap-affix\n * @url http://api.jquery.com/offset/\n * @param element\n */\n fn.position = function(element) {\n\n var offsetParentRect = {top: 0, left: 0},\n offsetParentElement,\n offset;\n\n // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent\n if (fn.css(element, 'position') === 'fixed') {\n\n // We assume that getBoundingClientRect is available when computed position is fixed\n offset = element.getBoundingClientRect();\n\n } else {\n\n // Get *real* offsetParentElement\n offsetParentElement = offsetParent(element);\n\n // Get correct offsets\n offset = fn.offset(element);\n if (!nodeName(offsetParentElement, 'html')) {\n offsetParentRect = fn.offset(offsetParentElement);\n }\n\n // Add offsetParent borders\n offsetParentRect.top += fn.css(offsetParentElement, 'borderTopWidth', true);\n offsetParentRect.left += fn.css(offsetParentElement, 'borderLeftWidth', true);\n }\n\n // Subtract parent offsets and element margins\n return {\n width: element.offsetWidth,\n height: element.offsetHeight,\n top: offset.top - offsetParentRect.top - fn.css(element, 'marginTop', true),\n left: offset.left - offsetParentRect.left - fn.css(element, 'marginLeft', true)\n };\n\n };\n\n /**\n * Returns the closest, non-statically positioned offsetParent of a given element\n * @required-by fn.position\n * @param element\n */\n var offsetParent = function offsetParentElement(element) {\n var docElement = element.ownerDocument;\n var offsetParent = element.offsetParent || docElement;\n if(nodeName(offsetParent, '#document')) return docElement.documentElement;\n while(offsetParent && !nodeName(offsetParent, 'html') && fn.css(offsetParent, 'position') === 'static') {\n offsetParent = offsetParent.offsetParent;\n }\n return offsetParent || docElement.documentElement;\n };\n\n /**\n * Provides equivalent of jQuery's height function\n * @required-by bootstrap-affix\n * @url http://api.jquery.com/height/\n * @param element\n * @param outer\n */\n fn.height = function(element, outer) {\n var value = element.offsetHeight;\n if(outer) {\n value += fn.css(element, 'marginTop', true) + fn.css(element, 'marginBottom', true);\n } else {\n value -= fn.css(element, 'paddingTop', true) + fn.css(element, 'paddingBottom', true) + fn.css(element, 'borderTopWidth', true) + fn.css(element, 'borderBottomWidth', true);\n }\n return value;\n };\n\n /**\n * Provides equivalent of jQuery's width function\n * @required-by bootstrap-affix\n * @url http://api.jquery.com/width/\n * @param element\n * @param outer\n */\n fn.width = function(element, outer) {\n var value = element.offsetWidth;\n if(outer) {\n value += fn.css(element, 'marginLeft', true) + fn.css(element, 'marginRight', true);\n } else {\n value -= fn.css(element, 'paddingLeft', true) + fn.css(element, 'paddingRight', true) + fn.css(element, 'borderLeftWidth', true) + fn.css(element, 'borderRightWidth', true);\n }\n return value;\n };\n\n return fn;\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.parseOptions', [])\n\n .provider('$parseOptions', function() {\n\n var defaults = this.defaults = {\n regexp: /^\\s*(.*?)(?:\\s+as\\s+(.*?))?(?:\\s+group\\s+by\\s+(.*))?\\s+for\\s+(?:([\\$\\w][\\$\\w]*)|(?:\\(\\s*([\\$\\w][\\$\\w]*)\\s*,\\s*([\\$\\w][\\$\\w]*)\\s*\\)))\\s+in\\s+(.*?)(?:\\s+track\\s+by\\s+(.*?))?$/\n };\n\n this.$get = function($parse, $q) {\n\n function ParseOptionsFactory(attr, config) {\n\n var $parseOptions = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n $parseOptions.$values = [];\n\n // Private vars\n var match, displayFn, valueName, keyName, groupByFn, valueFn, valuesFn;\n\n $parseOptions.init = function() {\n $parseOptions.$match = match = attr.match(options.regexp);\n displayFn = $parse(match[2] || match[1]),\n valueName = match[4] || match[6],\n keyName = match[5],\n groupByFn = $parse(match[3] || ''),\n valueFn = $parse(match[2] ? match[1] : valueName),\n valuesFn = $parse(match[7]);\n };\n\n $parseOptions.valuesFn = function(scope, controller) {\n return $q.when(valuesFn(scope, controller))\n .then(function(values) {\n $parseOptions.$values = values ? parseValues(values, scope) : {};\n return $parseOptions.$values;\n });\n };\n\n $parseOptions.displayValue = function(modelValue) {\n var scope = {};\n scope[valueName] = modelValue;\n return displayFn(scope);\n };\n\n // Private functions\n\n function parseValues(values, scope) {\n return values.map(function(match, index) {\n var locals = {}, label, value;\n locals[valueName] = match;\n label = displayFn(scope, locals);\n value = valueFn(scope, locals);\n return {label: label, value: value, index: index};\n });\n }\n\n $parseOptions.init();\n return $parseOptions;\n\n }\n\n return ParseOptionsFactory;\n\n };\n\n });\n","'use strict';\n\n(angular.version.minor < 3 && angular.version.dot < 14) && angular.module('ng')\n\n.factory('$$rAF', function($window, $timeout) {\n\n var requestAnimationFrame = $window.requestAnimationFrame ||\n $window.webkitRequestAnimationFrame ||\n $window.mozRequestAnimationFrame;\n\n var cancelAnimationFrame = $window.cancelAnimationFrame ||\n $window.webkitCancelAnimationFrame ||\n $window.mozCancelAnimationFrame ||\n $window.webkitCancelRequestAnimationFrame;\n\n var rafSupported = !!requestAnimationFrame;\n var raf = rafSupported ?\n function(fn) {\n var id = requestAnimationFrame(fn);\n return function() {\n cancelAnimationFrame(id);\n };\n } :\n function(fn) {\n var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666\n return function() {\n $timeout.cancel(timer);\n };\n };\n\n raf.supported = rafSupported;\n\n return raf;\n\n});\n\n// .factory('$$animateReflow', function($$rAF, $document) {\n\n// var bodyEl = $document[0].body;\n\n// return function(fn) {\n// //the returned function acts as the cancellation function\n// return $$rAF(function() {\n// //the line below will force the browser to perform a repaint\n// //so that all the animated elements within the animation frame\n// //will be properly updated and drawn on screen. This is\n// //required to perform multi-class CSS based animations with\n// //Firefox. DO NOT REMOVE THIS LINE.\n// var a = bodyEl.offsetWidth + 1;\n// fn();\n// });\n// };\n\n// });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.modal', ['mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$modal', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n backdropAnimation: 'am-fade',\n prefixClass: 'modal',\n prefixEvent: 'modal',\n placement: 'top',\n template: 'modal/modal.tpl.html',\n contentTemplate: false,\n container: false,\n element: null,\n backdrop: true,\n keyboard: true,\n html: false,\n show: true\n };\n\n this.$get = function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $timeout, $sce, dimensions) {\n\n var forEach = angular.forEach;\n var trim = String.prototype.trim;\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n var bodyElement = angular.element($window.document.body);\n var htmlReplaceRegExp = /ng-bind=\"/ig;\n\n function ModalFactory(config) {\n\n var $modal = {};\n\n // Common vars\n var options = $modal.$options = angular.extend({}, defaults, config);\n $modal.$promise = fetchTemplate(options.template);\n var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n if(!options.element && !options.container) {\n options.container = 'body';\n }\n\n // store $id to identify the triggering element in events\n // give priority to options.id, otherwise, try to use\n // element id if defined\n $modal.$id = options.id || options.element && options.element.attr('id') || '';\n\n // Support scope as string options\n forEach(['title', 'content'], function(key) {\n if(options[key]) scope[key] = $sce.trustAsHtml(options[key]);\n });\n\n // Provide scope helpers\n scope.$hide = function() {\n scope.$$postDigest(function() {\n $modal.hide();\n });\n };\n scope.$show = function() {\n scope.$$postDigest(function() {\n $modal.show();\n });\n };\n scope.$toggle = function() {\n scope.$$postDigest(function() {\n $modal.toggle();\n });\n };\n // Publish isShown as a protected var on scope\n $modal.$isShown = scope.$isShown = false;\n\n // Support contentTemplate option\n if(options.contentTemplate) {\n $modal.$promise = $modal.$promise.then(function(template) {\n var templateEl = angular.element(template);\n return fetchTemplate(options.contentTemplate)\n .then(function(contentTemplate) {\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]).removeAttr('ng-bind').html(contentTemplate);\n // Drop the default footer as you probably don't want it if you use a custom contentTemplate\n if(!config.template) contentEl.next().remove();\n return templateEl[0].outerHTML;\n });\n });\n }\n\n // Fetch, compile then initialize modal\n var modalLinker, modalElement;\n var backdropElement = angular.element('
    ');\n $modal.$promise.then(function(template) {\n if(angular.isObject(template)) template = template.data;\n if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html=\"');\n template = trim.apply(template);\n modalLinker = $compile(template);\n $modal.init();\n });\n\n $modal.init = function() {\n\n // Options: show\n if(options.show) {\n scope.$$postDigest(function() {\n $modal.show();\n });\n }\n\n };\n\n $modal.destroy = function() {\n\n // Remove element\n if(modalElement) {\n modalElement.remove();\n modalElement = null;\n }\n if(backdropElement) {\n backdropElement.remove();\n backdropElement = null;\n }\n\n // Destroy scope\n scope.$destroy();\n\n };\n\n $modal.show = function() {\n if($modal.$isShown) return;\n\n if(scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) {\n return;\n }\n var parent, after;\n if(angular.isElement(options.container)) {\n parent = options.container;\n after = options.container[0].lastChild ? angular.element(options.container[0].lastChild) : null;\n } else {\n if (options.container) {\n parent = findElement(options.container);\n after = parent[0].lastChild ? angular.element(parent[0].lastChild) : null;\n } else {\n parent = null;\n after = options.element;\n }\n }\n\n // Fetch a cloned element linked from template\n modalElement = $modal.$element = modalLinker(scope, function(clonedElement, scope) {});\n\n // Set the initial positioning.\n modalElement.css({display: 'block'}).addClass(options.placement);\n\n // Options: animation\n if(options.animation) {\n if(options.backdrop) {\n backdropElement.addClass(options.backdropAnimation);\n }\n modalElement.addClass(options.animation);\n }\n\n if(options.backdrop) {\n $animate.enter(backdropElement, bodyElement, null);\n }\n // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n var promise = $animate.enter(modalElement, parent, after, enterAnimateCallback);\n if(promise && promise.then) promise.then(enterAnimateCallback);\n\n $modal.$isShown = scope.$isShown = true;\n safeDigest(scope);\n // Focus once the enter-animation has started\n // Weird PhantomJS bug hack\n var el = modalElement[0];\n requestAnimationFrame(function() {\n el.focus();\n });\n\n bodyElement.addClass(options.prefixClass + '-open');\n if(options.animation) {\n bodyElement.addClass(options.prefixClass + '-with-' + options.animation);\n }\n\n // Bind events\n if(options.backdrop) {\n modalElement.on('click', hideOnBackdropClick);\n backdropElement.on('click', hideOnBackdropClick);\n backdropElement.on('wheel', preventEventDefault);\n }\n if(options.keyboard) {\n modalElement.on('keyup', $modal.$onKeyUp);\n }\n };\n\n function enterAnimateCallback() {\n scope.$emit(options.prefixEvent + '.show', $modal);\n }\n\n $modal.hide = function() {\n if(!$modal.$isShown) return;\n\n if(scope.$emit(options.prefixEvent + '.hide.before', $modal).defaultPrevented) {\n return;\n }\n var promise = $animate.leave(modalElement, leaveAnimateCallback);\n // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n if(promise && promise.then) promise.then(leaveAnimateCallback);\n\n if(options.backdrop) {\n $animate.leave(backdropElement);\n }\n $modal.$isShown = scope.$isShown = false;\n safeDigest(scope);\n\n // Unbind events\n if(options.backdrop) {\n modalElement.off('click', hideOnBackdropClick);\n backdropElement.off('click', hideOnBackdropClick);\n backdropElement.off('wheel', preventEventDefault);\n }\n if(options.keyboard) {\n modalElement.off('keyup', $modal.$onKeyUp);\n }\n };\n\n function leaveAnimateCallback() {\n scope.$emit(options.prefixEvent + '.hide', $modal);\n bodyElement.removeClass(options.prefixClass + '-open');\n if(options.animation) {\n bodyElement.removeClass(options.prefixClass + '-with-' + options.animation);\n }\n }\n\n $modal.toggle = function() {\n\n $modal.$isShown ? $modal.hide() : $modal.show();\n\n };\n\n $modal.focus = function() {\n modalElement[0].focus();\n };\n\n // Protected methods\n\n $modal.$onKeyUp = function(evt) {\n\n if (evt.which === 27 && $modal.$isShown) {\n $modal.hide();\n evt.stopPropagation();\n }\n\n };\n\n // Private methods\n\n function hideOnBackdropClick(evt) {\n if(evt.target !== evt.currentTarget) return;\n options.backdrop === 'static' ? $modal.focus() : $modal.hide();\n }\n\n function preventEventDefault(evt) {\n evt.preventDefault();\n }\n\n return $modal;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n function findElement(query, element) {\n return angular.element((element || document).querySelectorAll(query));\n }\n\n var fetchPromises = {};\n function fetchTemplate(template) {\n if(fetchPromises[template]) return fetchPromises[template];\n return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template))\n .then(function(res) {\n if(angular.isObject(res)) {\n $templateCache.put(template, res.data);\n return res.data;\n }\n return res;\n }));\n }\n\n return ModalFactory;\n\n };\n\n })\n\n .directive('bsModal', function($window, $sce, $modal) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope, element: element, show: false};\n angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n });\n });\n\n // Support scope as an object\n attr.bsModal && scope.$watch(attr.bsModal, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n }, true);\n\n // Initialize modal\n var modal = $modal(options);\n\n // Trigger\n element.on(attr.trigger || 'click', modal.toggle);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (modal) modal.destroy();\n options = null;\n modal = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.navbar', [])\n\n .provider('$navbar', function() {\n\n var defaults = this.defaults = {\n activeClass: 'active',\n routeAttr: 'data-match-route',\n strict: false\n };\n\n this.$get = function() {\n return {defaults: defaults};\n };\n\n })\n\n .directive('bsNavbar', function($window, $location, $navbar) {\n\n var defaults = $navbar.defaults;\n\n return {\n restrict: 'A',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = angular.copy(defaults);\n angular.forEach(Object.keys(defaults), function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Watch for the $location\n scope.$watch(function() {\n\n return $location.path();\n\n }, function(newValue, oldValue) {\n\n var liElements = element[0].querySelectorAll('li[' + options.routeAttr + ']');\n\n angular.forEach(liElements, function(li) {\n\n var liElement = angular.element(li);\n var pattern = liElement.attr(options.routeAttr).replace('/', '\\\\/');\n if(options.strict) {\n pattern = '^' + pattern + '$';\n }\n var regexp = new RegExp(pattern, ['i']);\n\n if(regexp.test(newValue)) {\n liElement.addClass(options.activeClass);\n } else {\n liElement.removeClass(options.activeClass);\n }\n\n });\n\n });\n\n }\n\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.popover', ['mgcrea.ngStrap.tooltip'])\n\n .provider('$popover', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n customClass: '',\n container: false,\n target: false,\n placement: 'right',\n template: 'popover/popover.tpl.html',\n contentTemplate: false,\n trigger: 'click',\n keyboard: true,\n html: false,\n title: '',\n content: '',\n delay: 0,\n autoClose: false\n };\n\n this.$get = function($tooltip) {\n\n function PopoverFactory(element, config) {\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n var $popover = $tooltip(element, options);\n\n // Support scope as string options [/*title, */content]\n if(options.content) {\n $popover.$scope.content = options.content;\n }\n\n return $popover;\n\n }\n\n return PopoverFactory;\n\n };\n\n })\n\n .directive('bsPopover', function($window, $sce, $popover) {\n\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'customClass', 'autoClose', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n angular.isDefined(oldValue) && requestAnimationFrame(function() {\n popover && popover.$applyPlacement();\n });\n });\n });\n\n // Support scope as an object\n attr.bsPopover && scope.$watch(attr.bsPopover, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n angular.isDefined(oldValue) && requestAnimationFrame(function() {\n popover && popover.$applyPlacement();\n });\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!popover || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(popover),?/i);\n newValue === true ? popover.show() : popover.hide();\n });\n\n // Initialize popover\n var popover = $popover(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (popover) popover.destroy();\n options = null;\n popover = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.select', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions'])\n\n .provider('$select', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'select',\n prefixEvent: '$select',\n placement: 'bottom-left',\n template: 'select/select.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n multiple: false,\n allNoneButtons: false,\n sort: true,\n caretHtml: ' ',\n placeholder: 'Choose among the following...',\n allText: 'All',\n noneText: 'None',\n maxLength: 3,\n maxLengthHtml: 'selected',\n iconCheckmark: 'glyphicon glyphicon-ok'\n };\n\n this.$get = function($window, $document, $rootScope, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n\n function SelectFactory(element, controller, config) {\n\n var $select = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $select = $tooltip(element, options);\n var scope = $select.$scope;\n\n scope.$matches = [];\n scope.$activeIndex = 0;\n scope.$isMultiple = options.multiple;\n scope.$showAllNoneButtons = options.allNoneButtons && options.multiple;\n scope.$iconCheckmark = options.iconCheckmark;\n scope.$allText = options.allText;\n scope.$noneText = options.noneText;\n\n scope.$activate = function(index) {\n scope.$$postDigest(function() {\n $select.activate(index);\n });\n };\n\n scope.$select = function(index, evt) {\n scope.$$postDigest(function() {\n $select.select(index);\n });\n };\n\n scope.$isVisible = function() {\n return $select.$isVisible();\n };\n\n scope.$isActive = function(index) {\n return $select.$isActive(index);\n };\n\n scope.$selectAll = function () {\n for (var i = 0; i < scope.$matches.length; i++) {\n if (!scope.$isActive(i)) {\n scope.$select(i);\n }\n }\n };\n\n scope.$selectNone = function () {\n for (var i = 0; i < scope.$matches.length; i++) {\n if (scope.$isActive(i)) {\n scope.$select(i);\n }\n }\n };\n\n // Public methods\n\n $select.update = function(matches) {\n scope.$matches = matches;\n $select.$updateActiveIndex();\n };\n\n $select.activate = function(index) {\n if(options.multiple) {\n scope.$activeIndex.sort();\n $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index);\n if(options.sort) scope.$activeIndex.sort();\n } else {\n scope.$activeIndex = index;\n }\n return scope.$activeIndex;\n };\n\n $select.select = function(index) {\n var value = scope.$matches[index].value;\n scope.$apply(function() {\n $select.activate(index);\n if(options.multiple) {\n controller.$setViewValue(scope.$activeIndex.map(function(index) {\n return scope.$matches[index].value;\n }));\n } else {\n controller.$setViewValue(value);\n // Hide if single select\n $select.hide();\n }\n });\n // Emit event\n scope.$emit(options.prefixEvent + '.select', value, index, $select);\n };\n\n // Protected methods\n\n $select.$updateActiveIndex = function() {\n if(controller.$modelValue && scope.$matches.length) {\n if(options.multiple && angular.isArray(controller.$modelValue)) {\n scope.$activeIndex = controller.$modelValue.map(function(value) {\n return $select.$getIndex(value);\n });\n } else {\n scope.$activeIndex = $select.$getIndex(controller.$modelValue);\n }\n } else if(scope.$activeIndex >= scope.$matches.length) {\n scope.$activeIndex = options.multiple ? [] : 0;\n }\n };\n\n $select.$isVisible = function() {\n if(!options.minLength || !controller) {\n return scope.$matches.length;\n }\n // minLength support\n return scope.$matches.length && controller.$viewValue.length >= options.minLength;\n };\n\n $select.$isActive = function(index) {\n if(options.multiple) {\n return scope.$activeIndex.indexOf(index) !== -1;\n } else {\n return scope.$activeIndex === index;\n }\n };\n\n $select.$getIndex = function(value) {\n var l = scope.$matches.length, i = l;\n if(!l) return;\n for(i = l; i--;) {\n if(scope.$matches[i].value === value) break;\n }\n if(i < 0) return;\n return i;\n };\n\n $select.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n targetEl.triggerHandler('click');\n }\n };\n\n $select.$onKeyDown = function(evt) {\n if (!/(9|13|38|40)/.test(evt.keyCode)) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Select with enter\n if(!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) {\n return $select.select(scope.$activeIndex);\n }\n\n // Navigate with keyboard\n if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--;\n else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++;\n else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;\n scope.$digest();\n };\n\n // Overrides\n\n var _show = $select.show;\n $select.show = function() {\n _show();\n if(options.multiple) {\n $select.$element.addClass('select-multiple');\n }\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $select.$element.on(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $select.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $select.hide;\n $select.hide = function() {\n $select.$element.off(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $select.$onKeyDown);\n }\n _hide(true);\n };\n\n return $select;\n\n }\n\n SelectFactory.defaults = defaults;\n return SelectFactory;\n\n };\n\n })\n\n .directive('bsSelect', function($window, $parse, $q, $select, $parseOptions) {\n\n var defaults = $select.defaults;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope, placeholder: defaults.placeholder};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'placeholder', 'multiple', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText', 'iconCheckmark', 'autoClose', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Add support for select markup\n if(element[0].nodeName.toLowerCase() === 'select') {\n var inputEl = element;\n inputEl.css('display', 'none');\n element = angular.element('');\n inputEl.after(element);\n }\n\n // Build proper ngOptions\n var parsedOptions = $parseOptions(attr.ngOptions);\n\n // Initialize select\n var select = $select(element, controller, options);\n\n // Watch ngOptions values before filtering for changes\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').trim();\n scope.$watch(watchedOptions, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);\n parsedOptions.valuesFn(scope, controller)\n .then(function(values) {\n select.update(values);\n controller.$render();\n });\n }, true);\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue);\n select.$updateActiveIndex();\n controller.$render();\n }, true);\n\n // Model rendering in view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n var selected, index;\n if(options.multiple && angular.isArray(controller.$modelValue)) {\n selected = controller.$modelValue.map(function(value) {\n index = select.$getIndex(value);\n return angular.isDefined(index) ? select.$scope.$matches[index].label : false;\n }).filter(angular.isDefined);\n if(selected.length > (options.maxLength || defaults.maxLength)) {\n selected = selected.length + ' ' + (options.maxLengthHtml || defaults.maxLengthHtml);\n } else {\n selected = selected.join(', ');\n }\n } else {\n index = select.$getIndex(controller.$modelValue);\n selected = angular.isDefined(index) ? select.$scope.$matches[index].label : false;\n }\n element.html((selected ? selected : options.placeholder) + defaults.caretHtml);\n };\n\n if(options.multiple){\n controller.$isEmpty = function(value){\n return !value || value.length === 0;\n };\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (select) select.destroy();\n options = null;\n select = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.tab', [])\n\n .provider('$tab', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n template: 'tab/tab.tpl.html',\n navClass: 'nav-tabs',\n activeClass: 'active'\n };\n\n var controller = this.controller = function($scope, $element, $attrs) {\n var self = this;\n\n // Attributes options\n self.$options = angular.copy(defaults);\n angular.forEach(['animation', 'navClass', 'activeClass'], function(key) {\n if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];\n });\n\n // Publish options on scope\n $scope.$navClass = self.$options.navClass;\n $scope.$activeClass = self.$options.activeClass;\n\n self.$panes = $scope.$panes = [];\n\n // DEPRECATED: $viewChangeListeners, please use $activePaneChangeListeners\n // Because we deprecated ngModel usage, we rename viewChangeListeners to \n // activePaneChangeListeners to make more sense.\n self.$activePaneChangeListeners = self.$viewChangeListeners = [];\n\n self.$push = function(pane) {\n self.$panes.push(pane);\n };\n\n self.$remove = function(pane) {\n var index = self.$panes.indexOf(pane);\n var activeIndex = self.$panes.$active;\n\n // remove pane from $panes array\n self.$panes.splice(index, 1);\n\n if (index < activeIndex) {\n // we removed a pane before the active pane, so we need to \n // decrement the active pane index\n activeIndex--;\n }\n else if (index === activeIndex && activeIndex === self.$panes.length) {\n // we remove the active pane and it was the one at the end,\n // so select the previous one\n activeIndex--;\n }\n self.$setActive(activeIndex);\n };\n\n self.$panes.$active = 0;\n self.$setActive = $scope.$setActive = function(value) {\n self.$panes.$active = value;\n self.$activePaneChangeListeners.forEach(function(fn) {\n fn();\n });\n };\n\n };\n\n this.$get = function() {\n var $tab = {};\n $tab.defaults = defaults;\n $tab.controller = controller;\n return $tab;\n };\n\n })\n\n .directive('bsTabs', function($window, $animate, $tab, $parse) {\n\n var defaults = $tab.defaults;\n\n return {\n require: ['?ngModel', 'bsTabs'],\n transclude: true,\n scope: true,\n controller: ['$scope', '$element', '$attrs', $tab.controller],\n templateUrl: function(element, attr) {\n return attr.template || defaults.template;\n },\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsTabsCtrl = controllers[1];\n\n // DEPRECATED: ngModel, please use bsActivePane\n // 'ngModel' is deprecated bacause if interferes with form validation\n // and status, so avoid using it here.\n if(ngModelCtrl) {\n console.warn('Usage of ngModel is deprecated, please use bsActivePane instead!');\n\n // Update the modelValue following\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n ngModelCtrl.$setViewValue(bsTabsCtrl.$panes.$active);\n });\n\n // modelValue -> $formatters -> viewValue\n ngModelCtrl.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n bsTabsCtrl.$setActive(modelValue * 1);\n return modelValue;\n });\n\n }\n\n if (attrs.bsActivePane) {\n // adapted from angularjs ngModelController bindings\n // https://github.com/angular/angular.js/blob/v1.3.1/src%2Fng%2Fdirective%2Finput.js#L1730\n var parsedBsActivePane = $parse(attrs.bsActivePane);\n\n // Update bsActivePane value with change\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n parsedBsActivePane.assign(scope, bsTabsCtrl.$panes.$active);\n });\n\n // watch bsActivePane for value changes\n scope.$watch(attrs.bsActivePane, function(newValue, oldValue) {\n bsTabsCtrl.$setActive(newValue * 1);\n }, true);\n }\n }\n };\n\n })\n\n .directive('bsPane', function($window, $animate, $sce) {\n\n return {\n require: ['^?ngModel', '^bsTabs'],\n scope: true,\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsTabsCtrl = controllers[1];\n\n // Add base class\n element.addClass('tab-pane');\n\n // Observe title attribute for change\n attrs.$observe('title', function(newValue, oldValue) {\n scope.title = $sce.trustAsHtml(newValue);\n });\n\n // Add animation class\n if(bsTabsCtrl.$options.animation) {\n element.addClass(bsTabsCtrl.$options.animation);\n }\n\n // Push pane to parent bsTabs controller\n bsTabsCtrl.$push(scope);\n\n // remove pane from tab controller when pane is destroyed\n scope.$on('$destroy', function() {\n bsTabsCtrl.$remove(scope);\n });\n\n function render() {\n var index = bsTabsCtrl.$panes.indexOf(scope);\n var active = bsTabsCtrl.$panes.$active;\n $animate[index === active ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass);\n }\n\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n render();\n });\n render();\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.scrollspy', ['mgcrea.ngStrap.helpers.debounce', 'mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$scrollspy', function() {\n\n // Pool of registered spies\n var spies = this.$$spies = {};\n\n var defaults = this.defaults = {\n debounce: 150,\n throttle: 100,\n offset: 100\n };\n\n this.$get = function($window, $document, $rootScope, dimensions, debounce, throttle) {\n\n var windowEl = angular.element($window);\n var docEl = angular.element($document.prop('documentElement'));\n var bodyEl = angular.element($window.document.body);\n\n // Helper functions\n\n function nodeName(element, name) {\n return element[0].nodeName && element[0].nodeName.toLowerCase() === name.toLowerCase();\n }\n\n function ScrollSpyFactory(config) {\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n if(!options.element) options.element = bodyEl;\n var isWindowSpy = nodeName(options.element, 'body');\n var scrollEl = isWindowSpy ? windowEl : options.element;\n var scrollId = isWindowSpy ? 'window' : options.id;\n\n // Use existing spy\n if(spies[scrollId]) {\n spies[scrollId].$$count++;\n return spies[scrollId];\n }\n\n var $scrollspy = {};\n\n // Private vars\n var unbindViewContentLoaded, unbindIncludeContentLoaded;\n var trackedElements = $scrollspy.$trackedElements = [];\n var sortedElements = [];\n var activeTarget;\n var debouncedCheckPosition;\n var throttledCheckPosition;\n var debouncedCheckOffsets;\n var viewportHeight;\n var scrollTop;\n\n $scrollspy.init = function() {\n\n // Setup internal ref counter\n this.$$count = 1;\n\n // Bind events\n debouncedCheckPosition = debounce(this.checkPosition, options.debounce);\n throttledCheckPosition = throttle(this.checkPosition, options.throttle);\n scrollEl.on('click', this.checkPositionWithEventLoop);\n windowEl.on('resize', debouncedCheckPosition);\n scrollEl.on('scroll', throttledCheckPosition);\n\n debouncedCheckOffsets = debounce(this.checkOffsets, options.debounce);\n unbindViewContentLoaded = $rootScope.$on('$viewContentLoaded', debouncedCheckOffsets);\n unbindIncludeContentLoaded = $rootScope.$on('$includeContentLoaded', debouncedCheckOffsets);\n debouncedCheckOffsets();\n\n // Register spy for reuse\n if(scrollId) {\n spies[scrollId] = $scrollspy;\n }\n\n };\n\n $scrollspy.destroy = function() {\n\n // Check internal ref counter\n this.$$count--;\n if(this.$$count > 0) {\n return;\n }\n\n // Unbind events\n scrollEl.off('click', this.checkPositionWithEventLoop);\n windowEl.off('resize', debouncedCheckPosition);\n scrollEl.off('scroll', throttledCheckPosition);\n unbindViewContentLoaded();\n unbindIncludeContentLoaded();\n if (scrollId) {\n delete spies[scrollId];\n }\n };\n\n $scrollspy.checkPosition = function() {\n\n // Not ready yet\n if(!sortedElements.length) return;\n\n // Calculate the scroll position\n scrollTop = (isWindowSpy ? $window.pageYOffset : scrollEl.prop('scrollTop')) || 0;\n\n // Calculate the viewport height for use by the components\n viewportHeight = Math.max($window.innerHeight, docEl.prop('clientHeight'));\n\n // Activate first element if scroll is smaller\n if(scrollTop < sortedElements[0].offsetTop && activeTarget !== sortedElements[0].target) {\n return $scrollspy.$activateElement(sortedElements[0]);\n }\n\n // Activate proper element\n for (var i = sortedElements.length; i--;) {\n if(angular.isUndefined(sortedElements[i].offsetTop) || sortedElements[i].offsetTop === null) continue;\n if(activeTarget === sortedElements[i].target) continue;\n if(scrollTop < sortedElements[i].offsetTop) continue;\n if(sortedElements[i + 1] && scrollTop > sortedElements[i + 1].offsetTop) continue;\n return $scrollspy.$activateElement(sortedElements[i]);\n }\n\n };\n\n $scrollspy.checkPositionWithEventLoop = function() {\n // IE 9 throws an error if we use 'this' instead of '$scrollspy'\n // in this setTimeout call\n setTimeout($scrollspy.checkPosition, 1);\n };\n\n // Protected methods\n\n $scrollspy.$activateElement = function(element) {\n if(activeTarget) {\n var activeElement = $scrollspy.$getTrackedElement(activeTarget);\n if(activeElement) {\n activeElement.source.removeClass('active');\n if(nodeName(activeElement.source, 'li') && nodeName(activeElement.source.parent().parent(), 'li')) {\n activeElement.source.parent().parent().removeClass('active');\n }\n }\n }\n activeTarget = element.target;\n element.source.addClass('active');\n if(nodeName(element.source, 'li') && nodeName(element.source.parent().parent(), 'li')) {\n element.source.parent().parent().addClass('active');\n }\n };\n\n $scrollspy.$getTrackedElement = function(target) {\n return trackedElements.filter(function(obj) {\n return obj.target === target;\n })[0];\n };\n\n // Track offsets behavior\n\n $scrollspy.checkOffsets = function() {\n\n angular.forEach(trackedElements, function(trackedElement) {\n var targetElement = document.querySelector(trackedElement.target);\n trackedElement.offsetTop = targetElement ? dimensions.offset(targetElement).top : null;\n if(options.offset && trackedElement.offsetTop !== null) trackedElement.offsetTop -= options.offset * 1;\n });\n\n sortedElements = trackedElements\n .filter(function(el) {\n return el.offsetTop !== null;\n })\n .sort(function(a, b) {\n return a.offsetTop - b.offsetTop;\n });\n\n debouncedCheckPosition();\n\n };\n\n $scrollspy.trackElement = function(target, source) {\n trackedElements.push({target: target, source: source});\n };\n\n $scrollspy.untrackElement = function(target, source) {\n var toDelete;\n for (var i = trackedElements.length; i--;) {\n if(trackedElements[i].target === target && trackedElements[i].source === source) {\n toDelete = i;\n break;\n }\n }\n trackedElements = trackedElements.splice(toDelete, 1);\n };\n\n $scrollspy.activate = function(i) {\n trackedElements[i].addClass('active');\n };\n\n // Initialize plugin\n\n $scrollspy.init();\n return $scrollspy;\n\n }\n\n return ScrollSpyFactory;\n\n };\n\n })\n\n .directive('bsScrollspy', function($rootScope, debounce, dimensions, $scrollspy) {\n\n return {\n restrict: 'EAC',\n link: function postLink(scope, element, attr) {\n\n var options = {scope: scope};\n angular.forEach(['offset', 'target'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n var scrollspy = $scrollspy(options);\n scrollspy.trackElement(options.target, element);\n\n scope.$on('$destroy', function() {\n if (scrollspy) {\n scrollspy.untrackElement(options.target, element);\n scrollspy.destroy();\n }\n options = null;\n scrollspy = null;\n });\n\n }\n };\n\n })\n\n\n .directive('bsScrollspyList', function($rootScope, debounce, dimensions, $scrollspy) {\n\n return {\n restrict: 'A',\n compile: function postLink(element, attr) {\n var children = element[0].querySelectorAll('li > a[href]');\n angular.forEach(children, function(child) {\n var childEl = angular.element(child);\n childEl.parent().attr('bs-scrollspy', '').attr('data-target', childEl.attr('href'));\n });\n }\n\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.timepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$timepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'timepicker',\n placement: 'bottom-left',\n template: 'timepicker/timepicker.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n // lang: $locale.id,\n useNative: true,\n timeType: 'date',\n timeFormat: 'shortTime',\n modelTimeFormat: null,\n autoclose: false,\n minTime: -Infinity,\n maxTime: +Infinity,\n length: 5,\n hourStep: 1,\n minuteStep: 5,\n iconUp: 'glyphicon glyphicon-chevron-up',\n iconDown: 'glyphicon glyphicon-chevron-down',\n arrowBehavior: 'pager'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function timepickerFactory(element, controller, config) {\n\n var $timepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $timepicker.$options;\n var scope = $timepicker.$scope;\n\n var lang = options.lang;\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n // View vars\n\n var selectedIndex = 0;\n var startDate = controller.$dateValue || new Date();\n var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()};\n\n var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);\n\n var hoursFormat = $dateFormatter.hoursFormat(format),\n timeSeparator = $dateFormatter.timeSeparator(format),\n minutesFormat = $dateFormatter.minutesFormat(format),\n showAM = $dateFormatter.showAM(format);\n\n scope.$iconUp = options.iconUp;\n scope.$iconDown = options.iconDown;\n\n // Scope methods\n\n scope.$select = function(date, index) {\n $timepicker.select(date, index);\n };\n scope.$moveIndex = function(value, index) {\n $timepicker.$moveIndex(value, index);\n };\n scope.$switchMeridian = function(date) {\n $timepicker.switchMeridian(date);\n };\n\n // Public methods\n\n $timepicker.update = function(date) {\n // console.warn('$timepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $timepicker.$date = date;\n angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()});\n $timepicker.$build();\n } else if(!$timepicker.$isBuilt) {\n $timepicker.$build();\n }\n };\n\n $timepicker.select = function(date, index, keep) {\n // console.warn('$timepicker.select', date, scope.$mode);\n if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);\n if(!angular.isDate(date)) date = new Date(date);\n if(index === 0) controller.$dateValue.setHours(date.getHours());\n else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes());\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $timepicker.hide(true); });\n }\n };\n\n $timepicker.switchMeridian = function(date) {\n if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {\n return;\n }\n var hours = (date || controller.$dateValue).getHours();\n controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n };\n\n // Protected methods\n\n $timepicker.$build = function() {\n // console.warn('$timepicker.$build() viewDate=%o', viewDate);\n var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);\n var hours = [], hour;\n for(i = 0; i < options.length; i++) {\n hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);\n hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)});\n }\n var minutes = [], minute;\n for(i = 0; i < options.length; i++) {\n minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);\n minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)});\n }\n\n var rows = [];\n for(i = 0; i < options.length; i++) {\n rows.push([hours[i], minutes[i]]);\n }\n scope.rows = rows;\n scope.showAM = showAM;\n scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12;\n scope.timeSeparator = timeSeparator;\n $timepicker.$isBuilt = true;\n };\n\n $timepicker.$isSelected = function(date, index) {\n if(!$timepicker.$date) return false;\n else if(index === 0) {\n return date.getHours() === $timepicker.$date.getHours();\n } else if(index === 1) {\n return date.getMinutes() === $timepicker.$date.getMinutes();\n }\n };\n\n $timepicker.$isDisabled = function(date, index) {\n var selectedTime;\n if(index === 0) {\n selectedTime = date.getTime() + viewDate.minute * 6e4;\n } else if(index === 1) {\n selectedTime = date.getTime() + viewDate.hour * 36e5;\n }\n return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;\n };\n\n scope.$arrowAction = function (value, index) {\n if (options.arrowBehavior === 'picker') {\n $timepicker.$setTimeByStep(value,index);\n } else {\n $timepicker.$moveIndex(value,index);\n }\n };\n\n $timepicker.$setTimeByStep = function(value, index) {\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n if (index === 0) {\n newDate.setHours(hours - (parseInt(options.hourStep, 10) * value));\n }\n else {\n newDate.setMinutes(minutes - (parseInt(options.minuteStep, 10) * value));\n }\n $timepicker.select(newDate, index, true);\n };\n\n $timepicker.$moveIndex = function(value, index) {\n var targetDate;\n if(index === 0) {\n targetDate = new Date(1970, 0, 1, viewDate.hour + (value * options.length), viewDate.minute);\n angular.extend(viewDate, {hour: targetDate.getHours()});\n } else if(index === 1) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep));\n angular.extend(viewDate, {minute: targetDate.getMinutes()});\n }\n $timepicker.$build();\n };\n\n $timepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $timepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Close on enter\n if(evt.keyCode === 13) return $timepicker.hide(true);\n\n // Navigate with keyboard\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n var lateralMove = /(37|39)/.test(evt.keyCode);\n var count = 2 + showAM * 1;\n\n // Navigate indexes (left, right)\n if (lateralMove) {\n if(evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1;\n else if(evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0;\n }\n\n // Update values (up, down)\n var selectRange = [0, hoursLength];\n if(selectedIndex === 0) {\n if(evt.keyCode === 38) newDate.setHours(hours - parseInt(options.hourStep, 10));\n else if(evt.keyCode === 40) newDate.setHours(hours + parseInt(options.hourStep, 10));\n // re-calculate hours length because we have changed hours value\n hoursLength = formatDate(newDate, hoursFormat).length;\n selectRange = [0, hoursLength];\n } else if(selectedIndex === 1) {\n if(evt.keyCode === 38) newDate.setMinutes(minutes - parseInt(options.minuteStep, 10));\n else if(evt.keyCode === 40) newDate.setMinutes(minutes + parseInt(options.minuteStep, 10));\n // re-calculate minutes length because we have changes minutes value\n minutesLength = formatDate(newDate, minutesFormat).length;\n selectRange = [hoursLength + 1, hoursLength + 1 + minutesLength];\n } else if(selectedIndex === 2) {\n if(!lateralMove) $timepicker.switchMeridian();\n selectRange = [hoursLength + 1 + minutesLength + 1, hoursLength + 1 + minutesLength + 3];\n }\n $timepicker.select(newDate, selectedIndex, true);\n createSelection(selectRange[0], selectRange[1]);\n parentScope.$digest();\n };\n\n // Private\n\n function createSelection(start, end) {\n if(element[0].createTextRange) {\n var selRange = element[0].createTextRange();\n selRange.collapse(true);\n selRange.moveStart('character', start);\n selRange.moveEnd('character', end);\n selRange.select();\n } else if(element[0].setSelectionRange) {\n element[0].setSelectionRange(start, end);\n } else if(angular.isUndefined(element[0].selectionStart)) {\n element[0].selectionStart = start;\n element[0].selectionEnd = end;\n }\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $timepicker.init;\n $timepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'time');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $timepicker.destroy;\n $timepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $timepicker.show;\n $timepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $timepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $timepicker.hide;\n $timepicker.hide = function(blur) {\n if(!$timepicker.$isShown) return;\n $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $timepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $timepicker;\n\n }\n\n timepickerFactory.defaults = defaults;\n return timepickerFactory;\n\n };\n\n })\n\n\n .directive('bsTimepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {\n\n var defaults = $timepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope, controller: controller};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'timeType', 'timeFormat', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!timepicker || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i);\n newValue === true ? timepicker.show() : timepicker.hide();\n });\n\n // Initialize timepicker\n if(isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm';\n var timepicker = $timepicker(element, controller, options);\n options = timepicker.$options;\n\n var lang = options.lang;\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n // Initialize parser\n var dateParser = $dateParser({format: options.timeFormat, lang: lang});\n\n // Observe attributes for changes\n angular.forEach(['minTime', 'maxTime'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);\n !isNaN(timepicker.$options[key]) && timepicker.$build();\n validateAgainstMinMaxTime(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue);\n timepicker.update(controller.$dateValue);\n }, true);\n\n function validateAgainstMinMaxTime(parsedTime) {\n if (!angular.isDate(parsedTime)) return;\n var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;\n var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if(!isValid) {\n return;\n }\n controller.$dateValue = parsedTime;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n // Null values should correctly reset the model value & validity\n if(!viewValue) {\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n controller.$setValidity('date', true);\n return null;\n }\n var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);\n if(!parsedTime || isNaN(parsedTime.getTime())) {\n controller.$setValidity('date', false);\n // return undefined, causes ngModelController to\n // invalidate model value\n return;\n } else {\n validateAgainstMinMaxTime(parsedTime);\n }\n if(options.timeType === 'string') {\n return formatDate(parsedTime, options.modelTimeFormat || options.timeFormat);\n } else if(options.timeType === 'number') {\n return controller.$dateValue.getTime();\n } else if(options.timeType === 'unix') {\n return controller.$dateValue.getTime() / 1000;\n } else if(options.timeType === 'iso') {\n return controller.$dateValue.toISOString();\n } else {\n return new Date(controller.$dateValue);\n }\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var date;\n if(angular.isUndefined(modelValue) || modelValue === null) {\n date = NaN;\n } else if(angular.isDate(modelValue)) {\n date = modelValue;\n } else if(options.timeType === 'string') {\n date = dateParser.parse(modelValue, null, options.modelTimeFormat);\n } else if(options.timeType === 'unix') {\n date = new Date(modelValue * 1000);\n } else {\n date = new Date(modelValue);\n }\n // Setup default value?\n // if(isNaN(date.getTime())) date = new Date(new Date().setMinutes(0) + 36e5);\n controller.$dateValue = date;\n return getTimeFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getTimeFormattedString());\n };\n\n function getTimeFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (timepicker) timepicker.destroy();\n options = null;\n timepicker = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$tooltip', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n customClass: '',\n prefixClass: 'tooltip',\n prefixEvent: 'tooltip',\n container: false,\n target: false,\n placement: 'top',\n template: 'tooltip/tooltip.tpl.html',\n contentTemplate: false,\n trigger: 'hover focus',\n keyboard: false,\n html: false,\n show: false,\n title: '',\n type: '',\n delay: 0,\n autoClose: false,\n bsEnabled: true\n };\n\n this.$get = function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) {\n\n var trim = String.prototype.trim;\n var isTouch = 'createTouch' in $window.document;\n var htmlReplaceRegExp = /ng-bind=\"/ig;\n var $body = angular.element($window.document);\n\n function TooltipFactory(element, config) {\n\n var $tooltip = {};\n\n // Common vars\n var nodeName = element[0].nodeName.toLowerCase();\n var options = $tooltip.$options = angular.extend({}, defaults, config);\n $tooltip.$promise = fetchTemplate(options.template);\n var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n if(options.delay && angular.isString(options.delay)) {\n var split = options.delay.split(',').map(parseFloat);\n options.delay = split.length > 1 ? {show: split[0], hide: split[1]} : split[0];\n }\n\n // store $id to identify the triggering element in events\n // give priority to options.id, otherwise, try to use\n // element id if defined\n $tooltip.$id = options.id || element.attr('id') || '';\n\n // Support scope as string options\n if(options.title) {\n scope.title = $sce.trustAsHtml(options.title);\n }\n\n // Provide scope helpers\n scope.$setEnabled = function(isEnabled) {\n scope.$$postDigest(function() {\n $tooltip.setEnabled(isEnabled);\n });\n };\n scope.$hide = function() {\n scope.$$postDigest(function() {\n $tooltip.hide();\n });\n };\n scope.$show = function() {\n scope.$$postDigest(function() {\n $tooltip.show();\n });\n };\n scope.$toggle = function() {\n scope.$$postDigest(function() {\n $tooltip.toggle();\n });\n };\n // Publish isShown as a protected var on scope\n $tooltip.$isShown = scope.$isShown = false;\n\n // Private vars\n var timeout, hoverState;\n\n // Support contentTemplate option\n if(options.contentTemplate) {\n $tooltip.$promise = $tooltip.$promise.then(function(template) {\n var templateEl = angular.element(template);\n return fetchTemplate(options.contentTemplate)\n .then(function(contentTemplate) {\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]);\n if(!contentEl.length) contentEl = findElement('[ng-bind=\"title\"]', templateEl[0]);\n contentEl.removeAttr('ng-bind').html(contentTemplate);\n return templateEl[0].outerHTML;\n });\n });\n }\n\n // Fetch, compile then initialize tooltip\n var tipLinker, tipElement, tipTemplate, tipContainer, tipScope;\n $tooltip.$promise.then(function(template) {\n if(angular.isObject(template)) template = template.data;\n if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html=\"');\n template = trim.apply(template);\n tipTemplate = template;\n tipLinker = $compile(template);\n $tooltip.init();\n });\n\n $tooltip.init = function() {\n\n // Options: delay\n if (options.delay && angular.isNumber(options.delay)) {\n options.delay = {\n show: options.delay,\n hide: options.delay\n };\n }\n\n // Replace trigger on touch devices ?\n // if(isTouch && options.trigger === defaults.trigger) {\n // options.trigger.replace(/hover/g, 'click');\n // }\n\n // Options : container\n if(options.container === 'self') {\n tipContainer = element;\n } else if(angular.isElement(options.container)) {\n tipContainer = options.container;\n } else if(options.container) {\n tipContainer = findElement(options.container);\n }\n\n // Options: trigger\n bindTriggerEvents();\n\n // Options: target\n if(options.target) {\n options.target = angular.isElement(options.target) ? options.target : findElement(options.target);\n }\n\n // Options: show\n if(options.show) {\n scope.$$postDigest(function() {\n options.trigger === 'focus' ? element[0].focus() : $tooltip.show();\n });\n }\n\n };\n\n $tooltip.destroy = function() {\n\n // Unbind events\n unbindTriggerEvents();\n\n // Remove element\n destroyTipElement();\n\n // Destroy scope\n scope.$destroy();\n\n };\n\n $tooltip.enter = function() {\n\n clearTimeout(timeout);\n hoverState = 'in';\n if (!options.delay || !options.delay.show) {\n return $tooltip.show();\n }\n\n timeout = setTimeout(function() {\n if (hoverState ==='in') $tooltip.show();\n }, options.delay.show);\n\n };\n\n $tooltip.show = function() {\n if (!options.bsEnabled || $tooltip.$isShown) return;\n\n scope.$emit(options.prefixEvent + '.show.before', $tooltip);\n var parent, after;\n if (options.container) {\n parent = tipContainer;\n if (tipContainer[0].lastChild) {\n after = angular.element(tipContainer[0].lastChild);\n } else {\n after = null;\n }\n } else {\n parent = null;\n after = element;\n }\n\n\n // Hide any existing tipElement\n if(tipElement) destroyTipElement();\n // Fetch a cloned element linked from template\n tipScope = $tooltip.$scope.$new();\n tipElement = $tooltip.$element = tipLinker(tipScope, function(clonedElement, scope) {});\n\n // Set the initial positioning. Make the tooltip invisible\n // so IE doesn't try to focus on it off screen.\n tipElement.css({top: '-9999px', left: '-9999px', display: 'block', visibility: 'hidden'});\n\n // Options: animation\n if(options.animation) tipElement.addClass(options.animation);\n // Options: type\n if(options.type) tipElement.addClass(options.prefixClass + '-' + options.type);\n // Options: custom classes\n if(options.customClass) tipElement.addClass(options.customClass);\n\n // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n var promise = $animate.enter(tipElement, parent, after, enterAnimateCallback);\n if(promise && promise.then) promise.then(enterAnimateCallback);\n\n $tooltip.$isShown = scope.$isShown = true;\n safeDigest(scope);\n $$rAF(function () {\n $tooltip.$applyPlacement();\n\n // Once placed, make the tooltip visible\n if(tipElement) tipElement.css({visibility: 'visible'});\n }); // var a = bodyEl.offsetWidth + 1; ?\n\n // Bind events\n if(options.keyboard) {\n if(options.trigger !== 'focus') {\n $tooltip.focus();\n }\n bindKeyboardEvents();\n }\n\n if(options.autoClose) {\n bindAutoCloseEvents();\n }\n\n };\n\n function enterAnimateCallback() {\n scope.$emit(options.prefixEvent + '.show', $tooltip);\n }\n\n $tooltip.leave = function() {\n\n clearTimeout(timeout);\n hoverState = 'out';\n if (!options.delay || !options.delay.hide) {\n return $tooltip.hide();\n }\n timeout = setTimeout(function () {\n if (hoverState === 'out') {\n $tooltip.hide();\n }\n }, options.delay.hide);\n\n };\n\n var _blur;\n var _tipToHide;\n $tooltip.hide = function(blur) {\n\n if(!$tooltip.$isShown) return;\n scope.$emit(options.prefixEvent + '.hide.before', $tooltip);\n\n // store blur value for leaveAnimateCallback to use\n _blur = blur;\n\n // store current tipElement reference to use\n // in leaveAnimateCallback\n _tipToHide = tipElement;\n\n // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n var promise = $animate.leave(tipElement, leaveAnimateCallback);\n if(promise && promise.then) promise.then(leaveAnimateCallback);\n\n $tooltip.$isShown = scope.$isShown = false;\n safeDigest(scope);\n\n // Unbind events\n if(options.keyboard && tipElement !== null) {\n unbindKeyboardEvents();\n }\n\n if(options.autoClose && tipElement !== null) {\n unbindAutoCloseEvents();\n }\n };\n\n function leaveAnimateCallback() {\n scope.$emit(options.prefixEvent + '.hide', $tooltip);\n\n // check if current tipElement still references\n // the same element when hide was called\n if (tipElement === _tipToHide) {\n // Allow to blur the input when hidden, like when pressing enter key\n if(_blur && options.trigger === 'focus') {\n return element[0].blur();\n }\n\n // clean up child scopes\n destroyTipElement();\n }\n }\n\n $tooltip.toggle = function() {\n $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter();\n };\n\n $tooltip.focus = function() {\n tipElement[0].focus();\n };\n\n $tooltip.setEnabled = function(isEnabled) {\n options.bsEnabled = isEnabled;\n };\n\n // Protected methods\n\n $tooltip.$applyPlacement = function() {\n if(!tipElement) return;\n\n // Determine if we're doing an auto or normal placement\n var placement = options.placement,\n autoToken = /\\s?auto?\\s?/i,\n autoPlace = autoToken.test(placement);\n\n if (autoPlace) {\n placement = placement.replace(autoToken, '') || defaults.placement;\n }\n\n // Need to add the position class before we get\n // the offsets\n tipElement.addClass(options.placement);\n\n // Get the position of the target element\n // and the height and width of the tooltip so we can center it.\n var elementPosition = getPosition(),\n tipWidth = tipElement.prop('offsetWidth'),\n tipHeight = tipElement.prop('offsetHeight');\n\n // If we're auto placing, we need to check the positioning\n if (autoPlace) {\n var originalPlacement = placement;\n var container = options.container ? angular.element(document.querySelector(options.container)) : element.parent();\n var containerPosition = getPosition(container);\n\n // Determine if the vertical placement\n if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) {\n placement = originalPlacement.replace('bottom', 'top');\n } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) {\n placement = originalPlacement.replace('top', 'bottom');\n }\n\n // Determine the horizontal placement\n // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right\n // and flow in the opposite direction of their placement.\n if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&\n elementPosition.right + tipWidth > containerPosition.width) {\n\n placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');\n } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&\n elementPosition.left - tipWidth < containerPosition.left) {\n\n placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');\n }\n\n tipElement.removeClass(originalPlacement).addClass(placement);\n }\n\n // Get the tooltip's top and left coordinates to center it with this directive.\n var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);\n applyPlacementCss(tipPosition.top, tipPosition.left);\n };\n\n $tooltip.$onKeyUp = function(evt) {\n if (evt.which === 27 && $tooltip.$isShown) {\n $tooltip.hide();\n evt.stopPropagation();\n }\n };\n\n $tooltip.$onFocusKeyUp = function(evt) {\n if (evt.which === 27) {\n element[0].blur();\n evt.stopPropagation();\n }\n };\n\n $tooltip.$onFocusElementMouseDown = function(evt) {\n evt.preventDefault();\n evt.stopPropagation();\n // Some browsers do not auto-focus buttons (eg. Safari)\n $tooltip.$isShown ? element[0].blur() : element[0].focus();\n };\n\n // bind/unbind events\n function bindTriggerEvents() {\n var triggers = options.trigger.split(' ');\n angular.forEach(triggers, function(trigger) {\n if(trigger === 'click') {\n element.on('click', $tooltip.toggle);\n } else if(trigger !== 'manual') {\n element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\n element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\n nodeName === 'button' && trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\n }\n });\n }\n\n function unbindTriggerEvents() {\n var triggers = options.trigger.split(' ');\n for (var i = triggers.length; i--;) {\n var trigger = triggers[i];\n if(trigger === 'click') {\n element.off('click', $tooltip.toggle);\n } else if(trigger !== 'manual') {\n element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\n element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\n nodeName === 'button' && trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\n }\n }\n }\n\n function bindKeyboardEvents() {\n if(options.trigger !== 'focus') {\n tipElement.on('keyup', $tooltip.$onKeyUp);\n } else {\n element.on('keyup', $tooltip.$onFocusKeyUp);\n }\n }\n\n function unbindKeyboardEvents() {\n if(options.trigger !== 'focus') {\n tipElement.off('keyup', $tooltip.$onKeyUp);\n } else {\n element.off('keyup', $tooltip.$onFocusKeyUp);\n }\n }\n\n var _autoCloseEventsBinded = false;\n function bindAutoCloseEvents() {\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n // Stop propagation when clicking inside tooltip\n tipElement.on('click', stopEventPropagation);\n\n // Hide when clicking outside tooltip\n $body.on('click', $tooltip.hide);\n\n _autoCloseEventsBinded = true;\n }, 0, false);\n }\n\n function unbindAutoCloseEvents() {\n if (_autoCloseEventsBinded) {\n tipElement.off('click', stopEventPropagation);\n $body.off('click', $tooltip.hide);\n _autoCloseEventsBinded = false;\n }\n }\n\n function stopEventPropagation(event) {\n event.stopPropagation();\n }\n\n // Private methods\n\n function getPosition($element) {\n $element = $element || (options.target || element);\n\n var el = $element[0];\n\n var elRect = el.getBoundingClientRect();\n if (elRect.width === null) {\n // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n elRect = angular.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top });\n }\n\n var elPos;\n if (options.container === 'body') {\n elPos = dimensions.offset(el);\n } else {\n elPos = dimensions.position(el);\n }\n\n return angular.extend({}, elRect, elPos);\n }\n\n function getCalculatedOffset(placement, position, actualWidth, actualHeight) {\n var offset;\n var split = placement.split('-');\n\n switch (split[0]) {\n case 'right':\n offset = {\n top: position.top + position.height / 2 - actualHeight / 2,\n left: position.left + position.width\n };\n break;\n case 'bottom':\n offset = {\n top: position.top + position.height,\n left: position.left + position.width / 2 - actualWidth / 2\n };\n break;\n case 'left':\n offset = {\n top: position.top + position.height / 2 - actualHeight / 2,\n left: position.left - actualWidth\n };\n break;\n default:\n offset = {\n top: position.top - actualHeight,\n left: position.left + position.width / 2 - actualWidth / 2\n };\n break;\n }\n\n if(!split[1]) {\n return offset;\n }\n\n // Add support for corners @todo css\n if(split[0] === 'top' || split[0] === 'bottom') {\n switch (split[1]) {\n case 'left':\n offset.left = position.left;\n break;\n case 'right':\n offset.left = position.left + position.width - actualWidth;\n }\n } else if(split[0] === 'left' || split[0] === 'right') {\n switch (split[1]) {\n case 'top':\n offset.top = position.top - actualHeight;\n break;\n case 'bottom':\n offset.top = position.top + position.height;\n }\n }\n\n return offset;\n }\n\n function applyPlacementCss(top, left) {\n tipElement.css({ top: top + 'px', left: left + 'px' });\n }\n\n function destroyTipElement() {\n // Cancel pending callbacks\n clearTimeout(timeout);\n\n if($tooltip.$isShown && tipElement !== null) {\n if(options.autoClose) {\n unbindAutoCloseEvents();\n }\n\n if(options.keyboard) {\n unbindKeyboardEvents();\n }\n }\n\n if(tipScope) {\n tipScope.$destroy();\n tipScope = null;\n }\n\n if(tipElement) {\n tipElement.remove();\n tipElement = $tooltip.$element = null;\n }\n }\n\n return $tooltip;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n function findElement(query, element) {\n return angular.element((element || document).querySelectorAll(query));\n }\n\n var fetchPromises = {};\n function fetchTemplate(template) {\n if(fetchPromises[template]) return fetchPromises[template];\n return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template))\n .then(function(res) {\n if(angular.isObject(res)) {\n $templateCache.put(template, res.data);\n return res.data;\n }\n return res;\n }));\n }\n\n return TooltipFactory;\n\n };\n\n })\n\n .directive('bsTooltip', function($window, $location, $sce, $tooltip, $$rAF) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // overwrite inherited title value when no value specified\n // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11\n if (!scope.hasOwnProperty('title')){\n scope.title = '';\n }\n\n // Observe scope attributes for change\n attr.$observe('title', function(newValue) {\n if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) {\n var oldValue = scope.title;\n scope.title = $sce.trustAsHtml(newValue);\n angular.isDefined(oldValue) && $$rAF(function() {\n tooltip && tooltip.$applyPlacement();\n });\n }\n });\n\n // Support scope as an object\n attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.title = newValue;\n }\n angular.isDefined(oldValue) && $$rAF(function() {\n tooltip && tooltip.$applyPlacement();\n });\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!tooltip || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i);\n newValue === true ? tooltip.show() : tooltip.hide();\n });\n\n // Enabled binding support\n attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.bsEnabled, newValue, oldValue);\n if(!tooltip || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i);\n newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true);\n });\n\n // Initialize popover\n var tooltip = $tooltip(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if(tooltip) tooltip.destroy();\n options = null;\n tooltip = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.typeahead', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions'])\n\n .provider('$typeahead', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'typeahead',\n prefixEvent: '$typeahead',\n placement: 'bottom-left',\n template: 'typeahead/typeahead.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n minLength: 1,\n filter: 'filter',\n limit: 6,\n comparator: ''\n };\n\n this.$get = function($window, $rootScope, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n\n function TypeaheadFactory(element, controller, config) {\n\n var $typeahead = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $typeahead = $tooltip(element, options);\n var parentScope = config.scope;\n var scope = $typeahead.$scope;\n\n scope.$resetMatches = function(){\n scope.$matches = [];\n scope.$activeIndex = 0;\n };\n scope.$resetMatches();\n\n scope.$activate = function(index) {\n scope.$$postDigest(function() {\n $typeahead.activate(index);\n });\n };\n\n scope.$select = function(index, evt) {\n scope.$$postDigest(function() {\n $typeahead.select(index);\n });\n };\n\n scope.$isVisible = function() {\n return $typeahead.$isVisible();\n };\n\n // Public methods\n\n $typeahead.update = function(matches) {\n scope.$matches = matches;\n if(scope.$activeIndex >= matches.length) {\n scope.$activeIndex = 0;\n }\n };\n\n $typeahead.activate = function(index) {\n scope.$activeIndex = index;\n };\n\n $typeahead.select = function(index) {\n var value = scope.$matches[index].value;\n // console.log('$setViewValue', value);\n controller.$setViewValue(value);\n controller.$render();\n scope.$resetMatches();\n if(parentScope) parentScope.$digest();\n // Emit event\n scope.$emit(options.prefixEvent + '.select', value, index, $typeahead);\n };\n\n // Protected methods\n\n $typeahead.$isVisible = function() {\n if(!options.minLength || !controller) {\n return !!scope.$matches.length;\n }\n // minLength support\n return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength;\n };\n\n $typeahead.$getIndex = function(value) {\n var l = scope.$matches.length, i = l;\n if(!l) return;\n for(i = l; i--;) {\n if(scope.$matches[i].value === value) break;\n }\n if(i < 0) return;\n return i;\n };\n\n $typeahead.$onMouseDown = function(evt) {\n // Prevent blur on mousedown\n evt.preventDefault();\n evt.stopPropagation();\n };\n\n $typeahead.$onKeyDown = function(evt) {\n if(!/(38|40|13)/.test(evt.keyCode)) return;\n\n // Let ngSubmit pass if the typeahead tip is hidden\n if($typeahead.$isVisible()) {\n evt.preventDefault();\n evt.stopPropagation();\n }\n\n // Select with enter\n if(evt.keyCode === 13 && scope.$matches.length) {\n $typeahead.select(scope.$activeIndex);\n }\n\n // Navigate with keyboard\n else if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--;\n else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++;\n else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;\n scope.$digest();\n };\n\n // Overrides\n\n var show = $typeahead.show;\n $typeahead.show = function() {\n show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $typeahead.$element.on('mousedown', $typeahead.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $typeahead.$onKeyDown);\n }\n }, 0, false);\n };\n\n var hide = $typeahead.hide;\n $typeahead.hide = function() {\n $typeahead.$element.off('mousedown', $typeahead.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $typeahead.$onKeyDown);\n }\n hide();\n };\n\n return $typeahead;\n\n }\n\n TypeaheadFactory.defaults = defaults;\n return TypeaheadFactory;\n\n };\n\n })\n\n .directive('bsTypeahead', function($window, $parse, $q, $typeahead, $parseOptions) {\n\n var defaults = $typeahead.defaults;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'comparator', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Build proper ngOptions\n var filter = options.filter || defaults.filter;\n var limit = options.limit || defaults.limit;\n var comparator = options.comparator || defaults.comparator;\n\n var ngOptions = attr.ngOptions;\n if(filter) ngOptions += ' | ' + filter + ':$viewValue';\n if (comparator) ngOptions += ':' + comparator;\n if(limit) ngOptions += ' | limitTo:' + limit;\n var parsedOptions = $parseOptions(ngOptions);\n\n // Initialize typeahead\n var typeahead = $typeahead(element, controller, options);\n\n // Watch options on demand\n if(options.watchOptions) {\n // Watch ngOptions values before filtering for changes, drop function calls\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').replace(/\\(.*\\)/g, '').trim();\n scope.$watch(watchedOptions, function (newValue, oldValue) {\n // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);\n parsedOptions.valuesFn(scope, controller).then(function (values) {\n typeahead.update(values);\n controller.$render();\n });\n }, true);\n }\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('$watch', element.attr('ng-model'), newValue);\n scope.$modelValue = newValue; // Publish modelValue on scope for custom templates\n parsedOptions.valuesFn(scope, controller)\n .then(function(values) {\n // Prevent input with no future prospect if selectMode is truthy\n // @TODO test selectMode\n if(options.selectMode && !values.length && newValue.length > 0) {\n controller.$setViewValue(controller.$viewValue.substring(0, controller.$viewValue.length - 1));\n return;\n }\n if(values.length > limit) values = values.slice(0, limit);\n var isVisible = typeahead.$isVisible();\n isVisible && typeahead.update(values);\n // Do not re-queue an update if a correct value has been selected\n if(values.length === 1 && values[0].value === newValue) return;\n !isVisible && typeahead.update(values);\n // Queue a new rendering that will leverage collection loading\n controller.$render();\n });\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var displayValue = parsedOptions.displayValue(modelValue);\n return displayValue === undefined ? '' : displayValue;\n });\n\n // Model rendering in view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n if(controller.$isEmpty(controller.$viewValue)) return element.val('');\n var index = typeahead.$getIndex(controller.$modelValue);\n var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue;\n selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected;\n element.val(selected ? selected.toString().replace(/<(?:.|\\n)*?>/gm, '').trim() : '');\n };\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (typeahead) typeahead.destroy();\n options = null;\n typeahead = null;\n });\n\n }\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/libs/angular-strap_2.1.6/angular-strap.tpl.js b/snow-flowable/src/main/resources/static/libs/angular-strap_2.1.6/angular-strap.tpl.js new file mode 100644 index 0000000..d85aa53 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-strap_2.1.6/angular-strap.tpl.js @@ -0,0 +1,89 @@ +/** + * angular-strap + * @version v2.1.6 - 2015-01-11 + * @link http://mgcrea.github.io/angular-strap + * @author Olivier Louvignes (olivier@mg-crea.com) + * @license MIT License, http://www.opensource.org/licenses/MIT + */ +(function(window, document, undefined) { +'use strict'; + +// Source: alert.tpl.js +angular.module('mgcrea.ngStrap.alert').run(['$templateCache', function($templateCache) { + + $templateCache.put('alert/alert.tpl.html', '
     
    '); + +}]); + +// Source: aside.tpl.js +angular.module('mgcrea.ngStrap.aside').run(['$templateCache', function($templateCache) { + + $templateCache.put('aside/aside.tpl.html', ''); + +}]); + +// Source: datepicker.tpl.js +angular.module('mgcrea.ngStrap.datepicker').run(['$templateCache', function($templateCache) { + + $templateCache.put('datepicker/datepicker.tpl.html', ''); + +}]); + +// Source: dropdown.tpl.js +angular.module('mgcrea.ngStrap.dropdown').run(['$templateCache', function($templateCache) { + + $templateCache.put('dropdown/dropdown.tpl.html', ''); + +}]); + +// Source: modal.tpl.js +angular.module('mgcrea.ngStrap.modal').run(['$templateCache', function($templateCache) { + + $templateCache.put('modal/modal.tpl.html', ''); + +}]); + +// Source: popover.tpl.js +angular.module('mgcrea.ngStrap.popover').run(['$templateCache', function($templateCache) { + + $templateCache.put('popover/popover.tpl.html', '

    '); + +}]); + +// Source: select.tpl.js +angular.module('mgcrea.ngStrap.select').run(['$templateCache', function($templateCache) { + + $templateCache.put('select/select.tpl.html', ''); + +}]); + +// Source: tab.tpl.js +angular.module('mgcrea.ngStrap.tab').run(['$templateCache', function($templateCache) { + + $templateCache.put('tab/tab.tpl.html', '
    '); + +}]); + +// Source: timepicker.tpl.js +angular.module('mgcrea.ngStrap.timepicker').run(['$templateCache', function($templateCache) { + + $templateCache.put('timepicker/timepicker.tpl.html', ''); + +}]); + +// Source: tooltip.tpl.js +angular.module('mgcrea.ngStrap.tooltip').run(['$templateCache', function($templateCache) { + + $templateCache.put('tooltip/tooltip.tpl.html', '
    '); + +}]); + +// Source: typeahead.tpl.js +angular.module('mgcrea.ngStrap.typeahead').run(['$templateCache', function($templateCache) { + + $templateCache.put('typeahead/typeahead.tpl.html', ''); + +}]); + + +})(window, document); diff --git a/snow-flowable/src/main/resources/static/libs/angular-strap_2.1.6/angular-strap.tpl.min.js b/snow-flowable/src/main/resources/static/libs/angular-strap_2.1.6/angular-strap.tpl.min.js new file mode 100644 index 0000000..c8f44b6 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-strap_2.1.6/angular-strap.tpl.min.js @@ -0,0 +1,8 @@ +/** + * angular-strap + * @version v2.1.6 - 2015-01-11 + * @link http://mgcrea.github.io/angular-strap + * @author Olivier Louvignes (olivier@mg-crea.com) + * @license MIT License, http://www.opensource.org/licenses/MIT + */ +!function(){"use strict";angular.module("mgcrea.ngStrap.alert").run(["$templateCache",function(t){t.put("alert/alert.tpl.html",'
     
    ')}]),angular.module("mgcrea.ngStrap.aside").run(["$templateCache",function(t){t.put("aside/aside.tpl.html",'')}]),angular.module("mgcrea.ngStrap.datepicker").run(["$templateCache",function(t){t.put("datepicker/datepicker.tpl.html",'')}]),angular.module("mgcrea.ngStrap.dropdown").run(["$templateCache",function(t){t.put("dropdown/dropdown.tpl.html",'')}]),angular.module("mgcrea.ngStrap.modal").run(["$templateCache",function(t){t.put("modal/modal.tpl.html",'')}]),angular.module("mgcrea.ngStrap.popover").run(["$templateCache",function(t){t.put("popover/popover.tpl.html",'

    ')}]),angular.module("mgcrea.ngStrap.select").run(["$templateCache",function(t){t.put("select/select.tpl.html",'')}]),angular.module("mgcrea.ngStrap.tab").run(["$templateCache",function(t){t.put("tab/tab.tpl.html",'
    ')}]),angular.module("mgcrea.ngStrap.timepicker").run(["$templateCache",function(t){t.put("timepicker/timepicker.tpl.html",'')}]),angular.module("mgcrea.ngStrap.tooltip").run(["$templateCache",function(t){t.put("tooltip/tooltip.tpl.html",'
    ')}]),angular.module("mgcrea.ngStrap.typeahead").run(["$templateCache",function(t){t.put("typeahead/typeahead.tpl.html",'')}])}(window,document); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/libs/angular-translate-loader-static-files/.bower.json b/snow-flowable/src/main/resources/static/libs/angular-translate-loader-static-files/.bower.json new file mode 100644 index 0000000..d2b66a9 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-translate-loader-static-files/.bower.json @@ -0,0 +1,19 @@ +{ + "name": "angular-translate-loader-static-files", + "version": "0.1.6", + "main": "./angular-translate-loader-static-files.js", + "dependencies": { + "angular": "1.0.8", + "angular-translate": "~1.1.1" + }, + "homepage": "https://github.com/PascalPrecht/bower-angular-translate-loader-static-files", + "_release": "0.1.6", + "_resolution": { + "type": "version", + "tag": "0.1.6", + "commit": "eaac546d29d6cde45873e6bad9d18cdff071d983" + }, + "_source": "git://github.com/PascalPrecht/bower-angular-translate-loader-static-files.git", + "_target": "0.1.6", + "_originalSource": "angular-translate-loader-static-files" +} \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/libs/angular-translate-loader-static-files/angular-translate-loader-static-files.js b/snow-flowable/src/main/resources/static/libs/angular-translate-loader-static-files/angular-translate-loader-static-files.js new file mode 100644 index 0000000..a68fbc7 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-translate-loader-static-files/angular-translate-loader-static-files.js @@ -0,0 +1,112 @@ +/*! + * angular-translate - v2.15.1 - 2017-03-04 + * + * Copyright (c) 2017 The angular-translate team, Pascal Precht; Licensed MIT + */ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define([], function () { + return (factory()); + }); + } else if (typeof exports === 'object') { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + factory(); + } +}(this, function () { + +$translateStaticFilesLoader.$inject = ['$q', '$http']; +angular.module('pascalprecht.translate') +/** + * @ngdoc object + * @name pascalprecht.translate.$translateStaticFilesLoader + * @requires $q + * @requires $http + * + * @description + * Creates a loading function for a typical static file url pattern: + * "lang-en_US.json", "lang-de_DE.json", etc. Using this builder, + * the response of these urls must be an object of key-value pairs. + * + * @param {object} options Options object, which gets prefix, suffix, key, and fileMap + */ +.factory('$translateStaticFilesLoader', $translateStaticFilesLoader); + +function $translateStaticFilesLoader($q, $http) { + + 'use strict'; + + return function (options) { + + if (!options || (!angular.isArray(options.files) && (!angular.isString(options.prefix) || !angular.isString(options.suffix)))) { + throw new Error('Couldn\'t load static files, no files and prefix or suffix specified!'); + } + + if (!options.files) { + options.files = [{ + prefix: options.prefix, + suffix: options.suffix + }]; + } + + var load = function (file) { + if (!file || (!angular.isString(file.prefix) || !angular.isString(file.suffix))) { + throw new Error('Couldn\'t load static file, no prefix or suffix specified!'); + } + + var fileUrl = [ + file.prefix, + options.key, + file.suffix + ].join(''); + + if (angular.isObject(options.fileMap) && options.fileMap[fileUrl]) { + fileUrl = options.fileMap[fileUrl]; + } + + return $http(angular.extend({ + url: fileUrl, + method: 'GET' + }, options.$http)) + .then(function(result) { + return result.data; + }, function () { + return $q.reject(options.key); + }); + }; + + var promises = [], + length = options.files.length; + + for (var i = 0; i < length; i++) { + promises.push(load({ + prefix: options.files[i].prefix, + key: options.key, + suffix: options.files[i].suffix + })); + } + + return $q.all(promises) + .then(function (data) { + var length = data.length, + mergedData = {}; + + for (var i = 0; i < length; i++) { + for (var key in data[i]) { + mergedData[key] = data[i][key]; + } + } + + return mergedData; + }); + }; +} + +$translateStaticFilesLoader.displayName = '$translateStaticFilesLoader'; +return 'pascalprecht.translate'; + +})); diff --git a/snow-flowable/src/main/resources/static/libs/angular-translate-loader-static-files/angular-translate-loader-static-files.min.js b/snow-flowable/src/main/resources/static/libs/angular-translate-loader-static-files/angular-translate-loader-static-files.min.js new file mode 100644 index 0000000..8ba0b60 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-translate-loader-static-files/angular-translate-loader-static-files.min.js @@ -0,0 +1,6 @@ +/*! + * angular-translate - v2.15.1 - 2017-03-04 + * + * Copyright (c) 2017 The angular-translate team, Pascal Precht; Licensed MIT + */ +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return b()}):"object"==typeof exports?module.exports=b():b()}(this,function(){function a(a,b){"use strict";return function(c){if(!(c&&(angular.isArray(c.files)||angular.isString(c.prefix)&&angular.isString(c.suffix))))throw new Error("Couldn't load static files, no files and prefix or suffix specified!");c.files||(c.files=[{prefix:c.prefix,suffix:c.suffix}]);for(var d=function(d){if(!d||!angular.isString(d.prefix)||!angular.isString(d.suffix))throw new Error("Couldn't load static file, no prefix or suffix specified!");var e=[d.prefix,c.key,d.suffix].join("");return angular.isObject(c.fileMap)&&c.fileMap[e]&&(e=c.fileMap[e]),b(angular.extend({url:e,method:"GET"},c.$http)).then(function(a){return a.data},function(){return a.reject(c.key)})},e=[],f=c.files.length,g=0;g= 4) { + var $cookies = $injector.get('$cookies'); + delegate = { + get : function (key) { + return $cookies.get(key); + }, + put : function (key, value) { + $cookies.put(key, value); + } + }; + } else { + var $cookieStore = $injector.get('$cookieStore'); + delegate = { + get : function (key) { + return $cookieStore.get(key); + }, + put : function (key, value) { + $cookieStore.put(key, value); + } + }; + } + + var $translateCookieStorage = { + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateCookieStorage#get + * @methodOf pascalprecht.translate.$translateCookieStorage + * + * @description + * Returns an item from cookieStorage by given name. + * + * @param {string} name Item name + * @return {string} Value of item name + */ + get : function (name) { + return delegate.get(name); + }, + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateCookieStorage#set + * @methodOf pascalprecht.translate.$translateCookieStorage + * + * @description + * Sets an item in cookieStorage by given name. + * + * @deprecated use #put + * + * @param {string} name Item name + * @param {string} value Item value + */ + set : function (name, value) { + delegate.put(name, value); + }, + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateCookieStorage#put + * @methodOf pascalprecht.translate.$translateCookieStorage + * + * @description + * Sets an item in cookieStorage by given name. + * + * @param {string} name Item name + * @param {string} value Item value + */ + put : function (name, value) { + delegate.put(name, value); + } + }; + + return $translateCookieStorage; +} + +$translateCookieStorageFactory.displayName = '$translateCookieStorage'; +return 'pascalprecht.translate'; + +})); diff --git a/snow-flowable/src/main/resources/static/libs/angular-translate-storage-cookie/angular-translate-storage-cookie.min.js b/snow-flowable/src/main/resources/static/libs/angular-translate-storage-cookie/angular-translate-storage-cookie.min.js new file mode 100644 index 0000000..54467c5 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-translate-storage-cookie/angular-translate-storage-cookie.min.js @@ -0,0 +1,6 @@ +/*! + * angular-translate - v2.15.1 - 2017-03-04 + * + * Copyright (c) 2017 The angular-translate team, Pascal Precht; Licensed MIT + */ +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return b()}):"object"==typeof exports?module.exports=b():b()}(this,function(){function a(a){"use strict";var b;if(1===angular.version.major&&angular.version.minor>=4){var c=a.get("$cookies");b={get:function(a){return c.get(a)},put:function(a,b){c.put(a,b)}}}else{var d=a.get("$cookieStore");b={get:function(a){return d.get(a)},put:function(a,b){d.put(a,b)}}}var e={get:function(a){return b.get(a)},set:function(a,c){b.put(a,c)},put:function(a,c){b.put(a,c)}};return e}return a.$inject=["$injector"],angular.module("pascalprecht.translate").factory("$translateCookieStorage",a),a.displayName="$translateCookieStorage","pascalprecht.translate"}); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/libs/angular-translate_2.15.1/angular-translate.js b/snow-flowable/src/main/resources/static/libs/angular-translate_2.15.1/angular-translate.js new file mode 100644 index 0000000..c2e2e14 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-translate_2.15.1/angular-translate.js @@ -0,0 +1,3709 @@ +/*! + * angular-translate - v2.15.1 - 2017-03-04 + * + * Copyright (c) 2017 The angular-translate team, Pascal Precht; Licensed MIT + */ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define([], function () { + return (factory()); + }); + } else if (typeof exports === 'object') { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + factory(); + } +}(this, function () { + +/** + * @ngdoc overview + * @name pascalprecht.translate + * + * @description + * The main module which holds everything together. + */ +runTranslate.$inject = ['$translate']; +$translate.$inject = ['$STORAGE_KEY', '$windowProvider', '$translateSanitizationProvider', 'pascalprechtTranslateOverrider']; +$translateDefaultInterpolation.$inject = ['$interpolate', '$translateSanitization']; +translateDirective.$inject = ['$translate', '$interpolate', '$compile', '$parse', '$rootScope']; +translateAttrDirective.$inject = ['$translate', '$rootScope']; +translateCloakDirective.$inject = ['$translate', '$rootScope']; +translateFilterFactory.$inject = ['$parse', '$translate']; +$translationCache.$inject = ['$cacheFactory']; +angular.module('pascalprecht.translate', ['ng']) + .run(runTranslate); + +function runTranslate($translate) { + + 'use strict'; + + var key = $translate.storageKey(), + storage = $translate.storage(); + + var fallbackFromIncorrectStorageValue = function () { + var preferred = $translate.preferredLanguage(); + if (angular.isString(preferred)) { + $translate.use(preferred); + // $translate.use() will also remember the language. + // So, we don't need to call storage.put() here. + } else { + storage.put(key, $translate.use()); + } + }; + + fallbackFromIncorrectStorageValue.displayName = 'fallbackFromIncorrectStorageValue'; + + if (storage) { + if (!storage.get(key)) { + fallbackFromIncorrectStorageValue(); + } else { + $translate.use(storage.get(key))['catch'](fallbackFromIncorrectStorageValue); + } + } else if (angular.isString($translate.preferredLanguage())) { + $translate.use($translate.preferredLanguage()); + } +} + +runTranslate.displayName = 'runTranslate'; + +/** + * @ngdoc object + * @name pascalprecht.translate.$translateSanitizationProvider + * + * @description + * + * Configurations for $translateSanitization + */ +angular.module('pascalprecht.translate').provider('$translateSanitization', $translateSanitizationProvider); + +function $translateSanitizationProvider () { + + 'use strict'; + + var $sanitize, + $sce, + currentStrategy = null, // TODO change to either 'sanitize', 'escape' or ['sanitize', 'escapeParameters'] in 3.0. + hasConfiguredStrategy = false, + hasShownNoStrategyConfiguredWarning = false, + strategies; + + /** + * Definition of a sanitization strategy function + * @callback StrategyFunction + * @param {string|object} value - value to be sanitized (either a string or an interpolated value map) + * @param {string} mode - either 'text' for a string (translation) or 'params' for the interpolated params + * @return {string|object} + */ + + /** + * @ngdoc property + * @name strategies + * @propertyOf pascalprecht.translate.$translateSanitizationProvider + * + * @description + * Following strategies are built-in: + *
    + *
    sanitize
    + *
    Sanitizes HTML in the translation text using $sanitize
    + *
    escape
    + *
    Escapes HTML in the translation
    + *
    sanitizeParameters
    + *
    Sanitizes HTML in the values of the interpolation parameters using $sanitize
    + *
    escapeParameters
    + *
    Escapes HTML in the values of the interpolation parameters
    + *
    escaped
    + *
    Support legacy strategy name 'escaped' for backwards compatibility (will be removed in 3.0)
    + *
    + * + */ + + strategies = { + sanitize: function (value, mode/*, context*/) { + if (mode === 'text') { + value = htmlSanitizeValue(value); + } + return value; + }, + escape: function (value, mode/*, context*/) { + if (mode === 'text') { + value = htmlEscapeValue(value); + } + return value; + }, + sanitizeParameters: function (value, mode/*, context*/) { + if (mode === 'params') { + value = mapInterpolationParameters(value, htmlSanitizeValue); + } + return value; + }, + escapeParameters: function (value, mode/*, context*/) { + if (mode === 'params') { + value = mapInterpolationParameters(value, htmlEscapeValue); + } + return value; + }, + sce: function (value, mode, context) { + if (mode === 'text') { + value = htmlTrustValue(value); + } else if (mode === 'params') { + if (context !== 'filter') { + // do html escape in filter context #1101 + value = mapInterpolationParameters(value, htmlEscapeValue); + } + } + return value; + }, + sceParameters: function (value, mode/*, context*/) { + if (mode === 'params') { + value = mapInterpolationParameters(value, htmlTrustValue); + } + return value; + } + }; + // Support legacy strategy name 'escaped' for backwards compatibility. + // TODO should be removed in 3.0 + strategies.escaped = strategies.escapeParameters; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateSanitizationProvider#addStrategy + * @methodOf pascalprecht.translate.$translateSanitizationProvider + * + * @description + * Adds a sanitization strategy to the list of known strategies. + * + * @param {string} strategyName - unique key for a strategy + * @param {StrategyFunction} strategyFunction - strategy function + * @returns {object} this + */ + this.addStrategy = function (strategyName, strategyFunction) { + strategies[strategyName] = strategyFunction; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateSanitizationProvider#removeStrategy + * @methodOf pascalprecht.translate.$translateSanitizationProvider + * + * @description + * Removes a sanitization strategy from the list of known strategies. + * + * @param {string} strategyName - unique key for a strategy + * @returns {object} this + */ + this.removeStrategy = function (strategyName) { + delete strategies[strategyName]; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateSanitizationProvider#useStrategy + * @methodOf pascalprecht.translate.$translateSanitizationProvider + * + * @description + * Selects a sanitization strategy. When an array is provided the strategies will be executed in order. + * + * @param {string|StrategyFunction|array} strategy The sanitization strategy / strategies which should be used. Either a name of an existing strategy, a custom strategy function, or an array consisting of multiple names and / or custom functions. + * @returns {object} this + */ + this.useStrategy = function (strategy) { + hasConfiguredStrategy = true; + currentStrategy = strategy; + return this; + }; + + /** + * @ngdoc object + * @name pascalprecht.translate.$translateSanitization + * @requires $injector + * @requires $log + * + * @description + * Sanitizes interpolation parameters and translated texts. + * + */ + this.$get = ['$injector', '$log', function ($injector, $log) { + + var cachedStrategyMap = {}; + + var applyStrategies = function (value, mode, context, selectedStrategies) { + angular.forEach(selectedStrategies, function (selectedStrategy) { + if (angular.isFunction(selectedStrategy)) { + value = selectedStrategy(value, mode, context); + } else if (angular.isFunction(strategies[selectedStrategy])) { + value = strategies[selectedStrategy](value, mode, context); + } else if (angular.isString(strategies[selectedStrategy])) { + if (!cachedStrategyMap[strategies[selectedStrategy]]) { + try { + cachedStrategyMap[strategies[selectedStrategy]] = $injector.get(strategies[selectedStrategy]); + } catch (e) { + cachedStrategyMap[strategies[selectedStrategy]] = function() {}; + throw new Error('pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: \'' + selectedStrategy + '\''); + } + } + value = cachedStrategyMap[strategies[selectedStrategy]](value, mode, context); + } else { + throw new Error('pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: \'' + selectedStrategy + '\''); + } + }); + return value; + }; + + // TODO: should be removed in 3.0 + var showNoStrategyConfiguredWarning = function () { + if (!hasConfiguredStrategy && !hasShownNoStrategyConfiguredWarning) { + $log.warn('pascalprecht.translate.$translateSanitization: No sanitization strategy has been configured. This can have serious security implications. See http://angular-translate.github.io/docs/#/guide/19_security for details.'); + hasShownNoStrategyConfiguredWarning = true; + } + }; + + if ($injector.has('$sanitize')) { + $sanitize = $injector.get('$sanitize'); + } + if ($injector.has('$sce')) { + $sce = $injector.get('$sce'); + } + + return { + /** + * @ngdoc function + * @name pascalprecht.translate.$translateSanitization#useStrategy + * @methodOf pascalprecht.translate.$translateSanitization + * + * @description + * Selects a sanitization strategy. When an array is provided the strategies will be executed in order. + * + * @param {string|StrategyFunction|array} strategy The sanitization strategy / strategies which should be used. Either a name of an existing strategy, a custom strategy function, or an array consisting of multiple names and / or custom functions. + */ + useStrategy: (function (self) { + return function (strategy) { + self.useStrategy(strategy); + }; + })(this), + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateSanitization#sanitize + * @methodOf pascalprecht.translate.$translateSanitization + * + * @description + * Sanitizes a value. + * + * @param {string|object} value The value which should be sanitized. + * @param {string} mode The current sanitization mode, either 'params' or 'text'. + * @param {string|StrategyFunction|array} [strategy] Optional custom strategy which should be used instead of the currently selected strategy. + * @param {string} [context] The context of this call: filter, service. Default is service + * @returns {string|object} sanitized value + */ + sanitize: function (value, mode, strategy, context) { + if (!currentStrategy) { + showNoStrategyConfiguredWarning(); + } + + if (!strategy && strategy !== null) { + strategy = currentStrategy; + } + + if (!strategy) { + return value; + } + + if (!context) { + context = 'service'; + } + + var selectedStrategies = angular.isArray(strategy) ? strategy : [strategy]; + return applyStrategies(value, mode, context, selectedStrategies); + } + }; + }]; + + var htmlEscapeValue = function (value) { + var element = angular.element('
    '); + element.text(value); // not chainable, see #1044 + return element.html(); + }; + + var htmlSanitizeValue = function (value) { + if (!$sanitize) { + throw new Error('pascalprecht.translate.$translateSanitization: Error cannot find $sanitize service. Either include the ngSanitize module (https://docs.angularjs.org/api/ngSanitize) or use a sanitization strategy which does not depend on $sanitize, such as \'escape\'.'); + } + return $sanitize(value); + }; + + var htmlTrustValue = function (value) { + if (!$sce) { + throw new Error('pascalprecht.translate.$translateSanitization: Error cannot find $sce service.'); + } + return $sce.trustAsHtml(value); + }; + + var mapInterpolationParameters = function (value, iteratee, stack) { + if (angular.isDate(value)) { + return value; + } else if (angular.isObject(value)) { + var result = angular.isArray(value) ? [] : {}; + + if (!stack) { + stack = []; + } else { + if (stack.indexOf(value) > -1) { + throw new Error('pascalprecht.translate.$translateSanitization: Error cannot interpolate parameter due recursive object'); + } + } + + stack.push(value); + angular.forEach(value, function (propertyValue, propertyKey) { + + /* Skipping function properties. */ + if (angular.isFunction(propertyValue)) { + return; + } + + result[propertyKey] = mapInterpolationParameters(propertyValue, iteratee, stack); + }); + stack.splice(-1, 1); // remove last + + return result; + } else if (angular.isNumber(value)) { + return value; + } else if (!angular.isUndefined(value) && value !== null) { + return iteratee(value); + } else { + return value; + } + }; +} + +/** + * @ngdoc object + * @name pascalprecht.translate.$translateProvider + * @description + * + * $translateProvider allows developers to register translation-tables, asynchronous loaders + * and similar to configure translation behavior directly inside of a module. + * + */ +angular.module('pascalprecht.translate') + .constant('pascalprechtTranslateOverrider', {}) + .provider('$translate', $translate); + +function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvider, pascalprechtTranslateOverrider) { + + 'use strict'; + + var $translationTable = {}, + $preferredLanguage, + $availableLanguageKeys = [], + $languageKeyAliases, + $fallbackLanguage, + $fallbackWasString, + $uses, + $nextLang, + $storageFactory, + $storageKey = $STORAGE_KEY, + $storagePrefix, + $missingTranslationHandlerFactory, + $interpolationFactory, + $interpolatorFactories = [], + $loaderFactory, + $cloakClassName = 'translate-cloak', + $loaderOptions, + $notFoundIndicatorLeft, + $notFoundIndicatorRight, + $postCompilingEnabled = false, + $forceAsyncReloadEnabled = false, + $nestedObjectDelimeter = '.', + $isReady = false, + $keepContent = false, + loaderCache, + directivePriority = 0, + statefulFilter = true, + postProcessFn, + uniformLanguageTagResolver = 'default', + languageTagResolver = { + 'default' : function (tag) { + return (tag || '').split('-').join('_'); + }, + java : function (tag) { + var temp = (tag || '').split('-').join('_'); + var parts = temp.split('_'); + return parts.length > 1 ? (parts[0].toLowerCase() + '_' + parts[1].toUpperCase()) : temp; + }, + bcp47 : function (tag) { + var temp = (tag || '').split('_').join('-'); + var parts = temp.split('-'); + return parts.length > 1 ? (parts[0].toLowerCase() + '-' + parts[1].toUpperCase()) : temp; + }, + 'iso639-1' : function (tag) { + var temp = (tag || '').split('_').join('-'); + var parts = temp.split('-'); + return parts[0].toLowerCase(); + } + }; + + var version = '2.15.1'; + + // tries to determine the browsers language + var getFirstBrowserLanguage = function () { + + // internal purpose only + if (angular.isFunction(pascalprechtTranslateOverrider.getLocale)) { + return pascalprechtTranslateOverrider.getLocale(); + } + + var nav = $windowProvider.$get().navigator, + browserLanguagePropertyKeys = ['language', 'browserLanguage', 'systemLanguage', 'userLanguage'], + i, + language; + + // support for HTML 5.1 "navigator.languages" + if (angular.isArray(nav.languages)) { + for (i = 0; i < nav.languages.length; i++) { + language = nav.languages[i]; + if (language && language.length) { + return language; + } + } + } + + // support for other well known properties in browsers + for (i = 0; i < browserLanguagePropertyKeys.length; i++) { + language = nav[browserLanguagePropertyKeys[i]]; + if (language && language.length) { + return language; + } + } + + return null; + }; + getFirstBrowserLanguage.displayName = 'angular-translate/service: getFirstBrowserLanguage'; + + // tries to determine the browsers locale + var getLocale = function () { + var locale = getFirstBrowserLanguage() || ''; + if (languageTagResolver[uniformLanguageTagResolver]) { + locale = languageTagResolver[uniformLanguageTagResolver](locale); + } + return locale; + }; + getLocale.displayName = 'angular-translate/service: getLocale'; + + /** + * @name indexOf + * @private + * + * @description + * indexOf polyfill. Kinda sorta. + * + * @param {array} array Array to search in. + * @param {string} searchElement Element to search for. + * + * @returns {int} Index of search element. + */ + var indexOf = function (array, searchElement) { + for (var i = 0, len = array.length; i < len; i++) { + if (array[i] === searchElement) { + return i; + } + } + return -1; + }; + + /** + * @name trim + * @private + * + * @description + * trim polyfill + * + * @returns {string} The string stripped of whitespace from both ends + */ + var trim = function () { + return this.toString().replace(/^\s+|\s+$/g, ''); + }; + + var negotiateLocale = function (preferred) { + if (!preferred) { + return; + } + + var avail = [], + locale = angular.lowercase(preferred), + i = 0, + n = $availableLanguageKeys.length; + + for (; i < n; i++) { + avail.push(angular.lowercase($availableLanguageKeys[i])); + } + + // Check for an exact match in our list of available keys + if (indexOf(avail, locale) > -1) { + return preferred; + } + + if ($languageKeyAliases) { + var alias; + for (var langKeyAlias in $languageKeyAliases) { + if ($languageKeyAliases.hasOwnProperty(langKeyAlias)) { + var hasWildcardKey = false; + var hasExactKey = Object.prototype.hasOwnProperty.call($languageKeyAliases, langKeyAlias) && + angular.lowercase(langKeyAlias) === angular.lowercase(preferred); + + if (langKeyAlias.slice(-1) === '*') { + hasWildcardKey = langKeyAlias.slice(0, -1) === preferred.slice(0, langKeyAlias.length - 1); + } + if (hasExactKey || hasWildcardKey) { + alias = $languageKeyAliases[langKeyAlias]; + if (indexOf(avail, angular.lowercase(alias)) > -1) { + return alias; + } + } + } + } + } + + // Check for a language code without region + var parts = preferred.split('_'); + + if (parts.length > 1 && indexOf(avail, angular.lowercase(parts[0])) > -1) { + return parts[0]; + } + + // If everything fails, return undefined. + return; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#translations + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Registers a new translation table for specific language key. + * + * To register a translation table for specific language, pass a defined language + * key as first parameter. + * + *
    +   *  // register translation table for language: 'de_DE'
    +   *  $translateProvider.translations('de_DE', {
    +   *    'GREETING': 'Hallo Welt!'
    +   *  });
    +   *
    +   *  // register another one
    +   *  $translateProvider.translations('en_US', {
    +   *    'GREETING': 'Hello world!'
    +   *  });
    +   * 
    + * + * When registering multiple translation tables for for the same language key, + * the actual translation table gets extended. This allows you to define module + * specific translation which only get added, once a specific module is loaded in + * your app. + * + * Invoking this method with no arguments returns the translation table which was + * registered with no language key. Invoking it with a language key returns the + * related translation table. + * + * @param {string} langKey A language key. + * @param {object} translationTable A plain old JavaScript object that represents a translation table. + * + */ + var translations = function (langKey, translationTable) { + + if (!langKey && !translationTable) { + return $translationTable; + } + + if (langKey && !translationTable) { + if (angular.isString(langKey)) { + return $translationTable[langKey]; + } + } else { + if (!angular.isObject($translationTable[langKey])) { + $translationTable[langKey] = {}; + } + angular.extend($translationTable[langKey], flatObject(translationTable)); + } + return this; + }; + + this.translations = translations; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#cloakClassName + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * + * Let's you change the class name for `translate-cloak` directive. + * Default class name is `translate-cloak`. + * + * @param {string} name translate-cloak class name + */ + this.cloakClassName = function (name) { + if (!name) { + return $cloakClassName; + } + $cloakClassName = name; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#nestedObjectDelimeter + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * + * Let's you change the delimiter for namespaced translations. + * Default delimiter is `.`. + * + * @param {string} delimiter namespace separator + */ + this.nestedObjectDelimeter = function (delimiter) { + if (!delimiter) { + return $nestedObjectDelimeter; + } + $nestedObjectDelimeter = delimiter; + return this; + }; + + /** + * @name flatObject + * @private + * + * @description + * Flats an object. This function is used to flatten given translation data with + * namespaces, so they are later accessible via dot notation. + */ + var flatObject = function (data, path, result, prevKey) { + var key, keyWithPath, keyWithShortPath, val; + + if (!path) { + path = []; + } + if (!result) { + result = {}; + } + for (key in data) { + if (!Object.prototype.hasOwnProperty.call(data, key)) { + continue; + } + val = data[key]; + if (angular.isObject(val)) { + flatObject(val, path.concat(key), result, key); + } else { + keyWithPath = path.length ? ('' + path.join($nestedObjectDelimeter) + $nestedObjectDelimeter + key) : key; + if (path.length && key === prevKey) { + // Create shortcut path (foo.bar == foo.bar.bar) + keyWithShortPath = '' + path.join($nestedObjectDelimeter); + // Link it to original path + result[keyWithShortPath] = '@:' + keyWithPath; + } + result[keyWithPath] = val; + } + } + return result; + }; + flatObject.displayName = 'flatObject'; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#addInterpolation + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Adds interpolation services to angular-translate, so it can manage them. + * + * @param {object} factory Interpolation service factory + */ + this.addInterpolation = function (factory) { + $interpolatorFactories.push(factory); + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useMessageFormatInterpolation + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use interpolation functionality of messageformat.js. + * This is useful when having high level pluralization and gender selection. + */ + this.useMessageFormatInterpolation = function () { + return this.useInterpolation('$translateMessageFormatInterpolation'); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useInterpolation + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate which interpolation style to use as default, application-wide. + * Simply pass a factory/service name. The interpolation service has to implement + * the correct interface. + * + * @param {string} factory Interpolation service name. + */ + this.useInterpolation = function (factory) { + $interpolationFactory = factory; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useSanitizeStrategy + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Simply sets a sanitation strategy type. + * + * @param {string} value Strategy type. + */ + this.useSanitizeValueStrategy = function (value) { + $translateSanitizationProvider.useStrategy(value); + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#preferredLanguage + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells the module which of the registered translation tables to use for translation + * at initial startup by passing a language key. Similar to `$translateProvider#use` + * only that it says which language to **prefer**. + * + * @param {string} langKey A language key. + */ + this.preferredLanguage = function (langKey) { + if (langKey) { + setupPreferredLanguage(langKey); + return this; + } + return $preferredLanguage; + }; + var setupPreferredLanguage = function (langKey) { + if (langKey) { + $preferredLanguage = langKey; + } + return $preferredLanguage; + }; + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#translationNotFoundIndicator + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Sets an indicator which is used when a translation isn't found. E.g. when + * setting the indicator as 'X' and one tries to translate a translation id + * called `NOT_FOUND`, this will result in `X NOT_FOUND X`. + * + * Internally this methods sets a left indicator and a right indicator using + * `$translateProvider.translationNotFoundIndicatorLeft()` and + * `$translateProvider.translationNotFoundIndicatorRight()`. + * + * **Note**: These methods automatically add a whitespace between the indicators + * and the translation id. + * + * @param {string} indicator An indicator, could be any string. + */ + this.translationNotFoundIndicator = function (indicator) { + this.translationNotFoundIndicatorLeft(indicator); + this.translationNotFoundIndicatorRight(indicator); + return this; + }; + + /** + * ngdoc function + * @name pascalprecht.translate.$translateProvider#translationNotFoundIndicatorLeft + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Sets an indicator which is used when a translation isn't found left to the + * translation id. + * + * @param {string} indicator An indicator. + */ + this.translationNotFoundIndicatorLeft = function (indicator) { + if (!indicator) { + return $notFoundIndicatorLeft; + } + $notFoundIndicatorLeft = indicator; + return this; + }; + + /** + * ngdoc function + * @name pascalprecht.translate.$translateProvider#translationNotFoundIndicatorLeft + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Sets an indicator which is used when a translation isn't found right to the + * translation id. + * + * @param {string} indicator An indicator. + */ + this.translationNotFoundIndicatorRight = function (indicator) { + if (!indicator) { + return $notFoundIndicatorRight; + } + $notFoundIndicatorRight = indicator; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#fallbackLanguage + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells the module which of the registered translation tables to use when missing translations + * at initial startup by passing a language key. Similar to `$translateProvider#use` + * only that it says which language to **fallback**. + * + * @param {string||array} langKey A language key. + * + */ + this.fallbackLanguage = function (langKey) { + fallbackStack(langKey); + return this; + }; + + var fallbackStack = function (langKey) { + if (langKey) { + if (angular.isString(langKey)) { + $fallbackWasString = true; + $fallbackLanguage = [langKey]; + } else if (angular.isArray(langKey)) { + $fallbackWasString = false; + $fallbackLanguage = langKey; + } + if (angular.isString($preferredLanguage) && indexOf($fallbackLanguage, $preferredLanguage) < 0) { + $fallbackLanguage.push($preferredLanguage); + } + + return this; + } else { + if ($fallbackWasString) { + return $fallbackLanguage[0]; + } else { + return $fallbackLanguage; + } + } + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#use + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Set which translation table to use for translation by given language key. When + * trying to 'use' a language which isn't provided, it'll throw an error. + * + * You actually don't have to use this method since `$translateProvider#preferredLanguage` + * does the job too. + * + * @param {string} langKey A language key. + */ + this.use = function (langKey) { + if (langKey) { + if (!$translationTable[langKey] && (!$loaderFactory)) { + // only throw an error, when not loading translation data asynchronously + throw new Error('$translateProvider couldn\'t find translationTable for langKey: \'' + langKey + '\''); + } + $uses = langKey; + return this; + } + return $uses; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#resolveClientLocale + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * This returns the current browser/client's language key. The result is processed with the configured uniform tag resolver. + * + * @returns {string} the current client/browser language key + */ + this.resolveClientLocale = function () { + return getLocale(); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#storageKey + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells the module which key must represent the choosed language by a user in the storage. + * + * @param {string} key A key for the storage. + */ + var storageKey = function (key) { + if (!key) { + if ($storagePrefix) { + return $storagePrefix + $storageKey; + } + return $storageKey; + } + $storageKey = key; + return this; + }; + + this.storageKey = storageKey; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useUrlLoader + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use `$translateUrlLoader` extension service as loader. + * + * @param {string} url Url + * @param {Object=} options Optional configuration object + */ + this.useUrlLoader = function (url, options) { + return this.useLoader('$translateUrlLoader', angular.extend({url : url}, options)); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useStaticFilesLoader + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use `$translateStaticFilesLoader` extension service as loader. + * + * @param {Object=} options Optional configuration object + */ + this.useStaticFilesLoader = function (options) { + return this.useLoader('$translateStaticFilesLoader', options); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useLoader + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use any other service as loader. + * + * @param {string} loaderFactory Factory name to use + * @param {Object=} options Optional configuration object + */ + this.useLoader = function (loaderFactory, options) { + $loaderFactory = loaderFactory; + $loaderOptions = options || {}; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useLocalStorage + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use `$translateLocalStorage` service as storage layer. + * + */ + this.useLocalStorage = function () { + return this.useStorage('$translateLocalStorage'); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useCookieStorage + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use `$translateCookieStorage` service as storage layer. + */ + this.useCookieStorage = function () { + return this.useStorage('$translateCookieStorage'); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useStorage + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use custom service as storage layer. + */ + this.useStorage = function (storageFactory) { + $storageFactory = storageFactory; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#storagePrefix + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Sets prefix for storage key. + * + * @param {string} prefix Storage key prefix + */ + this.storagePrefix = function (prefix) { + if (!prefix) { + return prefix; + } + $storagePrefix = prefix; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useMissingTranslationHandlerLog + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use built-in log handler when trying to translate + * a translation Id which doesn't exist. + * + * This is actually a shortcut method for `useMissingTranslationHandler()`. + * + */ + this.useMissingTranslationHandlerLog = function () { + return this.useMissingTranslationHandler('$translateMissingTranslationHandlerLog'); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useMissingTranslationHandler + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Expects a factory name which later gets instantiated with `$injector`. + * This method can be used to tell angular-translate to use a custom + * missingTranslationHandler. Just build a factory which returns a function + * and expects a translation id as argument. + * + * Example: + *
    +   *  app.config(function ($translateProvider) {
    +   *    $translateProvider.useMissingTranslationHandler('customHandler');
    +   *  });
    +   *
    +   *  app.factory('customHandler', function (dep1, dep2) {
    +   *    return function (translationId) {
    +   *      // something with translationId and dep1 and dep2
    +   *    };
    +   *  });
    +   * 
    + * + * @param {string} factory Factory name + */ + this.useMissingTranslationHandler = function (factory) { + $missingTranslationHandlerFactory = factory; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#usePostCompiling + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * If post compiling is enabled, all translated values will be processed + * again with AngularJS' $compile. + * + * Example: + *
    +   *  app.config(function ($translateProvider) {
    +   *    $translateProvider.usePostCompiling(true);
    +   *  });
    +   * 
    + * + * @param {string} factory Factory name + */ + this.usePostCompiling = function (value) { + $postCompilingEnabled = !(!value); + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#forceAsyncReload + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * If force async reload is enabled, async loader will always be called + * even if $translationTable already contains the language key, adding + * possible new entries to the $translationTable. + * + * Example: + *
    +   *  app.config(function ($translateProvider) {
    +   *    $translateProvider.forceAsyncReload(true);
    +   *  });
    +   * 
    + * + * @param {boolean} value - valid values are true or false + */ + this.forceAsyncReload = function (value) { + $forceAsyncReloadEnabled = !(!value); + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#uniformLanguageTag + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate which language tag should be used as a result when determining + * the current browser language. + * + * This setting must be set before invoking {@link pascalprecht.translate.$translateProvider#methods_determinePreferredLanguage determinePreferredLanguage()}. + * + *
    +   * $translateProvider
    +   *   .uniformLanguageTag('bcp47')
    +   *   .determinePreferredLanguage()
    +   * 
    + * + * The resolver currently supports: + * * default + * (traditionally: hyphens will be converted into underscores, i.e. en-US => en_US) + * en-US => en_US + * en_US => en_US + * en-us => en_us + * * java + * like default, but the second part will be always in uppercase + * en-US => en_US + * en_US => en_US + * en-us => en_US + * * BCP 47 (RFC 4646 & 4647) + * en-US => en-US + * en_US => en-US + * en-us => en-US + * + * See also: + * * http://en.wikipedia.org/wiki/IETF_language_tag + * * http://www.w3.org/International/core/langtags/ + * * http://tools.ietf.org/html/bcp47 + * + * @param {string|object} options - options (or standard) + * @param {string} options.standard - valid values are 'default', 'bcp47', 'java' + */ + this.uniformLanguageTag = function (options) { + + if (!options) { + options = {}; + } else if (angular.isString(options)) { + options = { + standard : options + }; + } + + uniformLanguageTagResolver = options.standard; + + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#determinePreferredLanguage + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to try to determine on its own which language key + * to set as preferred language. When `fn` is given, angular-translate uses it + * to determine a language key, otherwise it uses the built-in `getLocale()` + * method. + * + * The `getLocale()` returns a language key in the format `[lang]_[country]` or + * `[lang]` depending on what the browser provides. + * + * Use this method at your own risk, since not all browsers return a valid + * locale (see {@link pascalprecht.translate.$translateProvider#methods_uniformLanguageTag uniformLanguageTag()}). + * + * @param {Function=} fn Function to determine a browser's locale + */ + this.determinePreferredLanguage = function (fn) { + + var locale = (fn && angular.isFunction(fn)) ? fn() : getLocale(); + + if (!$availableLanguageKeys.length) { + $preferredLanguage = locale; + } else { + $preferredLanguage = negotiateLocale(locale) || locale; + } + + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#registerAvailableLanguageKeys + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Registers a set of language keys the app will work with. Use this method in + * combination with + * {@link pascalprecht.translate.$translateProvider#determinePreferredLanguage determinePreferredLanguage}. + * When available languages keys are registered, angular-translate + * tries to find the best fitting language key depending on the browsers locale, + * considering your language key convention. + * + * @param {object} languageKeys Array of language keys the your app will use + * @param {object=} aliases Alias map. + */ + this.registerAvailableLanguageKeys = function (languageKeys, aliases) { + if (languageKeys) { + $availableLanguageKeys = languageKeys; + if (aliases) { + $languageKeyAliases = aliases; + } + return this; + } + return $availableLanguageKeys; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useLoaderCache + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Registers a cache for internal $http based loaders. + * {@link pascalprecht.translate.$translationCache $translationCache}. + * When false the cache will be disabled (default). When true or undefined + * the cache will be a default (see $cacheFactory). When an object it will + * be treat as a cache object itself: the usage is $http({cache: cache}) + * + * @param {object} cache boolean, string or cache-object + */ + this.useLoaderCache = function (cache) { + if (cache === false) { + // disable cache + loaderCache = undefined; + } else if (cache === true) { + // enable cache using AJS defaults + loaderCache = true; + } else if (typeof(cache) === 'undefined') { + // enable cache using default + loaderCache = '$translationCache'; + } else if (cache) { + // enable cache using given one (see $cacheFactory) + loaderCache = cache; + } + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#directivePriority + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Sets the default priority of the translate directive. The standard value is `0`. + * Calling this function without an argument will return the current value. + * + * @param {number} priority for the translate-directive + */ + this.directivePriority = function (priority) { + if (priority === undefined) { + // getter + return directivePriority; + } else { + // setter with chaining + directivePriority = priority; + return this; + } + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#statefulFilter + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Since AngularJS 1.3, filters which are not stateless (depending at the scope) + * have to explicit define this behavior. + * Sets whether the translate filter should be stateful or stateless. The standard value is `true` + * meaning being stateful. + * Calling this function without an argument will return the current value. + * + * @param {boolean} state - defines the state of the filter + */ + this.statefulFilter = function (state) { + if (state === undefined) { + // getter + return statefulFilter; + } else { + // setter with chaining + statefulFilter = state; + return this; + } + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#postProcess + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * The post processor will be intercept right after the translation result. It can modify the result. + * + * @param {object} fn Function or service name (string) to be called after the translation value has been set / resolved. The function itself will enrich every value being processed and then continue the normal resolver process + */ + this.postProcess = function (fn) { + if (fn) { + postProcessFn = fn; + } else { + postProcessFn = undefined; + } + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#keepContent + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * If keepContent is set to true than translate directive will always use innerHTML + * as a default translation + * + * Example: + *
    +   *  app.config(function ($translateProvider) {
    +   *    $translateProvider.keepContent(true);
    +   *  });
    +   * 
    + * + * @param {boolean} value - valid values are true or false + */ + this.keepContent = function (value) { + $keepContent = !(!value); + return this; + }; + + /** + * @ngdoc object + * @name pascalprecht.translate.$translate + * @requires $interpolate + * @requires $log + * @requires $rootScope + * @requires $q + * + * @description + * The `$translate` service is the actual core of angular-translate. It expects a translation id + * and optional interpolate parameters to translate contents. + * + *
    +   *  $translate('HEADLINE_TEXT').then(function (translation) {
    +   *    $scope.translatedText = translation;
    +   *  });
    +   * 
    + * + * @param {string|array} translationId A token which represents a translation id + * This can be optionally an array of translation ids which + * results that the function returns an object where each key + * is the translation id and the value the translation. + * @param {object=} interpolateParams An object hash for dynamic values + * @param {string} interpolationId The id of the interpolation to use + * @param {string} defaultTranslationText the optional default translation text that is written as + * as default text in case it is not found in any configured language + * @param {string} forceLanguage A language to be used instead of the current language + * @returns {object} promise + */ + this.$get = ['$log', '$injector', '$rootScope', '$q', function ($log, $injector, $rootScope, $q) { + + var Storage, + defaultInterpolator = $injector.get($interpolationFactory || '$translateDefaultInterpolation'), + pendingLoader = false, + interpolatorHashMap = {}, + langPromises = {}, + fallbackIndex, + startFallbackIteration; + + var $translate = function (translationId, interpolateParams, interpolationId, defaultTranslationText, forceLanguage) { + if (!$uses && $preferredLanguage) { + $uses = $preferredLanguage; + } + var uses = (forceLanguage && forceLanguage !== $uses) ? // we don't want to re-negotiate $uses + (negotiateLocale(forceLanguage) || forceLanguage) : $uses; + + // Check forceLanguage is present + if (forceLanguage) { + loadTranslationsIfMissing(forceLanguage); + } + + // Duck detection: If the first argument is an array, a bunch of translations was requested. + // The result is an object. + if (angular.isArray(translationId)) { + // Inspired by Q.allSettled by Kris Kowal + // https://github.com/kriskowal/q/blob/b0fa72980717dc202ffc3cbf03b936e10ebbb9d7/q.js#L1553-1563 + // This transforms all promises regardless resolved or rejected + var translateAll = function (translationIds) { + var results = {}; // storing the actual results + var promises = []; // promises to wait for + // Wraps the promise a) being always resolved and b) storing the link id->value + var translate = function (translationId) { + var deferred = $q.defer(); + var regardless = function (value) { + results[translationId] = value; + deferred.resolve([translationId, value]); + }; + // we don't care whether the promise was resolved or rejected; just store the values + $translate(translationId, interpolateParams, interpolationId, defaultTranslationText, forceLanguage).then(regardless, regardless); + return deferred.promise; + }; + for (var i = 0, c = translationIds.length; i < c; i++) { + promises.push(translate(translationIds[i])); + } + // wait for all (including storing to results) + return $q.all(promises).then(function () { + // return the results + return results; + }); + }; + return translateAll(translationId); + } + + var deferred = $q.defer(); + + // trim off any whitespace + if (translationId) { + translationId = trim.apply(translationId); + } + + var promiseToWaitFor = (function () { + var promise = $preferredLanguage ? + langPromises[$preferredLanguage] : + langPromises[uses]; + + fallbackIndex = 0; + + if ($storageFactory && !promise) { + // looks like there's no pending promise for $preferredLanguage or + // $uses. Maybe there's one pending for a language that comes from + // storage. + var langKey = Storage.get($storageKey); + promise = langPromises[langKey]; + + if ($fallbackLanguage && $fallbackLanguage.length) { + var index = indexOf($fallbackLanguage, langKey); + // maybe the language from storage is also defined as fallback language + // we increase the fallback language index to not search in that language + // as fallback, since it's probably the first used language + // in that case the index starts after the first element + fallbackIndex = (index === 0) ? 1 : 0; + + // but we can make sure to ALWAYS fallback to preferred language at least + if (indexOf($fallbackLanguage, $preferredLanguage) < 0) { + $fallbackLanguage.push($preferredLanguage); + } + } + } + return promise; + }()); + + if (!promiseToWaitFor) { + // no promise to wait for? okay. Then there's no loader registered + // nor is a one pending for language that comes from storage. + // We can just translate. + determineTranslation(translationId, interpolateParams, interpolationId, defaultTranslationText, uses).then(deferred.resolve, deferred.reject); + } else { + var promiseResolved = function () { + // $uses may have changed while waiting + if (!forceLanguage) { + uses = $uses; + } + determineTranslation(translationId, interpolateParams, interpolationId, defaultTranslationText, uses).then(deferred.resolve, deferred.reject); + }; + promiseResolved.displayName = 'promiseResolved'; + + promiseToWaitFor['finally'](promiseResolved) + .catch(angular.noop); // we don't care about errors here, already handled + } + return deferred.promise; + }; + + /** + * @name applyNotFoundIndicators + * @private + * + * @description + * Applies not fount indicators to given translation id, if needed. + * This function gets only executed, if a translation id doesn't exist, + * which is why a translation id is expected as argument. + * + * @param {string} translationId Translation id. + * @returns {string} Same as given translation id but applied with not found + * indicators. + */ + var applyNotFoundIndicators = function (translationId) { + // applying notFoundIndicators + if ($notFoundIndicatorLeft) { + translationId = [$notFoundIndicatorLeft, translationId].join(' '); + } + if ($notFoundIndicatorRight) { + translationId = [translationId, $notFoundIndicatorRight].join(' '); + } + return translationId; + }; + + /** + * @name useLanguage + * @private + * + * @description + * Makes actual use of a language by setting a given language key as used + * language and informs registered interpolators to also use the given + * key as locale. + * + * @param {string} key Locale key. + */ + var useLanguage = function (key) { + $uses = key; + + // make sure to store new language key before triggering success event + if ($storageFactory) { + Storage.put($translate.storageKey(), $uses); + } + + $rootScope.$emit('$translateChangeSuccess', {language : key}); + + // inform default interpolator + defaultInterpolator.setLocale($uses); + + var eachInterpolator = function (interpolator, id) { + interpolatorHashMap[id].setLocale($uses); + }; + eachInterpolator.displayName = 'eachInterpolatorLocaleSetter'; + + // inform all others too! + angular.forEach(interpolatorHashMap, eachInterpolator); + $rootScope.$emit('$translateChangeEnd', {language : key}); + }; + + /** + * @name loadAsync + * @private + * + * @description + * Kicks off registered async loader using `$injector` and applies existing + * loader options. When resolved, it updates translation tables accordingly + * or rejects with given language key. + * + * @param {string} key Language key. + * @return {Promise} A promise. + */ + var loadAsync = function (key) { + if (!key) { + throw 'No language key specified for loading.'; + } + + var deferred = $q.defer(); + + $rootScope.$emit('$translateLoadingStart', {language : key}); + pendingLoader = true; + + var cache = loaderCache; + if (typeof(cache) === 'string') { + // getting on-demand instance of loader + cache = $injector.get(cache); + } + + var loaderOptions = angular.extend({}, $loaderOptions, { + key : key, + $http : angular.extend({}, { + cache : cache + }, $loaderOptions.$http) + }); + + var onLoaderSuccess = function (data) { + var translationTable = {}; + $rootScope.$emit('$translateLoadingSuccess', {language : key}); + + if (angular.isArray(data)) { + angular.forEach(data, function (table) { + angular.extend(translationTable, flatObject(table)); + }); + } else { + angular.extend(translationTable, flatObject(data)); + } + pendingLoader = false; + deferred.resolve({ + key : key, + table : translationTable + }); + $rootScope.$emit('$translateLoadingEnd', {language : key}); + }; + onLoaderSuccess.displayName = 'onLoaderSuccess'; + + var onLoaderError = function (key) { + $rootScope.$emit('$translateLoadingError', {language : key}); + deferred.reject(key); + $rootScope.$emit('$translateLoadingEnd', {language : key}); + }; + onLoaderError.displayName = 'onLoaderError'; + + $injector.get($loaderFactory)(loaderOptions) + .then(onLoaderSuccess, onLoaderError); + + return deferred.promise; + }; + + if ($storageFactory) { + Storage = $injector.get($storageFactory); + + if (!Storage.get || !Storage.put) { + throw new Error('Couldn\'t use storage \'' + $storageFactory + '\', missing get() or put() method!'); + } + } + + // if we have additional interpolations that were added via + // $translateProvider.addInterpolation(), we have to map'em + if ($interpolatorFactories.length) { + var eachInterpolationFactory = function (interpolatorFactory) { + var interpolator = $injector.get(interpolatorFactory); + // setting initial locale for each interpolation service + interpolator.setLocale($preferredLanguage || $uses); + // make'em recognizable through id + interpolatorHashMap[interpolator.getInterpolationIdentifier()] = interpolator; + }; + eachInterpolationFactory.displayName = 'interpolationFactoryAdder'; + + angular.forEach($interpolatorFactories, eachInterpolationFactory); + } + + /** + * @name getTranslationTable + * @private + * + * @description + * Returns a promise that resolves to the translation table + * or is rejected if an error occurred. + * + * @param langKey + * @returns {Q.promise} + */ + var getTranslationTable = function (langKey) { + var deferred = $q.defer(); + if (Object.prototype.hasOwnProperty.call($translationTable, langKey)) { + deferred.resolve($translationTable[langKey]); + } else if (langPromises[langKey]) { + var onResolve = function (data) { + translations(data.key, data.table); + deferred.resolve(data.table); + }; + onResolve.displayName = 'translationTableResolver'; + langPromises[langKey].then(onResolve, deferred.reject); + } else { + deferred.reject(); + } + return deferred.promise; + }; + + /** + * @name getFallbackTranslation + * @private + * + * @description + * Returns a promise that will resolve to the translation + * or be rejected if no translation was found for the language. + * This function is currently only used for fallback language translation. + * + * @param langKey The language to translate to. + * @param translationId + * @param interpolateParams + * @param Interpolator + * @param sanitizeStrategy + * @returns {Q.promise} + */ + var getFallbackTranslation = function (langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy) { + var deferred = $q.defer(); + + var onResolve = function (translationTable) { + if (Object.prototype.hasOwnProperty.call(translationTable, translationId) && translationTable[translationId] !== null) { + Interpolator.setLocale(langKey); + var translation = translationTable[translationId]; + if (translation.substr(0, 2) === '@:') { + getFallbackTranslation(langKey, translation.substr(2), interpolateParams, Interpolator, sanitizeStrategy) + .then(deferred.resolve, deferred.reject); + } else { + var interpolatedValue = Interpolator.interpolate(translationTable[translationId], interpolateParams, 'service', sanitizeStrategy, translationId); + interpolatedValue = applyPostProcessing(translationId, translationTable[translationId], interpolatedValue, interpolateParams, langKey); + + deferred.resolve(interpolatedValue); + + } + Interpolator.setLocale($uses); + } else { + deferred.reject(); + } + }; + onResolve.displayName = 'fallbackTranslationResolver'; + + getTranslationTable(langKey).then(onResolve, deferred.reject); + + return deferred.promise; + }; + + /** + * @name getFallbackTranslationInstant + * @private + * + * @description + * Returns a translation + * This function is currently only used for fallback language translation. + * + * @param langKey The language to translate to. + * @param translationId + * @param interpolateParams + * @param Interpolator + * @param sanitizeStrategy sanitize strategy override + * + * @returns {string} translation + */ + var getFallbackTranslationInstant = function (langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy) { + var result, translationTable = $translationTable[langKey]; + + if (translationTable && Object.prototype.hasOwnProperty.call(translationTable, translationId) && translationTable[translationId] !== null) { + Interpolator.setLocale(langKey); + result = Interpolator.interpolate(translationTable[translationId], interpolateParams, 'filter', sanitizeStrategy, translationId); + result = applyPostProcessing(translationId, translationTable[translationId], result, interpolateParams, langKey, sanitizeStrategy); + // workaround for TrustedValueHolderType + if (!angular.isString(result) && angular.isFunction(result.$$unwrapTrustedValue)) { + var result2 = result.$$unwrapTrustedValue(); + if (result2.substr(0, 2) === '@:') { + return getFallbackTranslationInstant(langKey, result2.substr(2), interpolateParams, Interpolator, sanitizeStrategy); + } + } else if (result.substr(0, 2) === '@:') { + return getFallbackTranslationInstant(langKey, result.substr(2), interpolateParams, Interpolator, sanitizeStrategy); + } + Interpolator.setLocale($uses); + } + + return result; + }; + + + /** + * @name translateByHandler + * @private + * + * Translate by missing translation handler. + * + * @param translationId + * @param interpolateParams + * @param defaultTranslationText + * @param sanitizeStrategy sanitize strategy override + * + * @returns translation created by $missingTranslationHandler or translationId is $missingTranslationHandler is + * absent + */ + var translateByHandler = function (translationId, interpolateParams, defaultTranslationText, sanitizeStrategy) { + // If we have a handler factory - we might also call it here to determine if it provides + // a default text for a translationid that can't be found anywhere in our tables + if ($missingTranslationHandlerFactory) { + return $injector.get($missingTranslationHandlerFactory)(translationId, $uses, interpolateParams, defaultTranslationText, sanitizeStrategy); + } else { + return translationId; + } + }; + + /** + * @name resolveForFallbackLanguage + * @private + * + * Recursive helper function for fallbackTranslation that will sequentially look + * for a translation in the fallbackLanguages starting with fallbackLanguageIndex. + * + * @param fallbackLanguageIndex + * @param translationId + * @param interpolateParams + * @param Interpolator + * @param defaultTranslationText + * @param sanitizeStrategy + * @returns {Q.promise} Promise that will resolve to the translation. + */ + var resolveForFallbackLanguage = function (fallbackLanguageIndex, translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy) { + var deferred = $q.defer(); + + if (fallbackLanguageIndex < $fallbackLanguage.length) { + var langKey = $fallbackLanguage[fallbackLanguageIndex]; + getFallbackTranslation(langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy).then( + function (data) { + deferred.resolve(data); + }, + function () { + // Look in the next fallback language for a translation. + // It delays the resolving by passing another promise to resolve. + return resolveForFallbackLanguage(fallbackLanguageIndex + 1, translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy).then(deferred.resolve, deferred.reject); + } + ); + } else { + // No translation found in any fallback language + // if a default translation text is set in the directive, then return this as a result + if (defaultTranslationText) { + deferred.resolve(defaultTranslationText); + } else { + var missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, defaultTranslationText); + + // if no default translation is set and an error handler is defined, send it to the handler + // and then return the result if it isn't undefined + if ($missingTranslationHandlerFactory && missingTranslationHandlerTranslation) { + deferred.resolve(missingTranslationHandlerTranslation); + } else { + deferred.reject(applyNotFoundIndicators(translationId)); + } + } + } + return deferred.promise; + }; + + /** + * @name resolveForFallbackLanguageInstant + * @private + * + * Recursive helper function for fallbackTranslation that will sequentially look + * for a translation in the fallbackLanguages starting with fallbackLanguageIndex. + * + * @param fallbackLanguageIndex + * @param translationId + * @param interpolateParams + * @param Interpolator + * @param sanitizeStrategy + * @returns {string} translation + */ + var resolveForFallbackLanguageInstant = function (fallbackLanguageIndex, translationId, interpolateParams, Interpolator, sanitizeStrategy) { + var result; + + if (fallbackLanguageIndex < $fallbackLanguage.length) { + var langKey = $fallbackLanguage[fallbackLanguageIndex]; + result = getFallbackTranslationInstant(langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy); + if (!result && result !== '') { + result = resolveForFallbackLanguageInstant(fallbackLanguageIndex + 1, translationId, interpolateParams, Interpolator); + } + } + return result; + }; + + /** + * Translates with the usage of the fallback languages. + * + * @param translationId + * @param interpolateParams + * @param Interpolator + * @param defaultTranslationText + * @param sanitizeStrategy + * @returns {Q.promise} Promise, that resolves to the translation. + */ + var fallbackTranslation = function (translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy) { + // Start with the fallbackLanguage with index 0 + return resolveForFallbackLanguage((startFallbackIteration > 0 ? startFallbackIteration : fallbackIndex), translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy); + }; + + /** + * Translates with the usage of the fallback languages. + * + * @param translationId + * @param interpolateParams + * @param Interpolator + * @param sanitizeStrategy + * @returns {String} translation + */ + var fallbackTranslationInstant = function (translationId, interpolateParams, Interpolator, sanitizeStrategy) { + // Start with the fallbackLanguage with index 0 + return resolveForFallbackLanguageInstant((startFallbackIteration > 0 ? startFallbackIteration : fallbackIndex), translationId, interpolateParams, Interpolator, sanitizeStrategy); + }; + + var determineTranslation = function (translationId, interpolateParams, interpolationId, defaultTranslationText, uses, sanitizeStrategy) { + + var deferred = $q.defer(); + + var table = uses ? $translationTable[uses] : $translationTable, + Interpolator = (interpolationId) ? interpolatorHashMap[interpolationId] : defaultInterpolator; + + // if the translation id exists, we can just interpolate it + if (table && Object.prototype.hasOwnProperty.call(table, translationId) && table[translationId] !== null) { + var translation = table[translationId]; + + // If using link, rerun $translate with linked translationId and return it + if (translation.substr(0, 2) === '@:') { + + $translate(translation.substr(2), interpolateParams, interpolationId, defaultTranslationText, uses) + .then(deferred.resolve, deferred.reject); + } else { + // + var resolvedTranslation = Interpolator.interpolate(translation, interpolateParams, 'service', sanitizeStrategy, translationId); + resolvedTranslation = applyPostProcessing(translationId, translation, resolvedTranslation, interpolateParams, uses); + deferred.resolve(resolvedTranslation); + } + } else { + var missingTranslationHandlerTranslation; + // for logging purposes only (as in $translateMissingTranslationHandlerLog), value is not returned to promise + if ($missingTranslationHandlerFactory && !pendingLoader) { + missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, defaultTranslationText); + } + + // since we couldn't translate the inital requested translation id, + // we try it now with one or more fallback languages, if fallback language(s) is + // configured. + if (uses && $fallbackLanguage && $fallbackLanguage.length) { + fallbackTranslation(translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy) + .then(function (translation) { + deferred.resolve(translation); + }, function (_translationId) { + deferred.reject(applyNotFoundIndicators(_translationId)); + }); + } else if ($missingTranslationHandlerFactory && !pendingLoader && missingTranslationHandlerTranslation) { + // looks like the requested translation id doesn't exists. + // Now, if there is a registered handler for missing translations and no + // asyncLoader is pending, we execute the handler + if (defaultTranslationText) { + deferred.resolve(defaultTranslationText); + } else { + deferred.resolve(missingTranslationHandlerTranslation); + } + } else { + if (defaultTranslationText) { + deferred.resolve(defaultTranslationText); + } else { + deferred.reject(applyNotFoundIndicators(translationId)); + } + } + } + return deferred.promise; + }; + + var determineTranslationInstant = function (translationId, interpolateParams, interpolationId, uses, sanitizeStrategy) { + + var result, table = uses ? $translationTable[uses] : $translationTable, + Interpolator = defaultInterpolator; + + // if the interpolation id exists use custom interpolator + if (interpolatorHashMap && Object.prototype.hasOwnProperty.call(interpolatorHashMap, interpolationId)) { + Interpolator = interpolatorHashMap[interpolationId]; + } + + // if the translation id exists, we can just interpolate it + if (table && Object.prototype.hasOwnProperty.call(table, translationId) && table[translationId] !== null) { + var translation = table[translationId]; + + // If using link, rerun $translate with linked translationId and return it + if (translation.substr(0, 2) === '@:') { + result = determineTranslationInstant(translation.substr(2), interpolateParams, interpolationId, uses, sanitizeStrategy); + } else { + result = Interpolator.interpolate(translation, interpolateParams, 'filter', sanitizeStrategy, translationId); + result = applyPostProcessing(translationId, translation, result, interpolateParams, uses, sanitizeStrategy); + } + } else { + var missingTranslationHandlerTranslation; + // for logging purposes only (as in $translateMissingTranslationHandlerLog), value is not returned to promise + if ($missingTranslationHandlerFactory && !pendingLoader) { + missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, sanitizeStrategy); + } + + // since we couldn't translate the inital requested translation id, + // we try it now with one or more fallback languages, if fallback language(s) is + // configured. + if (uses && $fallbackLanguage && $fallbackLanguage.length) { + fallbackIndex = 0; + result = fallbackTranslationInstant(translationId, interpolateParams, Interpolator, sanitizeStrategy); + } else if ($missingTranslationHandlerFactory && !pendingLoader && missingTranslationHandlerTranslation) { + // looks like the requested translation id doesn't exists. + // Now, if there is a registered handler for missing translations and no + // asyncLoader is pending, we execute the handler + result = missingTranslationHandlerTranslation; + } else { + result = applyNotFoundIndicators(translationId); + } + } + + return result; + }; + + var clearNextLangAndPromise = function (key) { + if ($nextLang === key) { + $nextLang = undefined; + } + langPromises[key] = undefined; + }; + + var applyPostProcessing = function (translationId, translation, resolvedTranslation, interpolateParams, uses, sanitizeStrategy) { + var fn = postProcessFn; + + if (fn) { + + if (typeof(fn) === 'string') { + // getting on-demand instance + fn = $injector.get(fn); + } + if (fn) { + return fn(translationId, translation, resolvedTranslation, interpolateParams, uses, sanitizeStrategy); + } + } + + return resolvedTranslation; + }; + + var loadTranslationsIfMissing = function (key) { + if (!$translationTable[key] && $loaderFactory && !langPromises[key]) { + langPromises[key] = loadAsync(key).then(function (translation) { + translations(translation.key, translation.table); + return translation; + }); + } + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#preferredLanguage + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the language key for the preferred language. + * + * @param {string} langKey language String or Array to be used as preferredLanguage (changing at runtime) + * + * @return {string} preferred language key + */ + $translate.preferredLanguage = function (langKey) { + if (langKey) { + setupPreferredLanguage(langKey); + } + return $preferredLanguage; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#cloakClassName + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the configured class name for `translate-cloak` directive. + * + * @return {string} cloakClassName + */ + $translate.cloakClassName = function () { + return $cloakClassName; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#nestedObjectDelimeter + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the configured delimiter for nested namespaces. + * + * @return {string} nestedObjectDelimeter + */ + $translate.nestedObjectDelimeter = function () { + return $nestedObjectDelimeter; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#fallbackLanguage + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the language key for the fallback languages or sets a new fallback stack. + * + * @param {string=} langKey language String or Array of fallback languages to be used (to change stack at runtime) + * + * @return {string||array} fallback language key + */ + $translate.fallbackLanguage = function (langKey) { + if (langKey !== undefined && langKey !== null) { + fallbackStack(langKey); + + // as we might have an async loader initiated and a new translation language might have been defined + // we need to add the promise to the stack also. So - iterate. + if ($loaderFactory) { + if ($fallbackLanguage && $fallbackLanguage.length) { + for (var i = 0, len = $fallbackLanguage.length; i < len; i++) { + if (!langPromises[$fallbackLanguage[i]]) { + langPromises[$fallbackLanguage[i]] = loadAsync($fallbackLanguage[i]); + } + } + } + } + $translate.use($translate.use()); + } + if ($fallbackWasString) { + return $fallbackLanguage[0]; + } else { + return $fallbackLanguage; + } + + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#useFallbackLanguage + * @methodOf pascalprecht.translate.$translate + * + * @description + * Sets the first key of the fallback language stack to be used for translation. + * Therefore all languages in the fallback array BEFORE this key will be skipped! + * + * @param {string=} langKey Contains the langKey the iteration shall start with. Set to false if you want to + * get back to the whole stack + */ + $translate.useFallbackLanguage = function (langKey) { + if (langKey !== undefined && langKey !== null) { + if (!langKey) { + startFallbackIteration = 0; + } else { + var langKeyPosition = indexOf($fallbackLanguage, langKey); + if (langKeyPosition > -1) { + startFallbackIteration = langKeyPosition; + } + } + + } + + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#proposedLanguage + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the language key of language that is currently loaded asynchronously. + * + * @return {string} language key + */ + $translate.proposedLanguage = function () { + return $nextLang; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#storage + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns registered storage. + * + * @return {object} Storage + */ + $translate.storage = function () { + return Storage; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#negotiateLocale + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns a language key based on available languages and language aliases. If a + * language key cannot be resolved, returns undefined. + * + * If no or a falsy key is given, returns undefined. + * + * @param {string} [key] Language key + * @return {string|undefined} Language key or undefined if no language key is found. + */ + $translate.negotiateLocale = negotiateLocale; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#use + * @methodOf pascalprecht.translate.$translate + * + * @description + * Tells angular-translate which language to use by given language key. This method is + * used to change language at runtime. It also takes care of storing the language + * key in a configured store to let your app remember the choosed language. + * + * When trying to 'use' a language which isn't available it tries to load it + * asynchronously with registered loaders. + * + * Returns promise object with loaded language file data or string of the currently used language. + * + * If no or a falsy key is given it returns the currently used language key. + * The returned string will be ```undefined``` if setting up $translate hasn't finished. + * @example + * $translate.use("en_US").then(function(data){ + * $scope.text = $translate("HELLO"); + * }); + * + * @param {string} [key] Language key + * @return {object|string} Promise with loaded language data or the language key if a falsy param was given. + */ + $translate.use = function (key) { + if (!key) { + return $uses; + } + + var deferred = $q.defer(); + deferred.promise.then(null, angular.noop); // AJS "Possibly unhandled rejection" + + $rootScope.$emit('$translateChangeStart', {language : key}); + + // Try to get the aliased language key + var aliasedKey = negotiateLocale(key); + // Ensure only registered language keys will be loaded + if ($availableLanguageKeys.length > 0 && !aliasedKey) { + return $q.reject(key); + } + + if (aliasedKey) { + key = aliasedKey; + } + + // if there isn't a translation table for the language we've requested, + // we load it asynchronously + $nextLang = key; + if (($forceAsyncReloadEnabled || !$translationTable[key]) && $loaderFactory && !langPromises[key]) { + langPromises[key] = loadAsync(key).then(function (translation) { + translations(translation.key, translation.table); + deferred.resolve(translation.key); + if ($nextLang === key) { + useLanguage(translation.key); + } + return translation; + }, function (key) { + $rootScope.$emit('$translateChangeError', {language : key}); + deferred.reject(key); + $rootScope.$emit('$translateChangeEnd', {language : key}); + return $q.reject(key); + }); + langPromises[key]['finally'](function () { + clearNextLangAndPromise(key); + }).catch(angular.noop); // we don't care about errors (clearing) + } else if (langPromises[key]) { + // we are already loading this asynchronously + // resolve our new deferred when the old langPromise is resolved + langPromises[key].then(function (translation) { + if ($nextLang === translation.key) { + useLanguage(translation.key); + } + deferred.resolve(translation.key); + return translation; + }, function (key) { + // find first available fallback language if that request has failed + if (!$uses && $fallbackLanguage && $fallbackLanguage.length > 0 && $fallbackLanguage[0] !== key) { + return $translate.use($fallbackLanguage[0]).then(deferred.resolve, deferred.reject); + } else { + return deferred.reject(key); + } + }); + } else { + deferred.resolve(key); + useLanguage(key); + } + + return deferred.promise; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#resolveClientLocale + * @methodOf pascalprecht.translate.$translate + * + * @description + * This returns the current browser/client's language key. The result is processed with the configured uniform tag resolver. + * + * @returns {string} the current client/browser language key + */ + $translate.resolveClientLocale = function () { + return getLocale(); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#storageKey + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the key for the storage. + * + * @return {string} storage key + */ + $translate.storageKey = function () { + return storageKey(); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#isPostCompilingEnabled + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns whether post compiling is enabled or not + * + * @return {bool} storage key + */ + $translate.isPostCompilingEnabled = function () { + return $postCompilingEnabled; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#isForceAsyncReloadEnabled + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns whether force async reload is enabled or not + * + * @return {boolean} forceAsyncReload value + */ + $translate.isForceAsyncReloadEnabled = function () { + return $forceAsyncReloadEnabled; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#isKeepContent + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns whether keepContent or not + * + * @return {boolean} keepContent value + */ + $translate.isKeepContent = function () { + return $keepContent; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#refresh + * @methodOf pascalprecht.translate.$translate + * + * @description + * Refreshes a translation table pointed by the given langKey. If langKey is not specified, + * the module will drop all existent translation tables and load new version of those which + * are currently in use. + * + * Refresh means that the module will drop target translation table and try to load it again. + * + * In case there are no loaders registered the refresh() method will throw an Error. + * + * If the module is able to refresh translation tables refresh() method will broadcast + * $translateRefreshStart and $translateRefreshEnd events. + * + * @example + * // this will drop all currently existent translation tables and reload those which are + * // currently in use + * $translate.refresh(); + * // this will refresh a translation table for the en_US language + * $translate.refresh('en_US'); + * + * @param {string} langKey A language key of the table, which has to be refreshed + * + * @return {promise} Promise, which will be resolved in case a translation tables refreshing + * process is finished successfully, and reject if not. + */ + $translate.refresh = function (langKey) { + if (!$loaderFactory) { + throw new Error('Couldn\'t refresh translation table, no loader registered!'); + } + + $rootScope.$emit('$translateRefreshStart', {language : langKey}); + + var deferred = $q.defer(), updatedLanguages = {}; + + //private helper + function loadNewData(languageKey) { + var promise = loadAsync(languageKey); + //update the load promise cache for this language + langPromises[languageKey] = promise; + //register a data handler for the promise + promise.then(function (data) { + //clear the cache for this language + $translationTable[languageKey] = {}; + //add the new data for this language + translations(languageKey, data.table); + //track that we updated this language + updatedLanguages[languageKey] = true; + }, + //handle rejection to appease the $q validation + angular.noop); + return promise; + } + + //set up post-processing + deferred.promise.then( + function () { + for (var key in $translationTable) { + if ($translationTable.hasOwnProperty(key)) { + //delete cache entries that were not updated + if (!(key in updatedLanguages)) { + delete $translationTable[key]; + } + } + } + if ($uses) { + useLanguage($uses); + } + }, + //handle rejection to appease the $q validation + angular.noop + ).finally( + function () { + $rootScope.$emit('$translateRefreshEnd', {language : langKey}); + } + ); + + if (!langKey) { + // if there's no language key specified we refresh ALL THE THINGS! + var languagesToReload = $fallbackLanguage && $fallbackLanguage.slice() || []; + if ($uses && languagesToReload.indexOf($uses) === -1) { + languagesToReload.push($uses); + } + $q.all(languagesToReload.map(loadNewData)).then(deferred.resolve, deferred.reject); + + } else if ($translationTable[langKey]) { + //just refresh the specified language cache + loadNewData(langKey).then(deferred.resolve, deferred.reject); + + } else { + deferred.reject(); + } + + return deferred.promise; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#instant + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns a translation instantly from the internal state of loaded translation. All rules + * regarding the current language, the preferred language of even fallback languages will be + * used except any promise handling. If a language was not found, an asynchronous loading + * will be invoked in the background. + * + * @param {string|array} translationId A token which represents a translation id + * This can be optionally an array of translation ids which + * results that the function's promise returns an object where + * each key is the translation id and the value the translation. + * @param {object} interpolateParams Params + * @param {string} interpolationId The id of the interpolation to use + * @param {string} forceLanguage A language to be used instead of the current language + * @param {string} sanitizeStrategy force sanitize strategy for this call instead of using the configured one + * + * @return {string|object} translation + */ + $translate.instant = function (translationId, interpolateParams, interpolationId, forceLanguage, sanitizeStrategy) { + + // we don't want to re-negotiate $uses + var uses = (forceLanguage && forceLanguage !== $uses) ? // we don't want to re-negotiate $uses + (negotiateLocale(forceLanguage) || forceLanguage) : $uses; + + // Detect undefined and null values to shorten the execution and prevent exceptions + if (translationId === null || angular.isUndefined(translationId)) { + return translationId; + } + + // Check forceLanguage is present + if (forceLanguage) { + loadTranslationsIfMissing(forceLanguage); + } + + // Duck detection: If the first argument is an array, a bunch of translations was requested. + // The result is an object. + if (angular.isArray(translationId)) { + var results = {}; + for (var i = 0, c = translationId.length; i < c; i++) { + results[translationId[i]] = $translate.instant(translationId[i], interpolateParams, interpolationId, forceLanguage, sanitizeStrategy); + } + return results; + } + + // We discarded unacceptable values. So we just need to verify if translationId is empty String + if (angular.isString(translationId) && translationId.length < 1) { + return translationId; + } + + // trim off any whitespace + if (translationId) { + translationId = trim.apply(translationId); + } + + var result, possibleLangKeys = []; + if ($preferredLanguage) { + possibleLangKeys.push($preferredLanguage); + } + if (uses) { + possibleLangKeys.push(uses); + } + if ($fallbackLanguage && $fallbackLanguage.length) { + possibleLangKeys = possibleLangKeys.concat($fallbackLanguage); + } + for (var j = 0, d = possibleLangKeys.length; j < d; j++) { + var possibleLangKey = possibleLangKeys[j]; + if ($translationTable[possibleLangKey]) { + if (typeof $translationTable[possibleLangKey][translationId] !== 'undefined') { + result = determineTranslationInstant(translationId, interpolateParams, interpolationId, uses, sanitizeStrategy); + } + } + if (typeof result !== 'undefined') { + break; + } + } + + if (!result && result !== '') { + if ($notFoundIndicatorLeft || $notFoundIndicatorRight) { + result = applyNotFoundIndicators(translationId); + } else { + // Return translation of default interpolator if not found anything. + result = defaultInterpolator.interpolate(translationId, interpolateParams, 'filter', sanitizeStrategy); + + // looks like the requested translation id doesn't exists. + // Now, if there is a registered handler for missing translations and no + // asyncLoader is pending, we execute the handler + var missingTranslationHandlerTranslation; + if ($missingTranslationHandlerFactory && !pendingLoader) { + missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, sanitizeStrategy); + } + + if ($missingTranslationHandlerFactory && !pendingLoader && missingTranslationHandlerTranslation) { + result = missingTranslationHandlerTranslation; + } + } + } + + return result; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#versionInfo + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the current version information for the angular-translate library + * + * @return {string} angular-translate version + */ + $translate.versionInfo = function () { + return version; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#loaderCache + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the defined loaderCache. + * + * @return {boolean|string|object} current value of loaderCache + */ + $translate.loaderCache = function () { + return loaderCache; + }; + + // internal purpose only + $translate.directivePriority = function () { + return directivePriority; + }; + + // internal purpose only + $translate.statefulFilter = function () { + return statefulFilter; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#isReady + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns whether the service is "ready" to translate (i.e. loading 1st language). + * + * See also {@link pascalprecht.translate.$translate#methods_onReady onReady()}. + * + * @return {boolean} current value of ready + */ + $translate.isReady = function () { + return $isReady; + }; + + var $onReadyDeferred = $q.defer(); + $onReadyDeferred.promise.then(function () { + $isReady = true; + }); + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#onReady + * @methodOf pascalprecht.translate.$translate + * + * @description + * Calls the function provided or resolved the returned promise after the service is "ready" to translate (i.e. loading 1st language). + * + * See also {@link pascalprecht.translate.$translate#methods_isReady isReady()}. + * + * @param {Function=} fn Function to invoke when service is ready + * @return {object} Promise resolved when service is ready + */ + $translate.onReady = function (fn) { + var deferred = $q.defer(); + if (angular.isFunction(fn)) { + deferred.promise.then(fn); + } + if ($isReady) { + deferred.resolve(); + } else { + $onReadyDeferred.promise.then(deferred.resolve); + } + return deferred.promise; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#getAvailableLanguageKeys + * @methodOf pascalprecht.translate.$translate + * + * @description + * This function simply returns the registered language keys being defined before in the config phase + * With this, an application can use the array to provide a language selection dropdown or similar + * without any additional effort + * + * @returns {object} returns the list of possibly registered language keys and mapping or null if not defined + */ + $translate.getAvailableLanguageKeys = function () { + if ($availableLanguageKeys.length > 0) { + return $availableLanguageKeys; + } + return null; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#getTranslationTable + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns translation table by the given language key. + * + * Unless a language is provided it returns a translation table of the current one. + * Note: If translation dictionary is currently downloading or in progress + * it will return null. + * + * @param {string} langKey A token which represents a translation id + * + * @return {object} a copy of angular-translate $translationTable + */ + $translate.getTranslationTable = function (langKey) { + langKey = langKey || $translate.use(); + if (langKey && $translationTable[langKey]) { + return angular.copy($translationTable[langKey]); + } + return null; + }; + + // Whenever $translateReady is being fired, this will ensure the state of $isReady + var globalOnReadyListener = $rootScope.$on('$translateReady', function () { + $onReadyDeferred.resolve(); + globalOnReadyListener(); // one time only + globalOnReadyListener = null; + }); + var globalOnChangeListener = $rootScope.$on('$translateChangeEnd', function () { + $onReadyDeferred.resolve(); + globalOnChangeListener(); // one time only + globalOnChangeListener = null; + }); + + if ($loaderFactory) { + + // If at least one async loader is defined and there are no + // (default) translations available we should try to load them. + if (angular.equals($translationTable, {})) { + if ($translate.use()) { + $translate.use($translate.use()); + } + } + + // Also, if there are any fallback language registered, we start + // loading them asynchronously as soon as we can. + if ($fallbackLanguage && $fallbackLanguage.length) { + var processAsyncResult = function (translation) { + translations(translation.key, translation.table); + $rootScope.$emit('$translateChangeEnd', {language : translation.key}); + return translation; + }; + for (var i = 0, len = $fallbackLanguage.length; i < len; i++) { + var fallbackLanguageId = $fallbackLanguage[i]; + if ($forceAsyncReloadEnabled || !$translationTable[fallbackLanguageId]) { + langPromises[fallbackLanguageId] = loadAsync(fallbackLanguageId).then(processAsyncResult); + } + } + } + } else { + $rootScope.$emit('$translateReady', {language : $translate.use()}); + } + + return $translate; + }]; +} + +$translate.displayName = 'displayName'; + +/** + * @ngdoc object + * @name pascalprecht.translate.$translateDefaultInterpolation + * @requires $interpolate + * + * @description + * Uses angular's `$interpolate` services to interpolate strings against some values. + * + * Be aware to configure a proper sanitization strategy. + * + * See also: + * * {@link pascalprecht.translate.$translateSanitization} + * + * @return {object} $translateDefaultInterpolation Interpolator service + */ +angular.module('pascalprecht.translate').factory('$translateDefaultInterpolation', $translateDefaultInterpolation); + +function $translateDefaultInterpolation ($interpolate, $translateSanitization) { + + 'use strict'; + + var $translateInterpolator = {}, + $locale, + $identifier = 'default'; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateDefaultInterpolation#setLocale + * @methodOf pascalprecht.translate.$translateDefaultInterpolation + * + * @description + * Sets current locale (this is currently not use in this interpolation). + * + * @param {string} locale Language key or locale. + */ + $translateInterpolator.setLocale = function (locale) { + $locale = locale; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateDefaultInterpolation#getInterpolationIdentifier + * @methodOf pascalprecht.translate.$translateDefaultInterpolation + * + * @description + * Returns an identifier for this interpolation service. + * + * @returns {string} $identifier + */ + $translateInterpolator.getInterpolationIdentifier = function () { + return $identifier; + }; + + /** + * @deprecated will be removed in 3.0 + * @see {@link pascalprecht.translate.$translateSanitization} + */ + $translateInterpolator.useSanitizeValueStrategy = function (value) { + $translateSanitization.useStrategy(value); + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateDefaultInterpolation#interpolate + * @methodOf pascalprecht.translate.$translateDefaultInterpolation + * + * @description + * Interpolates given value agains given interpolate params using angulars + * `$interpolate` service. + * + * Since AngularJS 1.5, `value` must not be a string but can be anything input. + * + * @param {string} value translation + * @param {object} interpolationParams interpolation params + * @param {string} context current context (filter, directive, service) + * @param {string} sanitizeStrategy sanitize strategy + * @param {string} translationId current translationId + * + * @returns {string} interpolated string + */ + $translateInterpolator.interpolate = function (value, interpolationParams, context, sanitizeStrategy, translationId) { // jshint ignore:line + interpolationParams = interpolationParams || {}; + interpolationParams = $translateSanitization.sanitize(interpolationParams, 'params', sanitizeStrategy, context); + + var interpolatedText; + if (angular.isNumber(value)) { + // numbers are safe + interpolatedText = '' + value; + } else if (angular.isString(value)) { + // strings must be interpolated (that's the job here) + interpolatedText = $interpolate(value)(interpolationParams); + interpolatedText = $translateSanitization.sanitize(interpolatedText, 'text', sanitizeStrategy, context); + } else { + // neither a number or a string, cant interpolate => empty string + interpolatedText = ''; + } + + return interpolatedText; + }; + + return $translateInterpolator; +} + +$translateDefaultInterpolation.displayName = '$translateDefaultInterpolation'; + +angular.module('pascalprecht.translate').constant('$STORAGE_KEY', 'NG_TRANSLATE_LANG_KEY'); + +angular.module('pascalprecht.translate') +/** + * @ngdoc directive + * @name pascalprecht.translate.directive:translate + * @requires $interpolate, + * @requires $compile, + * @requires $parse, + * @requires $rootScope + * @restrict AE + * + * @description + * Translates given translation id either through attribute or DOM content. + * Internally it uses $translate service to translate the translation id. It possible to + * pass an optional `translate-values` object literal as string into translation id. + * + * @param {string=} translate Translation id which could be either string or interpolated string. + * @param {string=} translate-values Values to pass into translation id. Can be passed as object literal string or interpolated object. + * @param {string=} translate-attr-ATTR translate Translation id and put it into ATTR attribute. + * @param {string=} translate-default will be used unless translation was successful + * @param {boolean=} translate-compile (default true if present) defines locally activation of {@link pascalprecht.translate.$translateProvider#methods_usePostCompiling} + * @param {boolean=} translate-keep-content (default true if present) defines that in case a KEY could not be translated, that the existing content is left in the innerHTML} + * + * @example + + +
    + +
    
    +        
    TRANSLATION_ID
    +
    
    +        
    
    +        
    {{translationId}}
    +
    
    +        
    WITH_VALUES
    +
    
    +        
    WITH_VALUES
    +
    
    +        
    
    +
    +      
    +
    + + angular.module('ngView', ['pascalprecht.translate']) + + .config(function ($translateProvider) { + + $translateProvider.translations('en',{ + 'TRANSLATION_ID': 'Hello there!', + 'WITH_VALUES': 'The following value is dynamic: {{value}}', + 'WITH_CAMEL_CASE_KEY': 'The interpolation key is camel cased: {{camelCaseKey}}' + }).preferredLanguage('en'); + + }); + + angular.module('ngView').controller('TranslateCtrl', function ($scope) { + $scope.translationId = 'TRANSLATION_ID'; + + $scope.values = { + value: 78 + }; + }); + + + it('should translate', function () { + inject(function ($rootScope, $compile) { + $rootScope.translationId = 'TRANSLATION_ID'; + + element = $compile('

    ')($rootScope); + $rootScope.$digest(); + expect(element.text()).toBe('Hello there!'); + + element = $compile('

    ')($rootScope); + $rootScope.$digest(); + expect(element.text()).toBe('Hello there!'); + + element = $compile('

    TRANSLATION_ID

    ')($rootScope); + $rootScope.$digest(); + expect(element.text()).toBe('Hello there!'); + + element = $compile('

    {{translationId}}

    ')($rootScope); + $rootScope.$digest(); + expect(element.text()).toBe('Hello there!'); + + element = $compile('

    ')($rootScope); + $rootScope.$digest(); + expect(element.attr('title')).toBe('Hello there!'); + + element = $compile('

    ')($rootScope); + $rootScope.$digest(); + expect(element.text()).toBe('The interpolation key is camel cased: Hello'); + }); + }); +
    +
    + */ +.directive('translate', translateDirective); +function translateDirective($translate, $interpolate, $compile, $parse, $rootScope) { + + 'use strict'; + + /** + * @name trim + * @private + * + * @description + * trim polyfill + * + * @returns {string} The string stripped of whitespace from both ends + */ + var trim = function() { + return this.toString().replace(/^\s+|\s+$/g, ''); + }; + + return { + restrict: 'AE', + scope: true, + priority: $translate.directivePriority(), + compile: function (tElement, tAttr) { + + var translateValuesExist = (tAttr.translateValues) ? + tAttr.translateValues : undefined; + + var translateInterpolation = (tAttr.translateInterpolation) ? + tAttr.translateInterpolation : undefined; + + var translateValueExist = tElement[0].outerHTML.match(/translate-value-+/i); + + var interpolateRegExp = '^(.*)(' + $interpolate.startSymbol() + '.*' + $interpolate.endSymbol() + ')(.*)', + watcherRegExp = '^(.*)' + $interpolate.startSymbol() + '(.*)' + $interpolate.endSymbol() + '(.*)'; + + return function linkFn(scope, iElement, iAttr) { + + scope.interpolateParams = {}; + scope.preText = ''; + scope.postText = ''; + scope.translateNamespace = getTranslateNamespace(scope); + var translationIds = {}; + + var initInterpolationParams = function (interpolateParams, iAttr, tAttr) { + // initial setup + if (iAttr.translateValues) { + angular.extend(interpolateParams, $parse(iAttr.translateValues)(scope.$parent)); + } + // initially fetch all attributes if existing and fill the params + if (translateValueExist) { + for (var attr in tAttr) { + if (Object.prototype.hasOwnProperty.call(iAttr, attr) && attr.substr(0, 14) === 'translateValue' && attr !== 'translateValues') { + var attributeName = angular.lowercase(attr.substr(14, 1)) + attr.substr(15); + interpolateParams[attributeName] = tAttr[attr]; + } + } + } + }; + + // Ensures any change of the attribute "translate" containing the id will + // be re-stored to the scope's "translationId". + // If the attribute has no content, the element's text value (white spaces trimmed off) will be used. + var observeElementTranslation = function (translationId) { + + // Remove any old watcher + if (angular.isFunction(observeElementTranslation._unwatchOld)) { + observeElementTranslation._unwatchOld(); + observeElementTranslation._unwatchOld = undefined; + } + + if (angular.equals(translationId , '') || !angular.isDefined(translationId)) { + var iElementText = trim.apply(iElement.text()); + + // Resolve translation id by inner html if required + var interpolateMatches = iElementText.match(interpolateRegExp); + // Interpolate translation id if required + if (angular.isArray(interpolateMatches)) { + scope.preText = interpolateMatches[1]; + scope.postText = interpolateMatches[3]; + translationIds.translate = $interpolate(interpolateMatches[2])(scope.$parent); + var watcherMatches = iElementText.match(watcherRegExp); + if (angular.isArray(watcherMatches) && watcherMatches[2] && watcherMatches[2].length) { + observeElementTranslation._unwatchOld = scope.$watch(watcherMatches[2], function (newValue) { + translationIds.translate = newValue; + updateTranslations(); + }); + } + } else { + // do not assigne the translation id if it is empty. + translationIds.translate = !iElementText ? undefined : iElementText; + } + } else { + translationIds.translate = translationId; + } + updateTranslations(); + }; + + var observeAttributeTranslation = function (translateAttr) { + iAttr.$observe(translateAttr, function (translationId) { + translationIds[translateAttr] = translationId; + updateTranslations(); + }); + }; + + // initial setup with values + initInterpolationParams(scope.interpolateParams, iAttr, tAttr); + + var firstAttributeChangedEvent = true; + iAttr.$observe('translate', function (translationId) { + if (typeof translationId === 'undefined') { + // case of element "xyz" + observeElementTranslation(''); + } else { + // case of regular attribute + if (translationId !== '' || !firstAttributeChangedEvent) { + translationIds.translate = translationId; + updateTranslations(); + } + } + firstAttributeChangedEvent = false; + }); + + for (var translateAttr in iAttr) { + if (iAttr.hasOwnProperty(translateAttr) && translateAttr.substr(0, 13) === 'translateAttr' && translateAttr.length > 13) { + observeAttributeTranslation(translateAttr); + } + } + + iAttr.$observe('translateDefault', function (value) { + scope.defaultText = value; + updateTranslations(); + }); + + if (translateValuesExist) { + iAttr.$observe('translateValues', function (interpolateParams) { + if (interpolateParams) { + scope.$parent.$watch(function () { + angular.extend(scope.interpolateParams, $parse(interpolateParams)(scope.$parent)); + }); + } + }); + } + + if (translateValueExist) { + var observeValueAttribute = function (attrName) { + iAttr.$observe(attrName, function (value) { + var attributeName = angular.lowercase(attrName.substr(14, 1)) + attrName.substr(15); + scope.interpolateParams[attributeName] = value; + }); + }; + for (var attr in iAttr) { + if (Object.prototype.hasOwnProperty.call(iAttr, attr) && attr.substr(0, 14) === 'translateValue' && attr !== 'translateValues') { + observeValueAttribute(attr); + } + } + } + + // Master update function + var updateTranslations = function () { + for (var key in translationIds) { + if (translationIds.hasOwnProperty(key) && translationIds[key] !== undefined) { + updateTranslation(key, translationIds[key], scope, scope.interpolateParams, scope.defaultText, scope.translateNamespace); + } + } + }; + + // Put translation processing function outside loop + var updateTranslation = function(translateAttr, translationId, scope, interpolateParams, defaultTranslationText, translateNamespace) { + if (translationId) { + // if translation id starts with '.' and translateNamespace given, prepend namespace + if (translateNamespace && translationId.charAt(0) === '.') { + translationId = translateNamespace + translationId; + } + + $translate(translationId, interpolateParams, translateInterpolation, defaultTranslationText, scope.translateLanguage) + .then(function (translation) { + applyTranslation(translation, scope, true, translateAttr); + }, function (translationId) { + applyTranslation(translationId, scope, false, translateAttr); + }); + } else { + // as an empty string cannot be translated, we can solve this using successful=false + applyTranslation(translationId, scope, false, translateAttr); + } + }; + + var applyTranslation = function (value, scope, successful, translateAttr) { + if (!successful) { + if (typeof scope.defaultText !== 'undefined') { + value = scope.defaultText; + } + } + if (translateAttr === 'translate') { + // default translate into innerHTML + if (successful || (!successful && !$translate.isKeepContent() && typeof iAttr.translateKeepContent === 'undefined')) { + iElement.empty().append(scope.preText + value + scope.postText); + } + var globallyEnabled = $translate.isPostCompilingEnabled(); + var locallyDefined = typeof tAttr.translateCompile !== 'undefined'; + var locallyEnabled = locallyDefined && tAttr.translateCompile !== 'false'; + if ((globallyEnabled && !locallyDefined) || locallyEnabled) { + $compile(iElement.contents())(scope); + } + } else { + // translate attribute + var attributeName = iAttr.$attr[translateAttr]; + if (attributeName.substr(0, 5) === 'data-') { + // ensure html5 data prefix is stripped + attributeName = attributeName.substr(5); + } + attributeName = attributeName.substr(15); + iElement.attr(attributeName, value); + } + }; + + if (translateValuesExist || translateValueExist || iAttr.translateDefault) { + scope.$watch('interpolateParams', updateTranslations, true); + } + + // Replaced watcher on translateLanguage with event listener + scope.$on('translateLanguageChanged', updateTranslations); + + // Ensures the text will be refreshed after the current language was changed + // w/ $translate.use(...) + var unbind = $rootScope.$on('$translateChangeSuccess', updateTranslations); + + // ensure translation will be looked up at least one + if (iElement.text().length) { + if (iAttr.translate) { + observeElementTranslation(iAttr.translate); + } else { + observeElementTranslation(''); + } + } else if (iAttr.translate) { + // ensure attribute will be not skipped + observeElementTranslation(iAttr.translate); + } + updateTranslations(); + scope.$on('$destroy', unbind); + }; + } + }; +} + +/** + * Returns the scope's namespace. + * @private + * @param scope + * @returns {string} + */ +function getTranslateNamespace(scope) { + 'use strict'; + if (scope.translateNamespace) { + return scope.translateNamespace; + } + if (scope.$parent) { + return getTranslateNamespace(scope.$parent); + } +} + +translateDirective.displayName = 'translateDirective'; + +angular.module('pascalprecht.translate') +/** + * @ngdoc directive + * @name pascalprecht.translate.directive:translate-attr + * @restrict A + * + * @description + * Translates attributes like translate-attr-ATTR, but with an object like ng-class. + * Internally it uses `translate` service to translate translation id. It possible to + * pass an optional `translate-values` object literal as string into translation id. + * + * @param {string=} translate-attr Object literal mapping attributes to translation ids. + * @param {string=} translate-values Values to pass into the translation ids. Can be passed as object literal string. + * + * @example + + +
    + + + +
    +
    + + angular.module('ngView', ['pascalprecht.translate']) + + .config(function ($translateProvider) { + + $translateProvider.translations('en',{ + 'TRANSLATION_ID': 'Hello there!', + 'WITH_VALUES': 'The following value is dynamic: {{value}}', + }).preferredLanguage('en'); + + }); + + angular.module('ngView').controller('TranslateCtrl', function ($scope) { + $scope.translationId = 'TRANSLATION_ID'; + + $scope.values = { + value: 78 + }; + }); + + + it('should translate', function () { + inject(function ($rootScope, $compile) { + $rootScope.translationId = 'TRANSLATION_ID'; + + element = $compile('')($rootScope); + $rootScope.$digest(); + expect(element.attr('placeholder)).toBe('Hello there!'); + expect(element.attr('title)).toBe('The following value is dynamic: 5'); + }); + }); + +
    + */ +.directive('translateAttr', translateAttrDirective); +function translateAttrDirective($translate, $rootScope) { + + 'use strict'; + + return { + restrict: 'A', + priority: $translate.directivePriority(), + link: function linkFn(scope, element, attr) { + + var translateAttr, + translateValues, + previousAttributes = {}; + + // Main update translations function + var updateTranslations = function () { + angular.forEach(translateAttr, function (translationId, attributeName) { + if (!translationId) { + return; + } + previousAttributes[attributeName] = true; + + // if translation id starts with '.' and translateNamespace given, prepend namespace + if (scope.translateNamespace && translationId.charAt(0) === '.') { + translationId = scope.translateNamespace + translationId; + } + $translate(translationId, translateValues, attr.translateInterpolation, undefined, scope.translateLanguage) + .then(function (translation) { + element.attr(attributeName, translation); + }, function (translationId) { + element.attr(attributeName, translationId); + }); + }); + + // Removing unused attributes that were previously used + angular.forEach(previousAttributes, function (flag, attributeName) { + if (!translateAttr[attributeName]) { + element.removeAttr(attributeName); + delete previousAttributes[attributeName]; + } + }); + }; + + // Watch for attribute changes + watchAttribute( + scope, + attr.translateAttr, + function (newValue) { translateAttr = newValue; }, + updateTranslations + ); + // Watch for value changes + watchAttribute( + scope, + attr.translateValues, + function (newValue) { translateValues = newValue; }, + updateTranslations + ); + + if (attr.translateValues) { + scope.$watch(attr.translateValues, updateTranslations, true); + } + + // Replaced watcher on translateLanguage with event listener + scope.$on('translateLanguageChanged', updateTranslations); + + // Ensures the text will be refreshed after the current language was changed + // w/ $translate.use(...) + var unbind = $rootScope.$on('$translateChangeSuccess', updateTranslations); + + updateTranslations(); + scope.$on('$destroy', unbind); + } + }; +} + +function watchAttribute(scope, attribute, valueCallback, changeCallback) { + 'use strict'; + if (!attribute) { + return; + } + if (attribute.substr(0, 2) === '::') { + attribute = attribute.substr(2); + } else { + scope.$watch(attribute, function(newValue) { + valueCallback(newValue); + changeCallback(); + }, true); + } + valueCallback(scope.$eval(attribute)); +} + +translateAttrDirective.displayName = 'translateAttrDirective'; + +angular.module('pascalprecht.translate') +/** + * @ngdoc directive + * @name pascalprecht.translate.directive:translateCloak + * @requires $translate + * @restrict A + * + * $description + * Adds a `translate-cloak` class name to the given element where this directive + * is applied initially and removes it, once a loader has finished loading. + * + * This directive can be used to prevent initial flickering when loading translation + * data asynchronously. + * + * The class name is defined in + * {@link pascalprecht.translate.$translateProvider#cloakClassName $translate.cloakClassName()}. + * + * @param {string=} translate-cloak If a translationId is provided, it will be used for showing + * or hiding the cloak. Basically it relies on the translation + * resolve. + */ +.directive('translateCloak', translateCloakDirective); + +function translateCloakDirective($translate, $rootScope) { + + 'use strict'; + + return { + compile : function (tElement) { + var applyCloak = function (element) { + element.addClass($translate.cloakClassName()); + }, + removeCloak = function (element) { + element.removeClass($translate.cloakClassName()); + }; + applyCloak(tElement); + + return function linkFn(scope, iElement, iAttr) { + //Create bound functions that incorporate the active DOM element. + var iRemoveCloak = removeCloak.bind(this, iElement), iApplyCloak = applyCloak.bind(this, iElement); + if (iAttr.translateCloak && iAttr.translateCloak.length) { + // Register a watcher for the defined translation allowing a fine tuned cloak + iAttr.$observe('translateCloak', function (translationId) { + $translate(translationId).then(iRemoveCloak, iApplyCloak); + }); + $rootScope.$on('$translateChangeSuccess', function () { + $translate(iAttr.translateCloak).then(iRemoveCloak, iApplyCloak); + }); + } else { + $translate.onReady(iRemoveCloak); + } + }; + } + }; +} + +translateCloakDirective.displayName = 'translateCloakDirective'; + +angular.module('pascalprecht.translate') +/** + * @ngdoc directive + * @name pascalprecht.translate.directive:translateNamespace + * @restrict A + * + * @description + * Translates given translation id either through attribute or DOM content. + * Internally it uses `translate` filter to translate translation id. It possible to + * pass an optional `translate-values` object literal as string into translation id. + * + * @param {string=} translate namespace name which could be either string or interpolated string. + * + * @example + + +
    + +
    +

    .HEADERS.TITLE

    +

    .HEADERS.WELCOME

    +
    + +
    +

    .TITLE

    +

    .WELCOME

    +
    + +
    +
    + + angular.module('ngView', ['pascalprecht.translate']) + + .config(function ($translateProvider) { + + $translateProvider.translations('en',{ + 'TRANSLATION_ID': 'Hello there!', + 'CONTENT': { + 'HEADERS': { + TITLE: 'Title' + } + }, + 'CONTENT.HEADERS.WELCOME': 'Welcome' + }).preferredLanguage('en'); + + }); + + +
    + */ +.directive('translateNamespace', translateNamespaceDirective); + +function translateNamespaceDirective() { + + 'use strict'; + + return { + restrict: 'A', + scope: true, + compile: function () { + return { + pre: function (scope, iElement, iAttrs) { + scope.translateNamespace = getTranslateNamespace(scope); + + if (scope.translateNamespace && iAttrs.translateNamespace.charAt(0) === '.') { + scope.translateNamespace += iAttrs.translateNamespace; + } else { + scope.translateNamespace = iAttrs.translateNamespace; + } + } + }; + } + }; +} + +/** + * Returns the scope's namespace. + * @private + * @param scope + * @returns {string} + */ +function getTranslateNamespace(scope) { + 'use strict'; + if (scope.translateNamespace) { + return scope.translateNamespace; + } + if (scope.$parent) { + return getTranslateNamespace(scope.$parent); + } +} + +translateNamespaceDirective.displayName = 'translateNamespaceDirective'; + +angular.module('pascalprecht.translate') +/** + * @ngdoc directive + * @name pascalprecht.translate.directive:translateLanguage + * @restrict A + * + * @description + * Forces the language to the directives in the underlying scope. + * + * @param {string=} translate language that will be negotiated. + * + * @example + + +
    + +
    +

    HELLO

    +
    + +
    +

    HELLO

    +
    + +
    +
    + + angular.module('ngView', ['pascalprecht.translate']) + + .config(function ($translateProvider) { + + $translateProvider + .translations('en',{ + 'HELLO': 'Hello world!' + }) + .translations('de',{ + 'HELLO': 'Hallo Welt!' + }) + .preferredLanguage('en'); + + }); + + +
    + */ +.directive('translateLanguage', translateLanguageDirective); + +function translateLanguageDirective() { + + 'use strict'; + + return { + restrict: 'A', + scope: true, + compile: function () { + return function linkFn(scope, iElement, iAttrs) { + + iAttrs.$observe('translateLanguage', function (newTranslateLanguage) { + scope.translateLanguage = newTranslateLanguage; + }); + + scope.$watch('translateLanguage', function(){ + scope.$broadcast('translateLanguageChanged'); + }); + }; + } + }; +} + +translateLanguageDirective.displayName = 'translateLanguageDirective'; + +angular.module('pascalprecht.translate') +/** + * @ngdoc filter + * @name pascalprecht.translate.filter:translate + * @requires $parse + * @requires pascalprecht.translate.$translate + * @function + * + * @description + * Uses `$translate` service to translate contents. Accepts interpolate parameters + * to pass dynamized values though translation. + * + * @param {string} translationId A translation id to be translated. + * @param {*=} interpolateParams Optional object literal (as hash or string) to pass values into translation. + * + * @returns {string} Translated text. + * + * @example + + +
    + +
    {{ 'TRANSLATION_ID' | translate }}
    +
    {{ translationId | translate }}
    +
    {{ 'WITH_VALUES' | translate:'{value: 5}' }}
    +
    {{ 'WITH_VALUES' | translate:values }}
    + +
    +
    + + angular.module('ngView', ['pascalprecht.translate']) + + .config(function ($translateProvider) { + + $translateProvider.translations('en', { + 'TRANSLATION_ID': 'Hello there!', + 'WITH_VALUES': 'The following value is dynamic: {{value}}' + }); + $translateProvider.preferredLanguage('en'); + + }); + + angular.module('ngView').controller('TranslateCtrl', function ($scope) { + $scope.translationId = 'TRANSLATION_ID'; + + $scope.values = { + value: 78 + }; + }); + +
    + */ +.filter('translate', translateFilterFactory); + +function translateFilterFactory($parse, $translate) { + + 'use strict'; + + var translateFilter = function (translationId, interpolateParams, interpolation, forceLanguage) { + if (!angular.isObject(interpolateParams)) { + var ctx = this || { + '__SCOPE_IS_NOT_AVAILABLE': 'More info at https://github.com/angular/angular.js/commit/8863b9d04c722b278fa93c5d66ad1e578ad6eb1f' + }; + interpolateParams = $parse(interpolateParams)(ctx); + } + + return $translate.instant(translationId, interpolateParams, interpolation, forceLanguage); + }; + + if ($translate.statefulFilter()) { + translateFilter.$stateful = true; + } + + return translateFilter; +} + +translateFilterFactory.displayName = 'translateFilterFactory'; + +angular.module('pascalprecht.translate') + +/** + * @ngdoc object + * @name pascalprecht.translate.$translationCache + * @requires $cacheFactory + * + * @description + * The first time a translation table is used, it is loaded in the translation cache for quick retrieval. You + * can load translation tables directly into the cache by consuming the + * `$translationCache` service directly. + * + * @return {object} $cacheFactory object. + */ + .factory('$translationCache', $translationCache); + +function $translationCache($cacheFactory) { + + 'use strict'; + + return $cacheFactory('translations'); +} + +$translationCache.displayName = '$translationCache'; +return 'pascalprecht.translate'; + +})); diff --git a/snow-flowable/src/main/resources/static/libs/angular-translate_2.15.1/angular-translate.min.js b/snow-flowable/src/main/resources/static/libs/angular-translate_2.15.1/angular-translate.min.js new file mode 100644 index 0000000..8549ef9 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular-translate_2.15.1/angular-translate.min.js @@ -0,0 +1,6 @@ +/*! + * angular-translate - v2.15.1 - 2017-03-04 + * + * Copyright (c) 2017 The angular-translate team, Pascal Precht; Licensed MIT + */ +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return b()}):"object"==typeof exports?module.exports=b():b()}(this,function(){function a(a){"use strict";var b=a.storageKey(),c=a.storage(),d=function(){var d=a.preferredLanguage();angular.isString(d)?a.use(d):c.put(b,a.use())};d.displayName="fallbackFromIncorrectStorageValue",c?c.get(b)?a.use(c.get(b)).catch(d):d():angular.isString(a.preferredLanguage())&&a.use(a.preferredLanguage())}function b(){"use strict";var a,b,c,d=null,e=!1,f=!1;c={sanitize:function(a,b){return"text"===b&&(a=h(a)),a},escape:function(a,b){return"text"===b&&(a=g(a)),a},sanitizeParameters:function(a,b){return"params"===b&&(a=j(a,h)),a},escapeParameters:function(a,b){return"params"===b&&(a=j(a,g)),a},sce:function(a,b,c){return"text"===b?a=i(a):"params"===b&&"filter"!==c&&(a=j(a,g)),a},sceParameters:function(a,b){return"params"===b&&(a=j(a,i)),a}},c.escaped=c.escapeParameters,this.addStrategy=function(a,b){return c[a]=b,this},this.removeStrategy=function(a){return delete c[a],this},this.useStrategy=function(a){return e=!0,d=a,this},this.$get=["$injector","$log",function(g,h){var i={},j=function(a,b,d,e){return angular.forEach(e,function(e){if(angular.isFunction(e))a=e(a,b,d);else if(angular.isFunction(c[e]))a=c[e](a,b,d);else{if(!angular.isString(c[e]))throw new Error("pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: '"+e+"'");if(!i[c[e]])try{i[c[e]]=g.get(c[e])}catch(a){throw i[c[e]]=function(){},new Error("pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: '"+e+"'")}a=i[c[e]](a,b,d)}}),a},k=function(){e||f||(h.warn("pascalprecht.translate.$translateSanitization: No sanitization strategy has been configured. This can have serious security implications. See http://angular-translate.github.io/docs/#/guide/19_security for details."),f=!0)};return g.has("$sanitize")&&(a=g.get("$sanitize")),g.has("$sce")&&(b=g.get("$sce")),{useStrategy:function(a){return function(b){a.useStrategy(b)}}(this),sanitize:function(a,b,c,e){if(d||k(),c||null===c||(c=d),!c)return a;e||(e="service");var f=angular.isArray(c)?c:[c];return j(a,b,e,f)}}}];var g=function(a){var b=angular.element("
    ");return b.text(a),b.html()},h=function(b){if(!a)throw new Error("pascalprecht.translate.$translateSanitization: Error cannot find $sanitize service. Either include the ngSanitize module (https://docs.angularjs.org/api/ngSanitize) or use a sanitization strategy which does not depend on $sanitize, such as 'escape'.");return a(b)},i=function(a){if(!b)throw new Error("pascalprecht.translate.$translateSanitization: Error cannot find $sce service.");return b.trustAsHtml(a)},j=function(a,b,c){if(angular.isDate(a))return a;if(angular.isObject(a)){var d=angular.isArray(a)?[]:{};if(c){if(c.indexOf(a)>-1)throw new Error("pascalprecht.translate.$translateSanitization: Error cannot interpolate parameter due recursive object")}else c=[];return c.push(a),angular.forEach(a,function(a,e){angular.isFunction(a)||(d[e]=j(a,b,c))}),c.splice(-1,1),d}return angular.isNumber(a)?a:angular.isUndefined(a)||null===a?a:b(a)}}function c(a,b,c,d){"use strict";var e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u={},v=[],w=a,x=[],y="translate-cloak",z=!1,A=!1,B=".",C=!1,D=!1,E=0,F=!0,G="default",H={default:function(a){return(a||"").split("-").join("_")},java:function(a){var b=(a||"").split("-").join("_"),c=b.split("_");return c.length>1?c[0].toLowerCase()+"_"+c[1].toUpperCase():b},bcp47:function(a){var b=(a||"").split("_").join("-"),c=b.split("-");return c.length>1?c[0].toLowerCase()+"-"+c[1].toUpperCase():b},"iso639-1":function(a){var b=(a||"").split("_").join("-"),c=b.split("-");return c[0].toLowerCase()}},I="2.15.1",J=function(){if(angular.isFunction(d.getLocale))return d.getLocale();var a,c,e=b.$get().navigator,f=["language","browserLanguage","systemLanguage","userLanguage"];if(angular.isArray(e.languages))for(a=0;a-1)return a;if(f){var g;for(var h in f)if(f.hasOwnProperty(h)){var i=!1,j=Object.prototype.hasOwnProperty.call(f,h)&&angular.lowercase(h)===angular.lowercase(a);if("*"===h.slice(-1)&&(i=h.slice(0,-1)===a.slice(0,h.length-1)),(j||i)&&(g=f[h],L(b,angular.lowercase(g))>-1))return g}}var k=a.split("_");return k.length>1&&L(b,angular.lowercase(k[0]))>-1?k[0]:void 0}},O=function(a,b){if(!a&&!b)return u;if(a&&!b){if(angular.isString(a))return u[a]}else angular.isObject(u[a])||(u[a]={}),angular.extend(u[a],P(b));return this};this.translations=O,this.cloakClassName=function(a){return a?(y=a,this):y},this.nestedObjectDelimeter=function(a){return a?(B=a,this):B};var P=function(a,b,c,d){var e,f,g,h;b||(b=[]),c||(c={});for(e in a)Object.prototype.hasOwnProperty.call(a,e)&&(h=a[e],angular.isObject(h)?P(h,b.concat(e),c,e):(f=b.length?""+b.join(B)+B+e:e,b.length&&e===d&&(g=""+b.join(B),c[g]="@:"+f),c[f]=h));return c};P.displayName="flatObject",this.addInterpolation=function(a){return x.push(a),this},this.useMessageFormatInterpolation=function(){return this.useInterpolation("$translateMessageFormatInterpolation")},this.useInterpolation=function(a){return n=a,this},this.useSanitizeValueStrategy=function(a){return c.useStrategy(a),this},this.preferredLanguage=function(a){return a?(Q(a),this):e};var Q=function(a){return a&&(e=a),e};this.translationNotFoundIndicator=function(a){return this.translationNotFoundIndicatorLeft(a),this.translationNotFoundIndicatorRight(a),this},this.translationNotFoundIndicatorLeft=function(a){return a?(q=a,this):q},this.translationNotFoundIndicatorRight=function(a){return a?(r=a,this):r},this.fallbackLanguage=function(a){return R(a),this};var R=function(a){return a?(angular.isString(a)?(h=!0,g=[a]):angular.isArray(a)&&(h=!1,g=a),angular.isString(e)&&L(g,e)<0&&g.push(e),this):h?g[0]:g};this.use=function(a){if(a){if(!u[a]&&!o)throw new Error("$translateProvider couldn't find translationTable for langKey: '"+a+"'");return i=a,this}return i},this.resolveClientLocale=function(){return K()};var S=function(a){return a?(w=a,this):l?l+w:w};this.storageKey=S,this.useUrlLoader=function(a,b){return this.useLoader("$translateUrlLoader",angular.extend({url:a},b))},this.useStaticFilesLoader=function(a){return this.useLoader("$translateStaticFilesLoader",a)},this.useLoader=function(a,b){return o=a,p=b||{},this},this.useLocalStorage=function(){return this.useStorage("$translateLocalStorage")},this.useCookieStorage=function(){return this.useStorage("$translateCookieStorage")},this.useStorage=function(a){return k=a,this},this.storagePrefix=function(a){return a?(l=a,this):a},this.useMissingTranslationHandlerLog=function(){return this.useMissingTranslationHandler("$translateMissingTranslationHandlerLog")},this.useMissingTranslationHandler=function(a){return m=a,this},this.usePostCompiling=function(a){return z=!!a,this},this.forceAsyncReload=function(a){return A=!!a,this},this.uniformLanguageTag=function(a){return a?angular.isString(a)&&(a={standard:a}):a={},G=a.standard,this},this.determinePreferredLanguage=function(a){var b=a&&angular.isFunction(a)?a():K();return e=v.length?N(b)||b:b,this},this.registerAvailableLanguageKeys=function(a,b){return a?(v=a,b&&(f=b),this):v},this.useLoaderCache=function(a){return a===!1?s=void 0:a===!0?s=!0:"undefined"==typeof a?s="$translationCache":a&&(s=a),this},this.directivePriority=function(a){return void 0===a?E:(E=a,this)},this.statefulFilter=function(a){return void 0===a?F:(F=a,this)},this.postProcess=function(a){return t=a?a:void 0,this},this.keepContent=function(a){return D=!!a,this},this.$get=["$log","$injector","$rootScope","$q",function(a,b,c,d){var f,l,G,H=b.get(n||"$translateDefaultInterpolation"),J=!1,T={},U={},V=function(a,b,c,h,j){!i&&e&&(i=e);var m=j&&j!==i?N(j)||j:i;if(j&&ka(j),angular.isArray(a)){var n=function(a){for(var e={},f=[],g=function(a){var f=d.defer(),g=function(b){e[a]=b,f.resolve([a,b])};return V(a,b,c,h,j).then(g,g),f.promise},i=0,k=a.length;i0?G:l,a,b,c,d,e)},fa=function(a,b,c,d){return da(G>0?G:l,a,b,c,d)},ga=function(a,b,c,e,f,h){var i=d.defer(),j=f?u[f]:u,k=c?T[c]:H;if(j&&Object.prototype.hasOwnProperty.call(j,a)&&null!==j[a]){var l=j[a];if("@:"===l.substr(0,2))V(l.substr(2),b,c,e,f).then(i.resolve,i.reject);else{var n=k.interpolate(l,b,"service",h,a);n=ja(a,l,n,b,f),i.resolve(n)}}else{var o;m&&!J&&(o=ba(a,b,e)),f&&g&&g.length?ea(a,b,k,e,h).then(function(a){i.resolve(a)},function(a){i.reject(W(a))}):m&&!J&&o?e?i.resolve(e):i.resolve(o):e?i.resolve(e):i.reject(W(a))}return i.promise},ha=function(a,b,c,d,e){var f,h=d?u[d]:u,i=H;if(T&&Object.prototype.hasOwnProperty.call(T,c)&&(i=T[c]),h&&Object.prototype.hasOwnProperty.call(h,a)&&null!==h[a]){var j=h[a];"@:"===j.substr(0,2)?f=ha(j.substr(2),b,c,d,e):(f=i.interpolate(j,b,"filter",e,a),f=ja(a,j,f,b,d,e))}else{var k;m&&!J&&(k=ba(a,b,e)),d&&g&&g.length?(l=0,f=fa(a,b,i,e)):f=m&&!J&&k?k:W(a)}return f},ia=function(a){j===a&&(j=void 0),U[a]=void 0},ja=function(a,c,d,e,f,g){var h=t;return h&&("string"==typeof h&&(h=b.get(h)),h)?h(a,c,d,e,f,g):d},ka=function(a){u[a]||!o||U[a]||(U[a]=Y(a).then(function(a){return O(a.key,a.table),a}))};V.preferredLanguage=function(a){return a&&Q(a),e},V.cloakClassName=function(){return y},V.nestedObjectDelimeter=function(){return B},V.fallbackLanguage=function(a){if(void 0!==a&&null!==a){if(R(a),o&&g&&g.length)for(var b=0,c=g.length;b-1&&(G=b)}else G=0},V.proposedLanguage=function(){return j},V.storage=function(){return f},V.negotiateLocale=N,V.use=function(a){if(!a)return i;var b=d.defer();b.promise.then(null,angular.noop),c.$emit("$translateChangeStart",{language:a});var e=N(a);return v.length>0&&!e?d.reject(a):(e&&(a=e),j=a,!A&&u[a]||!o||U[a]?U[a]?U[a].then(function(a){return j===a.key&&X(a.key),b.resolve(a.key),a},function(a){return!i&&g&&g.length>0&&g[0]!==a?V.use(g[0]).then(b.resolve,b.reject):b.reject(a)}):(b.resolve(a),X(a)):(U[a]=Y(a).then(function(c){return O(c.key,c.table),b.resolve(c.key),j===a&&X(c.key),c},function(a){return c.$emit("$translateChangeError",{language:a}),b.reject(a),c.$emit("$translateChangeEnd",{language:a}),d.reject(a)}),U[a].finally(function(){ia(a)}).catch(angular.noop)),b.promise)},V.resolveClientLocale=function(){return K()},V.storageKey=function(){return S()},V.isPostCompilingEnabled=function(){return z},V.isForceAsyncReloadEnabled=function(){return A},V.isKeepContent=function(){return D},V.refresh=function(a){function b(a){var b=Y(a);return U[a]=b,b.then(function(b){u[a]={},O(a,b.table),f[a]=!0},angular.noop),b}if(!o)throw new Error("Couldn't refresh translation table, no loader registered!");c.$emit("$translateRefreshStart",{language:a});var e=d.defer(),f={};if(e.promise.then(function(){for(var a in u)u.hasOwnProperty(a)&&(a in f||delete u[a]);i&&X(i)},angular.noop).finally(function(){c.$emit("$translateRefreshEnd",{language:a})}),a)u[a]?b(a).then(e.resolve,e.reject):e.reject();else{var h=g&&g.slice()||[];i&&h.indexOf(i)===-1&&h.push(i),d.all(h.map(b)).then(e.resolve,e.reject)}return e.promise},V.instant=function(a,b,c,d,f){var h=d&&d!==i?N(d)||d:i;if(null===a||angular.isUndefined(a))return a;if(d&&ka(d),angular.isArray(a)){for(var j={},k=0,l=a.length;k0?v:null},V.getTranslationTable=function(a){return a=a||V.use(),a&&u[a]?angular.copy(u[a]):null};var ma=c.$on("$translateReady",function(){la.resolve(),ma(),ma=null}),na=c.$on("$translateChangeEnd",function(){la.resolve(),na(),na=null});if(o){if(angular.equals(u,{})&&V.use()&&V.use(V.use()),g&&g.length)for(var oa=function(a){return O(a.key,a.table),c.$emit("$translateChangeEnd",{language:a.key}),a},pa=0,qa=g.length;pa13&&t(v);if(p.$observe("translateDefault",function(a){h.defaultText=a,y()}),j&&p.$observe("translateValues",function(a){a&&h.$parent.$watch(function(){angular.extend(h.interpolateParams,d(a)(h.$parent))})}),l){var w=function(a){p.$observe(a,function(b){var c=angular.lowercase(a.substr(14,1))+a.substr(15);h.interpolateParams[c]=b})};for(var x in p)Object.prototype.hasOwnProperty.call(p,x)&&"translateValue"===x.substr(0,14)&&"translateValues"!==x&&w(x)}var y=function(){for(var a in q)q.hasOwnProperty(a)&&void 0!==q[a]&&z(a,q[a],h,h.interpolateParams,h.defaultText,h.translateNamespace)},z=function(b,c,d,e,f,g){c?(g&&"."===c.charAt(0)&&(c=g+c),a(c,e,k,f,d.translateLanguage).then(function(a){A(a,d,!0,b)},function(a){A(a,d,!1,b)})):A(c,d,!1,b)},A=function(b,d,e,f){if(e||"undefined"!=typeof d.defaultText&&(b=d.defaultText),"translate"===f){(e||!e&&!a.isKeepContent()&&"undefined"==typeof p.translateKeepContent)&&o.empty().append(d.preText+b+d.postText);var g=a.isPostCompilingEnabled(),h="undefined"!=typeof i.translateCompile,j=h&&"false"!==i.translateCompile;(g&&!h||j)&&c(o.contents())(d)}else{var k=p.$attr[f];"data-"===k.substr(0,5)&&(k=k.substr(5)),k=k.substr(15),o.attr(k,b)}};(j||l||p.translateDefault)&&h.$watch("interpolateParams",y,!0),h.$on("translateLanguageChanged",y);var B=e.$on("$translateChangeSuccess",y);o.text().length?s(p.translate?p.translate:""):p.translate&&s(p.translate),y(),h.$on("$destroy",B)}}}}function f(a){"use strict";return a.translateNamespace?a.translateNamespace:a.$parent?f(a.$parent):void 0}function g(a,b){"use strict";return{restrict:"A",priority:a.directivePriority(),link:function(c,d,e){var f,g,i={},j=function(){angular.forEach(f,function(b,f){b&&(i[f]=!0,c.translateNamespace&&"."===b.charAt(0)&&(b=c.translateNamespace+b),a(b,g,e.translateInterpolation,void 0,c.translateLanguage).then(function(a){d.attr(f,a)},function(a){d.attr(f,a)}))}),angular.forEach(i,function(a,b){f[b]||(d.removeAttr(b),delete i[b])})};h(c,e.translateAttr,function(a){f=a},j),h(c,e.translateValues,function(a){g=a},j),e.translateValues&&c.$watch(e.translateValues,j,!0),c.$on("translateLanguageChanged",j);var k=b.$on("$translateChangeSuccess",j);j(),c.$on("$destroy",k)}}}function h(a,b,c,d){"use strict";b&&("::"===b.substr(0,2)?b=b.substr(2):a.$watch(b,function(a){c(a),d()},!0),c(a.$eval(b)))}function i(a,b){"use strict";return{compile:function(c){var d=function(b){b.addClass(a.cloakClassName())},e=function(b){b.removeClass(a.cloakClassName())};return d(c),function(c,f,g){var h=e.bind(this,f),i=d.bind(this,f);g.translateCloak&&g.translateCloak.length?(g.$observe("translateCloak",function(b){a(b).then(h,i)}),b.$on("$translateChangeSuccess",function(){a(g.translateCloak).then(h,i)})):a.onReady(h)}}}}function j(){"use strict";return{restrict:"A",scope:!0,compile:function(){return{pre:function(a,b,c){a.translateNamespace=f(a),a.translateNamespace&&"."===c.translateNamespace.charAt(0)?a.translateNamespace+=c.translateNamespace:a.translateNamespace=c.translateNamespace}}}}}function f(a){"use strict";return a.translateNamespace?a.translateNamespace:a.$parent?f(a.$parent):void 0}function k(){"use strict";return{restrict:"A",scope:!0,compile:function(){return function(a,b,c){c.$observe("translateLanguage",function(b){a.translateLanguage=b}),a.$watch("translateLanguage",function(){a.$broadcast("translateLanguageChanged")})}}}}function l(a,b){"use strict";var c=function(c,d,e,f){if(!angular.isObject(d)){var g=this||{__SCOPE_IS_NOT_AVAILABLE:"More info at https://github.com/angular/angular.js/commit/8863b9d04c722b278fa93c5d66ad1e578ad6eb1f"};d=a(d)(g)}return b.instant(c,d,e,f)};return b.statefulFilter()&&(c.$stateful=!0),c}function m(a){"use strict";return a("translations")}return a.$inject=["$translate"],c.$inject=["$STORAGE_KEY","$windowProvider","$translateSanitizationProvider","pascalprechtTranslateOverrider"],d.$inject=["$interpolate","$translateSanitization"],e.$inject=["$translate","$interpolate","$compile","$parse","$rootScope"],g.$inject=["$translate","$rootScope"],i.$inject=["$translate","$rootScope"],l.$inject=["$parse","$translate"],m.$inject=["$cacheFactory"],angular.module("pascalprecht.translate",["ng"]).run(a),a.displayName="runTranslate",angular.module("pascalprecht.translate").provider("$translateSanitization",b),angular.module("pascalprecht.translate").constant("pascalprechtTranslateOverrider",{}).provider("$translate",c),c.displayName="displayName",angular.module("pascalprecht.translate").factory("$translateDefaultInterpolation",d),d.displayName="$translateDefaultInterpolation",angular.module("pascalprecht.translate").constant("$STORAGE_KEY","NG_TRANSLATE_LANG_KEY"),angular.module("pascalprecht.translate").directive("translate",e),e.displayName="translateDirective",angular.module("pascalprecht.translate").directive("translateAttr",g),g.displayName="translateAttrDirective",angular.module("pascalprecht.translate").directive("translateCloak",i),i.displayName="translateCloakDirective",angular.module("pascalprecht.translate").directive("translateNamespace",j),j.displayName="translateNamespaceDirective",angular.module("pascalprecht.translate").directive("translateLanguage",k),k.displayName="translateLanguageDirective",angular.module("pascalprecht.translate").filter("translate",l),l.displayName="translateFilterFactory",angular.module("pascalprecht.translate").factory("$translationCache",m),m.displayName="$translationCache","pascalprecht.translate"}); \ No newline at end of file diff --git a/snow-flowable/src/main/resources/static/libs/angular_1.3.13/angular.js b/snow-flowable/src/main/resources/static/libs/angular_1.3.13/angular.js new file mode 100644 index 0000000..4f4f492 --- /dev/null +++ b/snow-flowable/src/main/resources/static/libs/angular_1.3.13/angular.js @@ -0,0 +1,26130 @@ +/** + * @license AngularJS v1.3.13 + * (c) 2010-2014 Google, Inc. http://angularjs.org + * License: MIT + */ +(function(window, document, undefined) {'use strict'; + +/** + * @description + * + * This object provides a utility for producing rich Error messages within + * Angular. It can be called as follows: + * + * var exampleMinErr = minErr('example'); + * throw exampleMinErr('one', 'This {0} is {1}', foo, bar); + * + * The above creates an instance of minErr in the example namespace. The + * resulting error will have a namespaced error code of example.one. The + * resulting error will replace {0} with the value of foo, and {1} with the + * value of bar. The object is not restricted in the number of arguments it can + * take. + * + * If fewer arguments are specified than necessary for interpolation, the extra + * interpolation markers will be preserved in the final string. + * + * Since data will be parsed statically during a build step, some restrictions + * are applied with respect to how minErr instances are created and called. + * Instances should have names of the form namespaceMinErr for a minErr created + * using minErr('namespace') . Error codes, namespaces and template strings + * should all be static strings, not variables or general expressions. + * + * @param {string} module The namespace to use for the new minErr instance. + * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning + * error from returned function, for cases when a particular type of error is useful. + * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance + */ + +function minErr(module, ErrorConstructor) { + ErrorConstructor = ErrorConstructor || Error; + return function() { + var code = arguments[0], + prefix = '[' + (module ? module + ':' : '') + code + '] ', + template = arguments[1], + templateArgs = arguments, + + message, i; + + message = prefix + template.replace(/\{\d+\}/g, function(match) { + var index = +match.slice(1, -1), arg; + + if (index + 2 < templateArgs.length) { + return toDebugString(templateArgs[index + 2]); + } + return match; + }); + + message = message + '\nhttp://errors.angularjs.org/1.3.13/' + + (module ? module + '/' : '') + code; + for (i = 2; i < arguments.length; i++) { + message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' + + encodeURIComponent(toDebugString(arguments[i])); + } + return new ErrorConstructor(message); + }; +} + +/* We need to tell jshint what variables are being exported */ +/* global angular: true, + msie: true, + jqLite: true, + jQuery: true, + slice: true, + splice: true, + push: true, + toString: true, + ngMinErr: true, + angularModule: true, + uid: true, + REGEX_STRING_REGEXP: true, + VALIDITY_STATE_PROPERTY: true, + + lowercase: true, + uppercase: true, + manualLowercase: true, + manualUppercase: true, + nodeName_: true, + isArrayLike: true, + forEach: true, + sortedKeys: true, + forEachSorted: true, + reverseParams: true, + nextUid: true, + setHashKey: true, + extend: true, + int: true, + inherit: true, + noop: true, + identity: true, + valueFn: true, + isUndefined: true, + isDefined: true, + isObject: true, + isString: true, + isNumber: true, + isDate: true, + isArray: true, + isFunction: true, + isRegExp: true, + isWindow: true, + isScope: true, + isFile: true, + isFormData: true, + isBlob: true, + isBoolean: true, + isPromiseLike: true, + trim: true, + escapeForRegexp: true, + isElement: true, + makeMap: true, + includes: true, + arrayRemove: true, + copy: true, + shallowCopy: true, + equals: true, + csp: true, + concat: true, + sliceArgs: true, + bind: true, + toJsonReplacer: true, + toJson: true, + fromJson: true, + startingTag: true, + tryDecodeURIComponent: true, + parseKeyValue: true, + toKeyValue: true, + encodeUriSegment: true, + encodeUriQuery: true, + angularInit: true, + bootstrap: true, + getTestability: true, + snake_case: true, + bindJQuery: true, + assertArg: true, + assertArgFn: true, + assertNotHasOwnProperty: true, + getter: true, + getBlockNodes: true, + hasOwnProperty: true, + createMap: true, + + NODE_TYPE_ELEMENT: true, + NODE_TYPE_TEXT: true, + NODE_TYPE_COMMENT: true, + NODE_TYPE_DOCUMENT: true, + NODE_TYPE_DOCUMENT_FRAGMENT: true, +*/ + +//////////////////////////////////// + +/** + * @ngdoc module + * @name ng + * @module ng + * @description + * + * # ng (core module) + * The ng module is loaded by default when an AngularJS application is started. The module itself + * contains the essential components for an AngularJS application to function. The table below + * lists a high level breakdown of each of the services/factories, filters, directives and testing + * components available within this core module. + * + *
    + */ + +var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/; + +// The name of a form control's ValidityState property. +// This is used so that it's possible for internal tests to create mock ValidityStates. +var VALIDITY_STATE_PROPERTY = 'validity'; + +/** + * @ngdoc function + * @name angular.lowercase + * @module ng + * @kind function + * + * @description Converts the specified string to lowercase. + * @param {string} string String to be converted to lowercase. + * @returns {string} Lowercased string. + */ +var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;}; +var hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * @ngdoc function + * @name angular.uppercase + * @module ng + * @kind function + * + * @description Converts the specified string to uppercase. + * @param {string} string String to be converted to uppercase. + * @returns {string} Uppercased string. + */ +var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;}; + + +var manualLowercase = function(s) { + /* jshint bitwise: false */ + return isString(s) + ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);}) + : s; +}; +var manualUppercase = function(s) { + /* jshint bitwise: false */ + return isString(s) + ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);}) + : s; +}; + + +// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish +// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods +// with correct but slower alternatives. +if ('i' !== 'I'.toLowerCase()) { + lowercase = manualLowercase; + uppercase = manualUppercase; +} + + +var + msie, // holds major version number for IE, or NaN if UA is not IE. + jqLite, // delay binding since jQuery could be loaded after us. + jQuery, // delay binding + slice = [].slice, + splice = [].splice, + push = [].push, + toString = Object.prototype.toString, + ngMinErr = minErr('ng'), + + /** @name angular */ + angular = window.angular || (window.angular = {}), + angularModule, + uid = 0; + +/** + * documentMode is an IE-only property + * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx + */ +msie = document.documentMode; + + +/** + * @private + * @param {*} obj + * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, + * String ...) + */ +function isArrayLike(obj) { + if (obj == null || isWindow(obj)) { + return false; + } + + var length = obj.length; + + if (obj.nodeType === NODE_TYPE_ELEMENT && length) { + return true; + } + + return isString(obj) || isArray(obj) || length === 0 || + typeof length === 'number' && length > 0 && (length - 1) in obj; +} + +/** + * @ngdoc function + * @name angular.forEach + * @module ng + * @kind function + * + * @description + * Invokes the `iterator` function once for each item in `obj` collection, which can be either an + * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value` + * is the value of an object property or an array element, `key` is the object property key or + * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional. + * + * It is worth noting that `.forEach` does not iterate over inherited properties because it filters + * using the `hasOwnProperty` method. + * + * Unlike ES262's + * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18), + * Providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just + * return the value provided. + * + ```js + var values = {name: 'misko', gender: 'male'}; + var log = []; + angular.forEach(values, function(value, key) { + this.push(key + ': ' + value); + }, log); + expect(log).toEqual(['name: misko', 'gender: male']); + ``` + * + * @param {Object|Array} obj Object to iterate over. + * @param {Function} iterator Iterator function. + * @param {Object=} context Object to become context (`this`) for the iterator function. + * @returns {Object|Array} Reference to `obj`. + */ + +function forEach(obj, iterator, context) { + var key, length; + if (obj) { + if (isFunction(obj)) { + for (key in obj) { + // Need to check if hasOwnProperty exists, + // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function + if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) { + iterator.call(context, obj[key], key, obj); + } + } + } else if (isArray(obj) || isArrayLike(obj)) { + var isPrimitive = typeof obj !== 'object'; + for (key = 0, length = obj.length; key < length; key++) { + if (isPrimitive || key in obj) { + iterator.call(context, obj[key], key, obj); + } + } + } else if (obj.forEach && obj.forEach !== forEach) { + obj.forEach(iterator, context, obj); + } else { + for (key in obj) { + if (obj.hasOwnProperty(key)) { + iterator.call(context, obj[key], key, obj); + } + } + } + } + return obj; +} + +function sortedKeys(obj) { + return Object.keys(obj).sort(); +} + +function forEachSorted(obj, iterator, context) { + var keys = sortedKeys(obj); + for (var i = 0; i < keys.length; i++) { + iterator.call(context, obj[keys[i]], keys[i]); + } + return keys; +} + + +/** + * when using forEach the params are value, key, but it is often useful to have key, value. + * @param {function(string, *)} iteratorFn + * @returns {function(*, string)} + */ +function reverseParams(iteratorFn) { + return function(value, key) { iteratorFn(key, value); }; +} + +/** + * A consistent way of creating unique IDs in angular. + * + * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before + * we hit number precision issues in JavaScript. + * + * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M + * + * @returns {number} an unique alpha-numeric string + */ +function nextUid() { + return ++uid; +} + + +/** + * Set or clear the hashkey for an object. + * @param obj object + * @param h the hashkey (!truthy to delete the hashkey) + */ +function setHashKey(obj, h) { + if (h) { + obj.$$hashKey = h; + } else { + delete obj.$$hashKey; + } +} + +/** + * @ngdoc function + * @name angular.extend + * @module ng + * @kind function + * + * @description + * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s) + * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so + * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`. + * Note: Keep in mind that `angular.extend` does not support recursive merge (deep copy). + * + * @param {Object} dst Destination object. + * @param {...Object} src Source object(s). + * @returns {Object} Reference to `dst`. + */ +function extend(dst) { + var h = dst.$$hashKey; + + for (var i = 1, ii = arguments.length; i < ii; i++) { + var obj = arguments[i]; + if (obj) { + var keys = Object.keys(obj); + for (var j = 0, jj = keys.length; j < jj; j++) { + var key = keys[j]; + dst[key] = obj[key]; + } + } + } + + setHashKey(dst, h); + return dst; +} + +function int(str) { + return parseInt(str, 10); +} + + +function inherit(parent, extra) { + return extend(Object.create(parent), extra); +} + +/** + * @ngdoc function + * @name angular.noop + * @module ng + * @kind function + * + * @description + * A function that performs no operations. This function can be useful when writing code in the + * functional style. + ```js + function foo(callback) { + var result = calculateResult(); + (callback || angular.noop)(result); + } + ``` + */ +function noop() {} +noop.$inject = []; + + +/** + * @ngdoc function + * @name angular.identity + * @module ng + * @kind function + * + * @description + * A function that returns its first argument. This function is useful when writing code in the + * functional style. + * + ```js + function transformer(transformationFn, value) { + return (transformationFn || angular.identity)(value); + }; + ``` + * @param {*} value to be returned. + * @returns {*} the value passed in. + */ +function identity($) {return $;} +identity.$inject = []; + + +function valueFn(value) {return function() {return value;};} + +/** + * @ngdoc function + * @name angular.isUndefined + * @module ng + * @kind function + * + * @description + * Determines if a reference is undefined. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is undefined. + */ +function isUndefined(value) {return typeof value === 'undefined';} + + +/** + * @ngdoc function + * @name angular.isDefined + * @module ng + * @kind function + * + * @description + * Determines if a reference is defined. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is defined. + */ +function isDefined(value) {return typeof value !== 'undefined';} + + +/** + * @ngdoc function + * @name angular.isObject + * @module ng + * @kind function + * + * @description + * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not + * considered to be objects. Note that JavaScript arrays are objects. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is an `Object` but not `null`. + */ +function isObject(value) { + // http://jsperf.com/isobject4 + return value !== null && typeof value === 'object'; +} + + +/** + * @ngdoc function + * @name angular.isString + * @module ng + * @kind function + * + * @description + * Determines if a reference is a `String`. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is a `String`. + */ +function isString(value) {return typeof value === 'string';} + + +/** + * @ngdoc function + * @name angular.isNumber + * @module ng + * @kind function + * + * @description + * Determines if a reference is a `Number`. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is a `Number`. + */ +function isNumber(value) {return typeof value === 'number';} + + +/** + * @ngdoc function + * @name angular.isDate + * @module ng + * @kind function + * + * @description + * Determines if a value is a date. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is a `Date`. + */ +function isDate(value) { + return toString.call(value) === '[object Date]'; +} + + +/** + * @ngdoc function + * @name angular.isArray + * @module ng + * @kind function + * + * @description + * Determines if a reference is an `Array`. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is an `Array`. + */ +var isArray = Array.isArray; + +/** + * @ngdoc function + * @name angular.isFunction + * @module ng + * @kind function + * + * @description + * Determines if a reference is a `Function`. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is a `Function`. + */ +function isFunction(value) {return typeof value === 'function';} + + +/** + * Determines if a value is a regular expression object. + * + * @private + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is a `RegExp`. + */ +function isRegExp(value) { + return toString.call(value) === '[object RegExp]'; +} + + +/** + * Checks if `obj` is a window object. + * + * @private + * @param {*} obj Object to check + * @returns {boolean} True if `obj` is a window obj. + */ +function isWindow(obj) { + return obj && obj.window === obj; +} + + +function isScope(obj) { + return obj && obj.$evalAsync && obj.$watch; +} + + +function isFile(obj) { + return toString.call(obj) === '[object File]'; +} + + +function isFormData(obj) { + return toString.call(obj) === '[object FormData]'; +} + + +function isBlob(obj) { + return toString.call(obj) === '[object Blob]'; +} + + +function isBoolean(value) { + return typeof value === 'boolean'; +} + + +function isPromiseLike(obj) { + return obj && isFunction(obj.then); +} + + +var trim = function(value) { + return isString(value) ? value.trim() : value; +}; + +// Copied from: +// http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021 +// Prereq: s is a string. +var escapeForRegexp = function(s) { + return s.replace(/([-()\[\]{}+?*.$\^|,:#= 0) + array.splice(index, 1); + return value; +} + +/** + * @ngdoc function + * @name angular.copy + * @module ng + * @kind function + * + * @description + * Creates a deep copy of `source`, which should be an object or an array. + * + * * If no destination is supplied, a copy of the object or array is created. + * * If a destination is provided, all of its elements (for arrays) or properties (for objects) + * are deleted and then all elements/properties from the source are copied to it. + * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned. + * * If `source` is identical to 'destination' an exception will be thrown. + * + * @param {*} source The source that will be used to make a copy. + * Can be any type, including primitives, `null`, and `undefined`. + * @param {(Object|Array)=} destination Destination into which the source is copied. If + * provided, must be of the same type as `source`. + * @returns {*} The copy or updated `destination`, if `destination` was specified. + * + * @example + + +
    + + Name:
    + E-mail:
    + Gender: male + female
    + + + +
    form = {{user | json}}
    +
    master = {{master | json}}
    +
    + + +
    +
    + */ +function copy(source, destination, stackSource, stackDest) { + if (isWindow(source) || isScope(source)) { + throw ngMinErr('cpws', + "Can't copy! Making copies of Window or Scope instances is not supported."); + } + + if (!destination) { + destination = source; + if (source) { + if (isArray(source)) { + destination = copy(source, [], stackSource, stackDest); + } else if (isDate(source)) { + destination = new Date(source.getTime()); + } else if (isRegExp(source)) { + destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]); + destination.lastIndex = source.lastIndex; + } else if (isObject(source)) { + var emptyObject = Object.create(Object.getPrototypeOf(source)); + destination = copy(source, emptyObject, stackSource, stackDest); + } + } + } else { + if (source === destination) throw ngMinErr('cpi', + "Can't copy! Source and destination are identical."); + + stackSource = stackSource || []; + stackDest = stackDest || []; + + if (isObject(source)) { + var index = stackSource.indexOf(source); + if (index !== -1) return stackDest[index]; + + stackSource.push(source); + stackDest.push(destination); + } + + var result; + if (isArray(source)) { + destination.length = 0; + for (var i = 0; i < source.length; i++) { + result = copy(source[i], null, stackSource, stackDest); + if (isObject(source[i])) { + stackSource.push(source[i]); + stackDest.push(result); + } + destination.push(result); + } + } else { + var h = destination.$$hashKey; + if (isArray(destination)) { + destination.length = 0; + } else { + forEach(destination, function(value, key) { + delete destination[key]; + }); + } + for (var key in source) { + if (source.hasOwnProperty(key)) { + result = copy(source[key], null, stackSource, stackDest); + if (isObject(source[key])) { + stackSource.push(source[key]); + stackDest.push(result); + } + destination[key] = result; + } + } + setHashKey(destination,h); + } + + } + return destination; +} + +/** + * Creates a shallow copy of an object, an array or a primitive. + * + * Assumes that there are no proto properties for objects. + */ +function shallowCopy(src, dst) { + if (isArray(src)) { + dst = dst || []; + + for (var i = 0, ii = src.length; i < ii; i++) { + dst[i] = src[i]; + } + } else if (isObject(src)) { + dst = dst || {}; + + for (var key in src) { + if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) { + dst[key] = src[key]; + } + } + } + + return dst || src; +} + + +/** + * @ngdoc function + * @name angular.equals + * @module ng + * @kind function + * + * @description + * Determines if two objects or two values are equivalent. Supports value types, regular + * expressions, arrays and objects. + * + * Two objects or values are considered equivalent if at least one of the following is true: + * + * * Both objects or values pass `===` comparison. + * * Both objects or values are of the same type and all of their properties are equal by + * comparing them with `angular.equals`. + * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal) + * * Both values represent the same regular expression (In JavaScript, + * /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual + * representation matches). + * + * During a property comparison, properties of `function` type and properties with names + * that begin with `$` are ignored. + * + * Scope and DOMWindow objects are being compared only by identify (`===`). + * + * @param {*} o1 Object or value to compare. + * @param {*} o2 Object or value to compare. + * @returns {boolean} True if arguments are equal. + */ +function equals(o1, o2) { + if (o1 === o2) return true; + if (o1 === null || o2 === null) return false; + if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN + var t1 = typeof o1, t2 = typeof o2, length, key, keySet; + if (t1 == t2) { + if (t1 == 'object') { + if (isArray(o1)) { + if (!isArray(o2)) return false; + if ((length = o1.length) == o2.length) { + for (key = 0; key < length; key++) { + if (!equals(o1[key], o2[key])) return false; + } + return true; + } + } else if (isDate(o1)) { + if (!isDate(o2)) return false; + return equals(o1.getTime(), o2.getTime()); + } else if (isRegExp(o1) && isRegExp(o2)) { + return o1.toString() == o2.toString(); + } else { + if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false; + keySet = {}; + for (key in o1) { + if (key.charAt(0) === '$' || isFunction(o1[key])) continue; + if (!equals(o1[key], o2[key])) return false; + keySet[key] = true; + } + for (key in o2) { + if (!keySet.hasOwnProperty(key) && + key.charAt(0) !== '$' && + o2[key] !== undefined && + !isFunction(o2[key])) return false; + } + return true; + } + } + } + return false; +} + +var csp = function() { + if (isDefined(csp.isActive_)) return csp.isActive_; + + var active = !!(document.querySelector('[ng-csp]') || + document.querySelector('[data-ng-csp]')); + + if (!active) { + try { + /* jshint -W031, -W054 */ + new Function(''); + /* jshint +W031, +W054 */ + } catch (e) { + active = true; + } + } + + return (csp.isActive_ = active); +}; + + + +function concat(array1, array2, index) { + return array1.concat(slice.call(array2, index)); +} + +function sliceArgs(args, startIndex) { + return slice.call(args, startIndex || 0); +} + + +/* jshint -W101 */ +/** + * @ngdoc function + * @name angular.bind + * @module ng + * @kind function + * + * @description + * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for + * `fn`). You can supply optional `args` that are prebound to the function. This feature is also + * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as + * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application). + * + * @param {Object} self Context which `fn` should be evaluated in. + * @param {function()} fn Function to be bound. + * @param {...*} args Optional arguments to be prebound to the `fn` function call. + * @returns {function()} Function that wraps the `fn` with all the specified bindings. + */ +/* jshint +W101 */ +function bind(self, fn) { + var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : []; + if (isFunction(fn) && !(fn instanceof RegExp)) { + return curryArgs.length + ? function() { + return arguments.length + ? fn.apply(self, concat(curryArgs, arguments, 0)) + : fn.apply(self, curryArgs); + } + : function() { + return arguments.length + ? fn.apply(self, arguments) + : fn.call(self); + }; + } else { + // in IE, native methods are not functions so they cannot be bound (note: they don't need to be) + return fn; + } +} + + +function toJsonReplacer(key, value) { + var val = value; + + if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') { + val = undefined; + } else if (isWindow(value)) { + val = '$WINDOW'; + } else if (value && document === value) { + val = '$DOCUMENT'; + } else if (isScope(value)) { + val = '$SCOPE'; + } + + return val; +} + + +/** + * @ngdoc function + * @name angular.toJson + * @module ng + * @kind function + * + * @description + * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be + * stripped since angular uses this notation internally. + * + * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON. + * @param {boolean|number=} pretty If set to true, the JSON output will contain newlines and whitespace. + * If set to an integer, the JSON output will contain that many spaces per indentation (the default is 2). + * @returns {string|undefined} JSON-ified string representing `obj`. + */ +function toJson(obj, pretty) { + if (typeof obj === 'undefined') return undefined; + if (!isNumber(pretty)) { + pretty = pretty ? 2 : null; + } + return JSON.stringify(obj, toJsonReplacer, pretty); +} + + +/** + * @ngdoc function + * @name angular.fromJson + * @module ng + * @kind function + * + * @description + * Deserializes a JSON string. + * + * @param {string} json JSON string to deserialize. + * @returns {Object|Array|string|number} Deserialized JSON string. + */ +function fromJson(json) { + return isString(json) + ? JSON.parse(json) + : json; +} + + +/** + * @returns {string} Returns the string representation of the element. + */ +function startingTag(element) { + element = jqLite(element).clone(); + try { + // turns out IE does not let you set .html() on elements which + // are not allowed to have children. So we just ignore it. + element.empty(); + } catch (e) {} + var elemHtml = jqLite('
    ').append(element).html(); + try { + return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) : + elemHtml. + match(/^(<[^>]+>)/)[1]. + replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); }); + } catch (e) { + return lowercase(elemHtml); + } + +} + + +///////////////////////////////////////////////// + +/** + * Tries to decode the URI component without throwing an exception. + * + * @private + * @param str value potential URI component to check. + * @returns {boolean} True if `value` can be decoded + * with the decodeURIComponent function. + */ +function tryDecodeURIComponent(value) { + try { + return decodeURIComponent(value); + } catch (e) { + // Ignore any invalid uri component + } +} + + +/** + * Parses an escaped url query string into key-value pairs. + * @returns {Object.} + */ +function parseKeyValue(/**string*/keyValue) { + var obj = {}, key_value, key; + forEach((keyValue || "").split('&'), function(keyValue) { + if (keyValue) { + key_value = keyValue.replace(/\+/g,'%20').split('='); + key = tryDecodeURIComponent(key_value[0]); + if (isDefined(key)) { + var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true; + if (!hasOwnProperty.call(obj, key)) { + obj[key] = val; + } else if (isArray(obj[key])) { + obj[key].push(val); + } else { + obj[key] = [obj[key],val]; + } + } + } + }); + return obj; +} + +function toKeyValue(obj) { + var parts = []; + forEach(obj, function(value, key) { + if (isArray(value)) { + forEach(value, function(arrayValue) { + parts.push(encodeUriQuery(key, true) + + (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true))); + }); + } else { + parts.push(encodeUriQuery(key, true) + + (value === true ? '' : '=' + encodeUriQuery(value, true))); + } + }); + return parts.length ? parts.join('&') : ''; +} + + +/** + * We need our custom method because encodeURIComponent is too aggressive and doesn't follow + * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path + * segments: + * segment = *pchar + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + * pct-encoded = "%" HEXDIG HEXDIG + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + * / "*" / "+" / "," / ";" / "=" + */ +function encodeUriSegment(val) { + return encodeUriQuery(val, true). + replace(/%26/gi, '&'). + replace(/%3D/gi, '='). + replace(/%2B/gi, '+'); +} + + +/** + * This method is intended for encoding *key* or *value* parts of query component. We need a custom + * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be + * encoded per http://tools.ietf.org/html/rfc3986: + * query = *( pchar / "/" / "?" ) + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * pct-encoded = "%" HEXDIG HEXDIG + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + * / "*" / "+" / "," / ";" / "=" + */ +function encodeUriQuery(val, pctEncodeSpaces) { + return encodeURIComponent(val). + replace(/%40/gi, '@'). + replace(/%3A/gi, ':'). + replace(/%24/g, '$'). + replace(/%2C/gi, ','). + replace(/%3B/gi, ';'). + replace(/%20/g, (pctEncodeSpaces ? '%20' : '+')); +} + +var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-']; + +function getNgAttribute(element, ngAttr) { + var attr, i, ii = ngAttrPrefixes.length; + element = jqLite(element); + for (i = 0; i < ii; ++i) { + attr = ngAttrPrefixes[i] + ngAttr; + if (isString(attr = element.attr(attr))) { + return attr; + } + } + return null; +} + +/** + * @ngdoc directive + * @name ngApp + * @module ng + * + * @element ANY + * @param {angular.Module} ngApp an optional application + * {@link angular.module module} name to load. + * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be + * created in "strict-di" mode. This means that the application will fail to invoke functions which + * do not use explicit function annotation (and are thus unsuitable for minification), as described + * in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in + * tracking down the root of these bugs. + * + * @description + * + * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive + * designates the **root element** of the application and is typically placed near the root element + * of the page - e.g. on the `` or `` tags. + * + * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp` + * found in the document will be used to define the root element to auto-bootstrap as an + * application. To run multiple applications in an HTML document you must manually bootstrap them using + * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other. + * + * You can specify an **AngularJS module** to be used as the root module for the application. This + * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It + * should contain the application code needed or have dependencies on other modules that will + * contain the code. See {@link angular.module} for more information. + * + * In the example below if the `ngApp` directive were not placed on the `html` element then the + * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}` + * would not be resolved to `3`. + * + * `ngApp` is the easiest, and most common way to bootstrap an application. + * + + +
    + I can add: {{a}} + {{b}} = {{ a+b }} +
    +
    + + angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) { + $scope.a = 1; + $scope.b = 2; + }); + +
    + * + * Using `ngStrictDi`, you would see something like this: + * + + +
    +
    + I can add: {{a}} + {{b}} = {{ a+b }} + +

    This renders because the controller does not fail to + instantiate, by using explicit annotation style (see + script.js for details) +

    +
    + +
    + Name:
    + Hello, {{name}}! + +

    This renders because the controller does not fail to + instantiate, by using explicit annotation style + (see script.js for details) +

    +
    + +
    + I can add: {{a}} + {{b}} = {{ a+b }} + +

    The controller could not be instantiated, due to relying + on automatic function annotations (which are disabled in + strict mode). As such, the content of this section is not + interpolated, and there should be an error in your web console. +

    +
    +
    +
    + + angular.module('ngAppStrictDemo', []) + // BadController will fail to instantiate, due to relying on automatic function annotation, + // rather than an explicit annotation + .controller('BadController', function($scope) { + $scope.a = 1; + $scope.b = 2; + }) + // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated, + // due to using explicit annotations using the array style and $inject property, respectively. + .controller('GoodController1', ['$scope', function($scope) { + $scope.a = 1; + $scope.b = 2; + }]) + .controller('GoodController2', GoodController2); + function GoodController2($scope) { + $scope.name = "World"; + } + GoodController2.$inject = ['$scope']; + + + div[ng-controller] { + margin-bottom: 1em; + -webkit-border-radius: 4px; + border-radius: 4px; + border: 1px solid; + padding: .5em; + } + div[ng-controller^=Good] { + border-color: #d6e9c6; + background-color: #dff0d8; + color: #3c763d; + } + div[ng-controller^=Bad] { + border-color: #ebccd1; + background-color: #f2dede; + color: #a94442; + margin-bottom: 0; + } + +
    + */ +function angularInit(element, bootstrap) { + var appElement, + module, + config = {}; + + // The element `element` has priority over any other element + forEach(ngAttrPrefixes, function(prefix) { + var name = prefix + 'app'; + + if (!appElement && element.hasAttribute && element.hasAttribute(name)) { + appElement = element; + module = element.getAttribute(name); + } + }); + forEach(ngAttrPrefixes, function(prefix) { + var name = prefix + 'app'; + var candidate; + + if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) { + appElement = candidate; + module = candidate.getAttribute(name); + } + }); + if (appElement) { + config.strictDi = getNgAttribute(appElement, "strict-di") !== null; + bootstrap(appElement, module ? [module] : [], config); + } +} + +/** + * @ngdoc function + * @name angular.bootstrap + * @module ng + * @description + * Use this function to manually start up angular application. + * + * See: {@link guide/bootstrap Bootstrap} + * + * Note that Protractor based end-to-end tests cannot use this function to bootstrap manually. + * They must use {@link ng.directive:ngApp ngApp}. + * + * Angular will detect if it has been loaded into the browser more than once and only allow the + * first loaded script to be bootstrapped and will report a warning to the browser console for + * each of the subsequent scripts. This prevents strange results in applications, where otherwise + * multiple instances of Angular try to work on the DOM. + * + * ```html + * + * + * + *
    + * {{greeting}} + *
    + * + * + * + * + * + * ``` + * + * @param {DOMElement} element DOM element which is the root of angular application. + * @param {Array=} modules an array of modules to load into the application. + * Each item in the array should be the name of a predefined module or a (DI annotated) + * function that will be invoked by the injector as a `config` block. + * See: {@link angular.module modules} + * @param {Object=} config an object for defining configuration options for the application. The + * following keys are supported: + * + * * `strictDi` - disable automatic function annotation for the application. This is meant to + * assist in finding bugs which break minified code. Defaults to `false`. + * + * @returns {auto.$injector} Returns the newly created injector for this app. + */ +function bootstrap(element, modules, config) { + if (!isObject(config)) config = {}; + var defaultConfig = { + strictDi: false + }; + config = extend(defaultConfig, config); + var doBootstrap = function() { + element = jqLite(element); + + if (element.injector()) { + var tag = (element[0] === document) ? 'document' : startingTag(element); + //Encode angle brackets to prevent input from being sanitized to empty string #8683 + throw ngMinErr( + 'btstrpd', + "App Already Bootstrapped with this Element '{0}'", + tag.replace(//,'>')); + } + + modules = modules || []; + modules.unshift(['$provide', function($provide) { + $provide.value('$rootElement', element); + }]); + + if (config.debugInfoEnabled) { + // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`. + modules.push(['$compileProvider', function($compileProvider) { + $compileProvider.debugInfoEnabled(true); + }]); + } + + modules.unshift('ng'); + var injector = createInjector(modules, config.strictDi); + injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', + function bootstrapApply(scope, element, compile, injector) { + scope.$apply(function() { + element.data('$injector', injector); + compile(element)(scope); + }); + }] + ); + return injector; + }; + + var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/; + var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/; + + if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) { + config.debugInfoEnabled = true; + window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, ''); + } + + if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) { + return doBootstrap(); + } + + window.name = window.name.replace(NG_DEFER_BOOTSTRAP, ''); + angular.resumeBootstrap = function(extraModules) { + forEach(extraModules, function(module) { + modules.push(module); + }); + return doBootstrap(); + }; + + if (isFunction(angular.resumeDeferredBootstrap)) { + angular.resumeDeferredBootstrap(); + } +} + +/** + * @ngdoc function + * @name angular.reloadWithDebugInfo + * @module ng + * @description + * Use this function to reload the current application with debug information turned on. + * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`. + * + * See {@link ng.$compileProvider#debugInfoEnabled} for more. + */ +function reloadWithDebugInfo() { + window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name; + window.location.reload(); +} + +/** + * @name angular.getTestability + * @module ng + * @description + * Get the testability service for the instance of Angular on the given + * element. + * @param {DOMElement} element DOM element which is the root of angular application. + */ +function getTestability(rootElement) { + var injector = angular.element(rootElement).injector(); + if (!injector) { + throw ngMinErr('test', + 'no injector found for element argument to getTestability'); + } + return injector.get('$$testability'); +} + +var SNAKE_CASE_REGEXP = /[A-Z]/g; +function snake_case(name, separator) { + separator = separator || '_'; + return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) { + return (pos ? separator : '') + letter.toLowerCase(); + }); +} + +var bindJQueryFired = false; +var skipDestroyOnNextJQueryCleanData; +function bindJQuery() { + var originalCleanData; + + if (bindJQueryFired) { + return; + } + + // bind to jQuery if present; + jQuery = window.jQuery; + // Use jQuery if it exists with proper functionality, otherwise default to us. + // Angular 1.2+ requires jQuery 1.7+ for on()/off() support. + // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older + // versions. It will not work for sure with jQuery <1.7, though. + if (jQuery && jQuery.fn.on) { + jqLite = jQuery; + extend(jQuery.fn, { + scope: JQLitePrototype.scope, + isolateScope: JQLitePrototype.isolateScope, + controller: JQLitePrototype.controller, + injector: JQLitePrototype.injector, + inheritedData: JQLitePrototype.inheritedData + }); + + // All nodes removed from the DOM via various jQuery APIs like .remove() + // are passed through jQuery.cleanData. Monkey-patch this method to fire + // the $destroy event on all removed nodes. + originalCleanData = jQuery.cleanData; + jQuery.cleanData = function(elems) { + var events; + if (!skipDestroyOnNextJQueryCleanData) { + for (var i = 0, elem; (elem = elems[i]) != null; i++) { + events = jQuery._data(elem, "events"); + if (events && events.$destroy) { + jQuery(elem).triggerHandler('$destroy'); + } + } + } else { + skipDestroyOnNextJQueryCleanData = false; + } + originalCleanData(elems); + }; + } else { + jqLite = JQLite; + } + + angular.element = jqLite; + + // Prevent double-proxying. + bindJQueryFired = true; +} + +/** + * throw error if the argument is falsy. + */ +function assertArg(arg, name, reason) { + if (!arg) { + throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required")); + } + return arg; +} + +function assertArgFn(arg, name, acceptArrayAnnotation) { + if (acceptArrayAnnotation && isArray(arg)) { + arg = arg[arg.length - 1]; + } + + assertArg(isFunction(arg), name, 'not a function, got ' + + (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg)); + return arg; +} + +/** + * throw error if the name given is hasOwnProperty + * @param {String} name the name to test + * @param {String} context the context in which the name is used, such as module or directive + */ +function assertNotHasOwnProperty(name, context) { + if (name === 'hasOwnProperty') { + throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context); + } +} + +/** + * Return the value accessible from the object by path. Any undefined traversals are ignored + * @param {Object} obj starting object + * @param {String} path path to traverse + * @param {boolean} [bindFnToScope=true] + * @returns {Object} value as accessible by path + */ +//TODO(misko): this function needs to be removed +function getter(obj, path, bindFnToScope) { + if (!path) return obj; + var keys = path.split('.'); + var key; + var lastInstance = obj; + var len = keys.length; + + for (var i = 0; i < len; i++) { + key = keys[i]; + if (obj) { + obj = (lastInstance = obj)[key]; + } + } + if (!bindFnToScope && isFunction(obj)) { + return bind(lastInstance, obj); + } + return obj; +} + +/** + * Return the DOM siblings between the first and last node in the given array. + * @param {Array} array like object + * @returns {jqLite} jqLite collection containing the nodes + */ +function getBlockNodes(nodes) { + // TODO(perf): just check if all items in `nodes` are siblings and if they are return the original + // collection, otherwise update the original collection. + var node = nodes[0]; + var endNode = nodes[nodes.length - 1]; + var blockNodes = [node]; + + do { + node = node.nextSibling; + if (!node) break; + blockNodes.push(node); + } while (node !== endNode); + + return jqLite(blockNodes); +} + + +/** + * Creates a new object without a prototype. This object is useful for lookup without having to + * guard against prototypically inherited properties via hasOwnProperty. + * + * Related micro-benchmarks: + * - http://jsperf.com/object-create2 + * - http://jsperf.com/proto-map-lookup/2 + * - http://jsperf.com/for-in-vs-object-keys2 + * + * @returns {Object} + */ +function createMap() { + return Object.create(null); +} + +var NODE_TYPE_ELEMENT = 1; +var NODE_TYPE_TEXT = 3; +var NODE_TYPE_COMMENT = 8; +var NODE_TYPE_DOCUMENT = 9; +var NODE_TYPE_DOCUMENT_FRAGMENT = 11; + +/** + * @ngdoc type + * @name angular.Module + * @module ng + * @description + * + * Interface for configuring angular {@link angular.module modules}. + */ + +function setupModuleLoader(window) { + + var $injectorMinErr = minErr('$injector'); + var ngMinErr = minErr('ng'); + + function ensure(obj, name, factory) { + return obj[name] || (obj[name] = factory()); + } + + var angular = ensure(window, 'angular', Object); + + // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap + angular.$$minErr = angular.$$minErr || minErr; + + return ensure(angular, 'module', function() { + /** @type {Object.} */ + var modules = {}; + + /** + * @ngdoc function + * @name angular.module + * @module ng + * @description + * + * The `angular.module` is a global place for creating, registering and retrieving Angular + * modules. + * All modules (angular core or 3rd party) that should be available to an application must be + * registered using this mechanism. + * + * When passed two or more arguments, a new module is created. If passed only one argument, an + * existing module (the name passed as the first argument to `module`) is retrieved. + * + * + * # Module + * + * A module is a collection of services, directives, controllers, filters, and configuration information. + * `angular.module` is used to configure the {@link auto.$injector $injector}. + * + * ```js + * // Create a new module + * var myModule = angular.module('myModule', []); + * + * // register a new service + * myModule.value('appName', 'MyCoolApp'); + * + * // configure existing services inside initialization blocks. + * myModule.config(['$locationProvider', function($locationProvider) { + * // Configure existing providers + * $locationProvider.hashPrefix('!'); + * }]); + * ``` + * + * Then you can create an injector and load your modules like this: + * + * ```js + * var injector = angular.injector(['ng', 'myModule']) + * ``` + * + * However it's more likely that you'll just use + * {@link ng.directive:ngApp ngApp} or + * {@link angular.bootstrap} to simplify this process for you. + * + * @param {!string} name The name of the module to create or retrieve. + * @param {!Array.=} requires If specified then new module is being created. If + * unspecified then the module is being retrieved for further configuration. + * @param {Function=} configFn Optional configuration function for the module. Same as + * {@link angular.Module#config Module#config()}. + * @returns {module} new module with the {@link angular.Module} api. + */ + return function module(name, requires, configFn) { + var assertNotHasOwnProperty = function(name, context) { + if (name === 'hasOwnProperty') { + throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context); + } + }; + + assertNotHasOwnProperty(name, 'module'); + if (requires && modules.hasOwnProperty(name)) { + modules[name] = null; + } + return ensure(modules, name, function() { + if (!requires) { + throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " + + "the module name or forgot to load it. If registering a module ensure that you " + + "specify the dependencies as the second argument.", name); + } + + /** @type {!Array.>} */ + var invokeQueue = []; + + /** @type {!Array.} */ + var configBlocks = []; + + /** @type {!Array.} */ + var runBlocks = []; + + var config = invokeLater('$injector', 'invoke', 'push', configBlocks); + + /** @type {angular.Module} */ + var moduleInstance = { + // Private state + _invokeQueue: invokeQueue, + _configBlocks: configBlocks, + _runBlocks: runBlocks, + + /** + * @ngdoc property + * @name angular.Module#requires + * @module ng + * + * @description + * Holds the list of modules which the injector will load before the current module is + * loaded. + */ + requires: requires, + + /** + * @ngdoc property + * @name angular.Module#name + * @module ng + * + * @description + * Name of the module. + */ + name: name, + + + /** + * @ngdoc method + * @name angular.Module#provider + * @module ng + * @param {string} name service name + * @param {Function} providerType Construction function for creating new instance of the + * service. + * @description + * See {@link auto.$provide#provider $provide.provider()}. + */ + provider: invokeLater('$provide', 'provider'), + + /** + * @ngdoc method + * @name angular.Module#factory + * @module ng + * @param {string} name service name + * @param {Function} providerFunction Function for creating new instance of the service. + * @description + * See {@link auto.$provide#factory $provide.factory()}. + */ + factory: invokeLater('$provide', 'factory'), + + /** + * @ngdoc method + * @name angular.Module#service + * @module ng + * @param {string} name service name + * @param {Function} constructor A constructor function that will be instantiated. + * @description + * See {@link auto.$provide#service $provide.service()}. + */ + service: invokeLater('$provide', 'service'), + + /** + * @ngdoc method + * @name angular.Module#value + * @module ng + * @param {string} name service name + * @param {*} object Service instance object. + * @description + * See {@link auto.$provide#value $provide.value()}. + */ + value: invokeLater('$provide', 'value'), + + /** + * @ngdoc method + * @name angular.Module#constant + * @module ng + * @param {string} name constant name + * @param {*} object Constant value. + * @description + * Because the constant are fixed, they get applied before other provide methods. + * See {@link auto.$provide#constant $provide.constant()}. + */ + constant: invokeLater('$provide', 'constant', 'unshift'), + + /** + * @ngdoc method + * @name angular.Module#animation + * @module ng + * @param {string} name animation name + * @param {Function} animationFactory Factory function for creating new instance of an + * animation. + * @description + * + * **NOTE**: animations take effect only if the **ngAnimate** module is loaded. + * + * + * Defines an animation hook that can be later used with + * {@link ngAnimate.$animate $animate} service and directives that use this service. + * + * ```js + * module.animation('.animation-name', function($inject1, $inject2) { + * return { + * eventName : function(element, done) { + * //code to run the animation + * //once complete, then run done() + * return function cancellationFunction(element) { + * //code to cancel the animation + * } + * } + * } + * }) + * ``` + * + * See {@link ng.$animateProvider#register $animateProvider.register()} and + * {@link ngAnimate ngAnimate module} for more information. + */ + animation: invokeLater('$animateProvider', 'register'), + + /** + * @ngdoc method + * @name angular.Module#filter + * @module ng + * @param {string} name Filter name. + * @param {Function} filterFactory Factory function for creating new instance of filter. + * @description + * See {@link ng.$filterProvider#register $filterProvider.register()}. + */ + filter: invokeLater('$filterProvider', 'register'), + + /** + * @ngdoc method + * @name angular.Module#controller + * @module ng + * @param {string|Object} name Controller name, or an object map of controllers where the + * keys are the names and the values are the constructors. + * @param {Function} constructor Controller constructor function. + * @description + * See {@link ng.$controllerProvider#register $controllerProvider.register()}. + */ + controller: invokeLater('$controllerProvider', 'register'), + + /** + * @ngdoc method + * @name angular.Module#directive + * @module ng + * @param {string|Object} name Directive name, or an object map of directives where the + * keys are the names and the values are the factories. + * @param {Function} directiveFactory Factory function for creating new instance of + * directives. + * @description + * See {@link ng.$compileProvider#directive $compileProvider.directive()}. + */ + directive: invokeLater('$compileProvider', 'directive'), + + /** + * @ngdoc method + * @name angular.Module#config + * @module ng + * @param {Function} configFn Execute this function on module load. Useful for service + * configuration. + * @description + * Use this method to register work which needs to be performed on module loading. + * For more about how to configure services, see + * {@link providers#provider-recipe Provider Recipe}. + */ + config: config, + + /** + * @ngdoc method + * @name angular.Module#run + * @module ng + * @param {Function} initializationFn Execute this function after injector creation. + * Useful for application initialization. + * @description + * Use this method to register work which should be performed when the injector is done + * loading all modules. + */ + run: function(block) { + runBlocks.push(block); + return this; + } + }; + + if (configFn) { + config(configFn); + } + + return moduleInstance; + + /** + * @param {string} provider + * @param {string} method + * @param {String=} insertMethod + * @returns {angular.Module} + */ + function invokeLater(provider, method, insertMethod, queue) { + if (!queue) queue = invokeQueue; + return function() { + queue[insertMethod || 'push']([provider, method, arguments]); + return moduleInstance; + }; + } + }); + }; + }); + +} + +/* global: toDebugString: true */ + +function serializeObject(obj) { + var seen = []; + + return JSON.stringify(obj, function(key, val) { + val = toJsonReplacer(key, val); + if (isObject(val)) { + + if (seen.indexOf(val) >= 0) return '<>'; + + seen.push(val); + } + return val; + }); +} + +function toDebugString(obj) { + if (typeof obj === 'function') { + return obj.toString().replace(/ \{[\s\S]*$/, ''); + } else if (typeof obj === 'undefined') { + return 'undefined'; + } else if (typeof obj !== 'string') { + return serializeObject(obj); + } + return obj; +} + +/* global angularModule: true, + version: true, + + $LocaleProvider, + $CompileProvider, + + htmlAnchorDirective, + inputDirective, + inputDirective, + formDirective, + scriptDirective, + selectDirective, + styleDirective, + optionDirective, + ngBindDirective, + ngBindHtmlDirective, + ngBindTemplateDirective, + ngClassDirective, + ngClassEvenDirective, + ngClassOddDirective, + ngCspDirective, + ngCloakDirective, + ngControllerDirective, + ngFormDirective, + ngHideDirective, + ngIfDirective, + ngIncludeDirective, + ngIncludeFillContentDirective, + ngInitDirective, + ngNonBindableDirective, + ngPluralizeDirective, + ngRepeatDirective, + ngShowDirective, + ngStyleDirective, + ngSwitchDirective, + ngSwitchWhenDirective, + ngSwitchDefaultDirective, + ngOptionsDirective, + ngTranscludeDirective, + ngModelDirective, + ngListDirective, + ngChangeDirective, + patternDirective, + patternDirective, + requiredDirective, + requiredDirective, + minlengthDirective, + minlengthDirective, + maxlengthDirective, + maxlengthDirective, + ngValueDirective, + ngModelOptionsDirective, + ngAttributeAliasDirectives, + ngEventDirectives, + + $AnchorScrollProvider, + $AnimateProvider, + $BrowserProvider, + $CacheFactoryProvider, + $ControllerProvider, + $DocumentProvider, + $ExceptionHandlerProvider, + $FilterProvider, + $InterpolateProvider, + $IntervalProvider, + $HttpProvider, + $HttpBackendProvider, + $LocationProvider, + $LogProvider, + $ParseProvider, + $RootScopeProvider, + $QProvider, + $$QProvider, + $$SanitizeUriProvider, + $SceProvider, + $SceDelegateProvider, + $SnifferProvider, + $TemplateCacheProvider, + $TemplateRequestProvider, + $$TestabilityProvider, + $TimeoutProvider, + $$RAFProvider, + $$AsyncCallbackProvider, + $WindowProvider, + $$jqLiteProvider +*/ + + +/** + * @ngdoc object + * @name angular.version + * @module ng + * @description + * An object that contains information about the current AngularJS version. This object has the + * following properties: + * + * - `full` – `{string}` – Full version string, such as "0.9.18". + * - `major` – `{number}` – Major version number, such as "0". + * - `minor` – `{number}` – Minor version number, such as "9". + * - `dot` – `{number}` – Dot version number, such as "18". + * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat". + */ +var version = { + full: '1.3.13', // all of these placeholder strings will be replaced by grunt's + major: 1, // package task + minor: 3, + dot: 13, + codeName: 'meticulous-riffleshuffle' +}; + + +function publishExternalAPI(angular) { + extend(angular, { + 'bootstrap': bootstrap, + 'copy': copy, + 'extend': extend, + 'equals': equals, + 'element': jqLite, + 'forEach': forEach, + 'injector': createInjector, + 'noop': noop, + 'bind': bind, + 'toJson': toJson, + 'fromJson': fromJson, + 'identity': identity, + 'isUndefined': isUndefined, + 'isDefined': isDefined, + 'isString': isString, + 'isFunction': isFunction, + 'isObject': isObject, + 'isNumber': isNumber, + 'isElement': isElement, + 'isArray': isArray, + 'version': version, + 'isDate': isDate, + 'lowercase': lowercase, + 'uppercase': uppercase, + 'callbacks': {counter: 0}, + 'getTestability': getTestability, + '$$minErr': minErr, + '$$csp': csp, + 'reloadWithDebugInfo': reloadWithDebugInfo + }); + + angularModule = setupModuleLoader(window); + try { + angularModule('ngLocale'); + } catch (e) { + angularModule('ngLocale', []).provider('$locale', $LocaleProvider); + } + + angularModule('ng', ['ngLocale'], ['$provide', + function ngModule($provide) { + // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it. + $provide.provider({ + $$sanitizeUri: $$SanitizeUriProvider + }); + $provide.provider('$compile', $CompileProvider). + directive({ + a: htmlAnchorDirective, + input: inputDirective, + textarea: inputDirective, + form: formDirective, + script: scriptDirective, + select: selectDirective, + style: styleDirective, + option: optionDirective, + ngBind: ngBindDirective, + ngBindHtml: ngBindHtmlDirective, + ngBindTemplate: ngBindTemplateDirective, + ngClass: ngClassDirective, + ngClassEven: ngClassEvenDirective, + ngClassOdd: ngClassOddDirective, + ngCloak: ngCloakDirective, + ngController: ngControllerDirective, + ngForm: ngFormDirective, + ngHide: ngHideDirective, + ngIf: ngIfDirective, + ngInclude: ngIncludeDirective, + ngInit: ngInitDirective, + ngNonBindable: ngNonBindableDirective, + ngPluralize: ngPluralizeDirective, + ngRepeat: ngRepeatDirective, + ngShow: ngShowDirective, + ngStyle: ngStyleDirective, + ngSwitch: ngSwitchDirective, + ngSwitchWhen: ngSwitchWhenDirective, + ngSwitchDefault: ngSwitchDefaultDirective, + ngOptions: ngOptionsDirective, + ngTransclude: ngTranscludeDirective, + ngModel: ngModelDirective, + ngList: ngListDirective, + ngChange: ngChangeDirective, + pattern: patternDirective, + ngPattern: patternDirective, + required: requiredDirective, + ngRequired: requiredDirective, + minlength: minlengthDirective, + ngMinlength: minlengthDirective, + maxlength: maxlengthDirective, + ngMaxlength: maxlengthDirective, + ngValue: ngValueDirective, + ngModelOptions: ngModelOptionsDirective + }). + directive({ + ngInclude: ngIncludeFillContentDirective + }). + directive(ngAttributeAliasDirectives). + directive(ngEventDirectives); + $provide.provider({ + $anchorScroll: $AnchorScrollProvider, + $animate: $AnimateProvider, + $browser: $BrowserProvider, + $cacheFactory: $CacheFactoryProvider, + $controller: $ControllerProvider, + $document: $DocumentProvider, + $exceptionHandler: $ExceptionHandlerProvider, + $filter: $FilterProvider, + $interpolate: $InterpolateProvider, + $interval: $IntervalProvider, + $http: $HttpProvider, + $httpBackend: $HttpBackendProvider, + $location: $LocationProvider, + $log: $LogProvider, + $parse: $ParseProvider, + $rootScope: $RootScopeProvider, + $q: $QProvider, + $$q: $$QProvider, + $sce: $SceProvider, + $sceDelegate: $SceDelegateProvider, + $sniffer: $SnifferProvider, + $templateCache: $TemplateCacheProvider, + $templateRequest: $TemplateRequestProvider, + $$testability: $$TestabilityProvider, + $timeout: $TimeoutProvider, + $window: $WindowProvider, + $$rAF: $$RAFProvider, + $$asyncCallback: $$AsyncCallbackProvider, + $$jqLite: $$jqLiteProvider + }); + } + ]); +} + +/* global JQLitePrototype: true, + addEventListenerFn: true, + removeEventListenerFn: true, + BOOLEAN_ATTR: true, + ALIASED_ATTR: true, +*/ + +////////////////////////////////// +//JQLite +////////////////////////////////// + +/** + * @ngdoc function + * @name angular.element + * @module ng + * @kind function + * + * @description + * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element. + * + * If jQuery is available, `angular.element` is an alias for the + * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element` + * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite." + * + *
    jqLite is a tiny, API-compatible subset of jQuery that allows + * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most + * commonly needed functionality with the goal of having a very small footprint.
    + * + * To use jQuery, simply load it before `DOMContentLoaded` event fired. + * + *
    **Note:** all element references in Angular are always wrapped with jQuery or + * jqLite; they are never raw DOM references.
    + * + * ## Angular's jqLite + * jqLite provides only the following jQuery methods: + * + * - [`addClass()`](http://api.jquery.com/addClass/) + * - [`after()`](http://api.jquery.com/after/) + * - [`append()`](http://api.jquery.com/append/) + * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters + * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData + * - [`children()`](http://api.jquery.com/children/) - Does not support selectors + * - [`clone()`](http://api.jquery.com/clone/) + * - [`contents()`](http://api.jquery.com/contents/) + * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()` + * - [`data()`](http://api.jquery.com/data/) + * - [`detach()`](http://api.jquery.com/detach/) + * - [`empty()`](http://api.jquery.com/empty/) + * - [`eq()`](http://api.jquery.com/eq/) + * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name + * - [`hasClass()`](http://api.jquery.com/hasClass/) + * - [`html()`](http://api.jquery.com/html/) + * - [`next()`](http://api.jquery.com/next/) - Does not support selectors + * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData + * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors + * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors + * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors + * - [`prepend()`](http://api.jquery.com/prepend/) + * - [`prop()`](http://api.jquery.com/prop/) + * - [`ready()`](http://api.jquery.com/ready/) + * - [`remove()`](http://api.jquery.com/remove/) + * - [`removeAttr()`](http://api.jquery.com/removeAttr/) + * - [`removeClass()`](http://api.jquery.com/removeClass/) + * - [`removeData()`](http://api.jquery.com/removeData/) + * - [`replaceWith()`](http://api.jquery.com/replaceWith/) + * - [`text()`](http://api.jquery.com/text/) + * - [`toggleClass()`](http://api.jquery.com/toggleClass/) + * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers. + * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces + * - [`val()`](http://api.jquery.com/val/) + * - [`wrap()`](http://api.jquery.com/wrap/) + * + * ## jQuery/jqLite Extras + * Angular also provides the following additional methods and events to both jQuery and jqLite: + * + * ### Events + * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event + * on all DOM nodes being removed. This can be used to clean up any 3rd party bindings to the DOM + * element before it is removed. + * + * ### Methods + * - `controller(name)` - retrieves the controller of the current element or its parent. By default + * retrieves controller associated with the `ngController` directive. If `name` is provided as + * camelCase directive name, then the controller for this directive will be retrieved (e.g. + * `'ngModel'`). + * - `injector()` - retrieves the injector of the current element or its parent. + * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current + * element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to + * be enabled. + * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the + * current element. This getter should be used only on elements that contain a directive which starts a new isolate + * scope. Calling `scope()` on this element always returns the original non-isolate scope. + * Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled. + * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top + * parent element is reached. + * + * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery. + * @returns {Object} jQuery object. + */ + +JQLite.expando = 'ng339'; + +var jqCache = JQLite.cache = {}, + jqId = 1, + addEventListenerFn = function(element, type, fn) { + element.addEventListener(type, fn, false); + }, + removeEventListenerFn = function(element, type, fn) { + element.removeEventListener(type, fn, false); + }; + +/* + * !!! This is an undocumented "private" function !!! + */ +JQLite._data = function(node) { + //jQuery always returns an object on cache miss + return this.cache[node[this.expando]] || {}; +}; + +function jqNextId() { return ++jqId; } + + +var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g; +var MOZ_HACK_REGEXP = /^moz([A-Z])/; +var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"}; +var jqLiteMinErr = minErr('jqLite'); + +/** + * Converts snake_case to camelCase. + * Also there is special case for Moz prefix starting with upper case letter. + * @param name Name to normalize + */ +function camelCase(name) { + return name. + replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) { + return offset ? letter.toUpperCase() : letter; + }). + replace(MOZ_HACK_REGEXP, 'Moz$1'); +} + +var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/; +var HTML_REGEXP = /<|&#?\w+;/; +var TAG_NAME_REGEXP = /<([\w:]+)/; +var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi; + +var wrapMap = { + 'option': [1, ''], + + 'thead': [1, '', '
    '], + 'col': [2, '', '
    '], + 'tr': [2, '', '
    '], + 'td': [3, '', '
    '], + '_default': [0, "", ""] +}; + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function jqLiteIsTextNode(html) { + return !HTML_REGEXP.test(html); +} + +function jqLiteAcceptsData(node) { + // The window object can accept data but has no nodeType + // Otherwise we are only interested in elements (1) and documents (9) + var nodeType = node.nodeType; + return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT; +} + +function jqLiteBuildFragment(html, context) { + var tmp, tag, wrap, + fragment = context.createDocumentFragment(), + nodes = [], i; + + if (jqLiteIsTextNode(html)) { + // Convert non-html into a text node + nodes.push(context.createTextNode(html)); + } else { + // Convert html into DOM nodes + tmp = tmp || fragment.appendChild(context.createElement("div")); + tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase(); + wrap = wrapMap[tag] || wrapMap._default; + tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1>") + wrap[2]; + + // Descend through wrappers to the right content + i = wrap[0]; + while (i--) { + tmp = tmp.lastChild; + } + + nodes = concat(nodes, tmp.childNodes); + + tmp = fragment.firstChild; + tmp.textContent = ""; + } + + // Remove wrapper from fragment + fragment.textContent = ""; + fragment.innerHTML = ""; // Clear inner HTML + forEach(nodes, function(node) { + fragment.appendChild(node); + }); + + return fragment; +} + +function jqLiteParseHTML(html, context) { + context = context || document; + var parsed; + + if ((parsed = SINGLE_TAG_REGEXP.exec(html))) { + return [context.createElement(parsed[1])]; + } + + if ((parsed = jqLiteBuildFragment(html, context))) { + return parsed.childNodes; + } + + return []; +} + +///////////////////////////////////////////// +function JQLite(element) { + if (element instanceof JQLite) { + return element; + } + + var argIsString; + + if (isString(element)) { + element = trim(element); + argIsString = true; + } + if (!(this instanceof JQLite)) { + if (argIsString && element.charAt(0) != '<') { + throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element'); + } + return new JQLite(element); + } + + if (argIsString) { + jqLiteAddNodes(this, jqLiteParseHTML(element)); + } else { + jqLiteAddNodes(this, element); + } +} + +function jqLiteClone(element) { + return element.cloneNode(true); +} + +function jqLiteDealoc(element, onlyDescendants) { + if (!onlyDescendants) jqLiteRemoveData(element); + + if (element.querySelectorAll) { + var descendants = element.querySelectorAll('*'); + for (var i = 0, l = descendants.length; i < l; i++) { + jqLiteRemoveData(descendants[i]); + } + } +} + +function jqLiteOff(element, type, fn, unsupported) { + if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument'); + + var expandoStore = jqLiteExpandoStore(element); + var events = expandoStore && expandoStore.events; + var handle = expandoStore && expandoStore.handle; + + if (!handle) return; //no listeners registered + + if (!type) { + for (type in events) { + if (type !== '$destroy') { + removeEventListenerFn(element, type, handle); + } + delete events[type]; + } + } else { + forEach(type.split(' '), function(type) { + if (isDefined(fn)) { + var listenerFns = events[type]; + arrayRemove(listenerFns || [], fn); + if (listenerFns && listenerFns.length > 0) { + return; + } + } + + removeEventListenerFn(element, type, handle); + delete events[type]; + }); + } +} + +function jqLiteRemoveData(element, name) { + var expandoId = element.ng339; + var expandoStore = expandoId && jqCache[expandoId]; + + if (expandoStore) { + if (name) { + delete expandoStore.data[name]; + return; + } + + if (expandoStore.handle) { + if (expandoStore.events.$destroy) { + expandoStore.handle({}, '$destroy'); + } + jqLiteOff(element); + } + delete jqCache[expandoId]; + element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it + } +} + + +function jqLiteExpandoStore(element, createIfNecessary) { + var expandoId = element.ng339, + expandoStore = expandoId && jqCache[expandoId]; + + if (createIfNecessary && !expandoStore) { + element.ng339 = expandoId = jqNextId(); + expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined}; + } + + return expandoStore; +} + + +function jqLiteData(element, key, value) { + if (jqLiteAcceptsData(element)) { + + var isSimpleSetter = isDefined(value); + var isSimpleGetter = !isSimpleSetter && key && !isObject(key); + var massGetter = !key; + var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter); + var data = expandoStore && expandoStore.data; + + if (isSimpleSetter) { // data('key', value) + data[key] = value; + } else { + if (massGetter) { // data() + return data; + } else { + if (isSimpleGetter) { // data('key') + // don't force creation of expandoStore if it doesn't exist yet + return data && data[key]; + } else { // mass-setter: data({key1: val1, key2: val2}) + extend(data, key); + } + } + } + } +} + +function jqLiteHasClass(element, selector) { + if (!element.getAttribute) return false; + return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " "). + indexOf(" " + selector + " ") > -1); +} + +function jqLiteRemoveClass(element, cssClasses) { + if (cssClasses && element.setAttribute) { + forEach(cssClasses.split(' '), function(cssClass) { + element.setAttribute('class', trim( + (" " + (element.getAttribute('class') || '') + " ") + .replace(/[\n\t]/g, " ") + .replace(" " + trim(cssClass) + " ", " ")) + ); + }); + } +} + +function jqLiteAddClass(element, cssClasses) { + if (cssClasses && element.setAttribute) { + var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ') + .replace(/[\n\t]/g, " "); + + forEach(cssClasses.split(' '), function(cssClass) { + cssClass = trim(cssClass); + if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) { + existingClasses += cssClass + ' '; + } + }); + + element.setAttribute('class', trim(existingClasses)); + } +} + + +function jqLiteAddNodes(root, elements) { + // THIS CODE IS VERY HOT. Don't make changes without benchmarking. + + if (elements) { + + // if a Node (the most common case) + if (elements.nodeType) { + root[root.length++] = elements; + } else { + var length = elements.length; + + // if an Array or NodeList and not a Window + if (typeof length === 'number' && elements.window !== elements) { + if (length) { + for (var i = 0; i < length; i++) { + root[root.length++] = elements[i]; + } + } + } else { + root[root.length++] = elements; + } + } + } +} + + +function jqLiteController(element, name) { + return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller'); +} + +function jqLiteInheritedData(element, name, value) { + // if element is the document object work with the html element instead + // this makes $(document).scope() possible + if (element.nodeType == NODE_TYPE_DOCUMENT) { + element = element.documentElement; + } + var names = isArray(name) ? name : [name]; + + while (element) { + for (var i = 0, ii = names.length; i < ii; i++) { + if ((value = jqLite.data(element, names[i])) !== undefined) return value; + } + + // If dealing with a document fragment node with a host element, and no parent, use the host + // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM + // to lookup parent controllers. + element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host); + } +} + +function jqLiteEmpty(element) { + jqLiteDealoc(element, true); + while (element.firstChild) { + element.removeChild(element.firstChild); + } +} + +function jqLiteRemove(element, keepData) { + if (!keepData) jqLiteDealoc(element); + var parent = element.parentNode; + if (parent) parent.removeChild(element); +} + + +function jqLiteDocumentLoaded(action, win) { + win = win || window; + if (win.document.readyState === 'complete') { + // Force the action to be run async for consistent behaviour + // from the action's point of view + // i.e. it will definitely not be in a $apply + win.setTimeout(action); + } else { + // No need to unbind this handler as load is only ever called once + jqLite(win).on('load', action); + } +} + +////////////////////////////////////////// +// Functions which are declared directly. +////////////////////////////////////////// +var JQLitePrototype = JQLite.prototype = { + ready: function(fn) { + var fired = false; + + function trigger() { + if (fired) return; + fired = true; + fn(); + } + + // check if document is already loaded + if (document.readyState === 'complete') { + setTimeout(trigger); + } else { + this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9 + // we can not use jqLite since we are not done loading and jQuery could be loaded later. + // jshint -W064 + JQLite(window).on('load', trigger); // fallback to window.onload for others + // jshint +W064 + } + }, + toString: function() { + var value = []; + forEach(this, function(e) { value.push('' + e);}); + return '[' + value.join(', ') + ']'; + }, + + eq: function(index) { + return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]); + }, + + length: 0, + push: push, + sort: [].sort, + splice: [].splice +}; + +////////////////////////////////////////// +// Functions iterating getter/setters. +// these functions return self on setter and +// value on get. +////////////////////////////////////////// +var BOOLEAN_ATTR = {}; +forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) { + BOOLEAN_ATTR[lowercase(value)] = value; +}); +var BOOLEAN_ELEMENTS = {}; +forEach('input,select,option,textarea,button,form,details'.split(','), function(value) { + BOOLEAN_ELEMENTS[value] = true; +}); +var ALIASED_ATTR = { + 'ngMinlength': 'minlength', + 'ngMaxlength': 'maxlength', + 'ngMin': 'min', + 'ngMax': 'max', + 'ngPattern': 'pattern' +}; + +function getBooleanAttrName(element, name) { + // check dom last since we will most likely fail on name + var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()]; + + // booleanAttr is here twice to minimize DOM access + return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr; +} + +function getAliasedAttrName(element, name) { + var nodeName = element.nodeName; + return (nodeName === 'INPUT' || nodeName === 'TEXTAREA') && ALIASED_ATTR[name]; +} + +forEach({ + data: jqLiteData, + removeData: jqLiteRemoveData +}, function(fn, name) { + JQLite[name] = fn; +}); + +forEach({ + data: jqLiteData, + inheritedData: jqLiteInheritedData, + + scope: function(element) { + // Can't use jqLiteData here directly so we stay compatible with jQuery! + return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']); + }, + + isolateScope: function(element) { + // Can't use jqLiteData here directly so we stay compatible with jQuery! + return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate'); + }, + + controller: jqLiteController, + + injector: function(element) { + return jqLiteInheritedData(element, '$injector'); + }, + + removeAttr: function(element, name) { + element.removeAttribute(name); + }, + + hasClass: jqLiteHasClass, + + css: function(element, name, value) { + name = camelCase(name); + + if (isDefined(value)) { + element.style[name] = value; + } else { + return element.style[name]; + } + }, + + attr: function(element, name, value) { + var lowercasedName = lowercase(name); + if (BOOLEAN_ATTR[lowercasedName]) { + if (isDefined(value)) { + if (!!value) { + element[name] = true; + element.setAttribute(name, lowercasedName); + } else { + element[name] = false; + element.removeAttribute(lowercasedName); + } + } else { + return (element[name] || + (element.attributes.getNamedItem(name) || noop).specified) + ? lowercasedName + : undefined; + } + } else if (isDefined(value)) { + element.setAttribute(name, value); + } else if (element.getAttribute) { + // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code + // some elements (e.g. Document) don't have get attribute, so return undefined + var ret = element.getAttribute(name, 2); + // normalize non-existing attributes to undefined (as jQuery) + return ret === null ? undefined : ret; + } + }, + + prop: function(element, name, value) { + if (isDefined(value)) { + element[name] = value; + } else { + return element[name]; + } + }, + + text: (function() { + getText.$dv = ''; + return getText; + + function getText(element, value) { + if (isUndefined(value)) { + var nodeType = element.nodeType; + return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : ''; + } + element.textContent = value; + } + })(), + + val: function(element, value) { + if (isUndefined(value)) { + if (element.multiple && nodeName_(element) === 'select') { + var result = []; + forEach(element.options, function(option) { + if (option.selected) { + result.push(option.value || option.text); + } + }); + return result.length === 0 ? null : result; + } + return element.value; + } + element.value = value; + }, + + html: function(element, value) { + if (isUndefined(value)) { + return element.innerHTML; + } + jqLiteDealoc(element, true); + element.innerHTML = value; + }, + + empty: jqLiteEmpty +}, function(fn, name) { + /** + * Properties: writes return selection, reads return first value + */ + JQLite.prototype[name] = function(arg1, arg2) { + var i, key; + var nodeCount = this.length; + + // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it + // in a way that survives minification. + // jqLiteEmpty takes no arguments but is a setter. + if (fn !== jqLiteEmpty && + (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) { + if (isObject(arg1)) { + + // we are a write, but the object properties are the key/values + for (i = 0; i < nodeCount; i++) { + if (fn === jqLiteData) { + // data() takes the whole object in jQuery + fn(this[i], arg1); + } else { + for (key in arg1) { + fn(this[i], key, arg1[key]); + } + } + } + // return self for chaining + return this; + } else { + // we are a read, so read the first child. + // TODO: do we still need this? + var value = fn.$dv; + // Only if we have $dv do we iterate over all, otherwise it is just the first element. + var jj = (value === undefined) ? Math.min(nodeCount, 1) : nodeCount; + for (var j = 0; j < jj; j++) { + var nodeValue = fn(this[j], arg1, arg2); + value = value ? value + nodeValue : nodeValue; + } + return value; + } + } else { + // we are a write, so apply to all children + for (i = 0; i < nodeCount; i++) { + fn(this[i], arg1, arg2); + } + // return self for chaining + return this; + } + }; +}); + +function createEventHandler(element, events) { + var eventHandler = function(event, type) { + // jQuery specific api + event.isDefaultPrevented = function() { + return event.defaultPrevented; + }; + + var eventFns = events[type || event.type]; + var eventFnsLength = eventFns ? eventFns.length : 0; + + if (!eventFnsLength) return; + + if (isUndefined(event.immediatePropagationStopped)) { + var originalStopImmediatePropagation = event.stopImmediatePropagation; + event.stopImmediatePropagation = function() { + event.immediatePropagationStopped = true; + + if (event.stopPropagation) { + event.stopPropagation(); + } + + if (originalStopImmediatePropagation) { + originalStopImmediatePropagation.call(event); + } + }; + } + + event.isImmediatePropagationStopped = function() { + return event.immediatePropagationStopped === true; + }; + + // Copy event handlers in case event handlers array is modified during execution. + if ((eventFnsLength > 1)) { + eventFns = shallowCopy(eventFns); + } + + for (var i = 0; i < eventFnsLength; i++) { + if (!event.isImmediatePropagationStopped()) { + eventFns[i].call(element, event); + } + } + }; + + // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all + // events on `element` + eventHandler.elem = element; + return eventHandler; +} + +////////////////////////////////////////// +// Functions iterating traversal. +// These functions chain results into a single +// selector. +////////////////////////////////////////// +forEach({ + removeData: jqLiteRemoveData, + + on: function jqLiteOn(element, type, fn, unsupported) { + if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters'); + + // Do not add event handlers to non-elements because they will not be cleaned up. + if (!jqLiteAcceptsData(element)) { + return; + } + + var expandoStore = jqLiteExpandoStore(element, true); + var events = expandoStore.events; + var handle = expandoStore.handle; + + if (!handle) { + handle = expandoStore.handle = createEventHandler(element, events); + } + + // http://jsperf.com/string-indexof-vs-split + var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type]; + var i = types.length; + + while (i--) { + type = types[i]; + var eventFns = events[type]; + + if (!eventFns) { + events[type] = []; + + if (type === 'mouseenter' || type === 'mouseleave') { + // Refer to jQuery's implementation of mouseenter & mouseleave + // Read about mouseenter and mouseleave: + // http://www.quirksmode.org/js/events_mouse.html#link8 + + jqLiteOn(element, MOUSE_EVENT_MAP[type], function(event) { + var target = this, related = event.relatedTarget; + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if (!related || (related !== target && !target.contains(related))) { + handle(event, type); + } + }); + + } else { + if (type !== '$destroy') { + addEventListenerFn(element, type, handle); + } + } + eventFns = events[type]; + } + eventFns.push(fn); + } + }, + + off: jqLiteOff, + + one: function(element, type, fn) { + element = jqLite(element); + + //add the listener twice so that when it is called + //you can remove the original function and still be + //able to call element.off(ev, fn) normally + element.on(type, function onFn() { + element.off(type, fn); + element.off(type, onFn); + }); + element.on(type, fn); + }, + + replaceWith: function(element, replaceNode) { + var index, parent = element.parentNode; + jqLiteDealoc(element); + forEach(new JQLite(replaceNode), function(node) { + if (index) { + parent.insertBefore(node, index.nextSibling); + } else { + parent.replaceChild(node, element); + } + index = node; + }); + }, + + children: function(element) { + var children = []; + forEach(element.childNodes, function(element) { + if (element.nodeType === NODE_TYPE_ELEMENT) + children.push(element); + }); + return children; + }, + + contents: function(element) { + return element.contentDocument || element.childNodes || []; + }, + + append: function(element, node) { + var nodeType = element.nodeType; + if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return; + + node = new JQLite(node); + + for (var i = 0, ii = node.length; i < ii; i++) { + var child = node[i]; + element.appendChild(child); + } + }, + + prepend: function(element, node) { + if (element.nodeType === NODE_TYPE_ELEMENT) { + var index = element.firstChild; + forEach(new JQLite(node), function(child) { + element.insertBefore(child, index); + }); + } + }, + + wrap: function(element, wrapNode) { + wrapNode = jqLite(wrapNode).eq(0).clone()[0]; + var parent = element.parentNode; + if (parent) { + parent.replaceChild(wrapNode, element); + } + wrapNode.appendChild(element); + }, + + remove: jqLiteRemove, + + detach: function(element) { + jqLiteRemove(element, true); + }, + + after: function(element, newElement) { + var index = element, parent = element.parentNode; + newElement = new JQLite(newElement); + + for (var i = 0, ii = newElement.length; i < ii; i++) { + var node = newElement[i]; + parent.insertBefore(node, index.nextSibling); + index = node; + } + }, + + addClass: jqLiteAddClass, + removeClass: jqLiteRemoveClass, + + toggleClass: function(element, selector, condition) { + if (selector) { + forEach(selector.split(' '), function(className) { + var classCondition = condition; + if (isUndefined(classCondition)) { + classCondition = !jqLiteHasClass(element, className); + } + (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className); + }); + } + }, + + parent: function(element) { + var parent = element.parentNode; + return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null; + }, + + next: function(element) { + return element.nextElementSibling; + }, + + find: function(element, selector) { + if (element.getElementsByTagName) { + return element.getElementsByTagName(selector); + } else { + return []; + } + }, + + clone: jqLiteClone, + + triggerHandler: function(element, event, extraParameters) { + + var dummyEvent, eventFnsCopy, handlerArgs; + var eventName = event.type || event; + var expandoStore = jqLiteExpandoStore(element); + var events = expandoStore && expandoStore.events; + var eventFns = events && events[eventName]; + + if (eventFns) { + // Create a dummy event to pass to the handlers + dummyEvent = { + preventDefault: function() { this.defaultPrevented = true; }, + isDefaultPrevented: function() { return this.defaultPrevented === true; }, + stopImmediatePropagation: function() { this.immediatePropagationStopped = true; }, + isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; }, + stopPropagation: noop, + type: eventName, + target: element + }; + + // If a custom event was provided then extend our dummy event with it + if (event.type) { + dummyEvent = extend(dummyEvent, event); + } + + // Copy event handlers in case event handlers array is modified during execution. + eventFnsCopy = shallowCopy(eventFns); + handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent]; + + forEach(eventFnsCopy, function(fn) { + if (!dummyEvent.isImmediatePropagationStopped()) { + fn.apply(element, handlerArgs); + } + }); + } + } +}, function(fn, name) { + /** + * chaining functions + */ + JQLite.prototype[name] = function(arg1, arg2, arg3) { + var value; + + for (var i = 0, ii = this.length; i < ii; i++) { + if (isUndefined(value)) { + value = fn(this[i], arg1, arg2, arg3); + if (isDefined(value)) { + // any function which returns a value needs to be wrapped + value = jqLite(value); + } + } else { + jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3)); + } + } + return isDefined(value) ? value : this; + }; + + // bind legacy bind/unbind to on/off + JQLite.prototype.bind = JQLite.prototype.on; + JQLite.prototype.unbind = JQLite.prototype.off; +}); + + +// Provider for private $$jqLite service +function $$jqLiteProvider() { + this.$get = function $$jqLite() { + return extend(JQLite, { + hasClass: function(node, classes) { + if (node.attr) node = node[0]; + return jqLiteHasClass(node, classes); + }, + addClass: function(node, classes) { + if (node.attr) node = node[0]; + return jqLiteAddClass(node, classes); + }, + removeClass: function(node, classes) { + if (node.attr) node = node[0]; + return jqLiteRemoveClass(node, classes); + } + }); + }; +} + +/** + * Computes a hash of an 'obj'. + * Hash of a: + * string is string + * number is number as string + * object is either result of calling $$hashKey function on the object or uniquely generated id, + * that is also assigned to the $$hashKey property of the object. + * + * @param obj + * @returns {string} hash string such that the same input will have the same hash string. + * The resulting string key is in 'type:hashKey' format. + */ +function hashKey(obj, nextUidFn) { + var key = obj && obj.$$hashKey; + + if (key) { + if (typeof key === 'function') { + key = obj.$$hashKey(); + } + return key; + } + + var objType = typeof obj; + if (objType == 'function' || (objType == 'object' && obj !== null)) { + key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)(); + } else { + key = objType + ':' + obj; + } + + return key; +} + +/** + * HashMap which can use objects as keys + */ +function HashMap(array, isolatedUid) { + if (isolatedUid) { + var uid = 0; + this.nextUid = function() { + return ++uid; + }; + } + forEach(array, this.put, this); +} +HashMap.prototype = { + /** + * Store key value pair + * @param key key to store can be any type + * @param value value to store can be any type + */ + put: function(key, value) { + this[hashKey(key, this.nextUid)] = value; + }, + + /** + * @param key + * @returns {Object} the value for the key + */ + get: function(key) { + return this[hashKey(key, this.nextUid)]; + }, + + /** + * Remove the key/value pair + * @param key + */ + remove: function(key) { + var value = this[key = hashKey(key, this.nextUid)]; + delete this[key]; + return value; + } +}; + +/** + * @ngdoc function + * @module ng + * @name angular.injector + * @kind function + * + * @description + * Creates an injector object that can be used for retrieving services as well as for + * dependency injection (see {@link guide/di dependency injection}). + * + * @param {Array.} modules A list of module functions or their aliases. See + * {@link angular.module}. The `ng` module must be explicitly added. + * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which + * disallows argument name annotation inference. + * @returns {injector} Injector object. See {@link auto.$injector $injector}. + * + * @example + * Typical usage + * ```js + * // create an injector + * var $injector = angular.injector(['ng']); + * + * // use the injector to kick off your application + * // use the type inference to auto inject arguments, or use implicit injection + * $injector.invoke(function($rootScope, $compile, $document) { + * $compile($document)($rootScope); + * $rootScope.$digest(); + * }); + * ``` + * + * Sometimes you want to get access to the injector of a currently running Angular app + * from outside Angular. Perhaps, you want to inject and compile some markup after the + * application has been bootstrapped. You can do this using the extra `injector()` added + * to JQuery/jqLite elements. See {@link angular.element}. + * + * *This is fairly rare but could be the case if a third party library is injecting the + * markup.* + * + * In the following example a new block of HTML containing a `ng-controller` + * directive is added to the end of the document body by JQuery. We then compile and link + * it into the current AngularJS scope. + * + * ```js + * var $div = $('
    {{content.label}}
    '); + * $(document.body).append($div); + * + * angular.element(document).injector().invoke(function($compile) { + * var scope = angular.element($div).scope(); + * $compile($div)(scope); + * }); + * ``` + */ + + +/** + * @ngdoc module + * @name auto + * @description + * + * Implicit module which gets automatically added to each {@link auto.$injector $injector}. + */ + +var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m; +var FN_ARG_SPLIT = /,/; +var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/; +var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; +var $injectorMinErr = minErr('$injector'); + +function anonFn(fn) { + // For anonymous functions, showing at the very least the function signature can help in + // debugging. + var fnText = fn.toString().replace(STRIP_COMMENTS, ''), + args = fnText.match(FN_ARGS); + if (args) { + return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')'; + } + return 'fn'; +} + +function annotate(fn, strictDi, name) { + var $inject, + fnText, + argDecl, + last; + + if (typeof fn === 'function') { + if (!($inject = fn.$inject)) { + $inject = []; + if (fn.length) { + if (strictDi) { + if (!isString(name) || !name) { + name = fn.name || anonFn(fn); + } + throw $injectorMinErr('strictdi', + '{0} is not using explicit annotation and cannot be invoked in strict mode', name); + } + fnText = fn.toString().replace(STRIP_COMMENTS, ''); + argDecl = fnText.match(FN_ARGS); + forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) { + arg.replace(FN_ARG, function(all, underscore, name) { + $inject.push(name); + }); + }); + } + fn.$inject = $inject; + } + } else if (isArray(fn)) { + last = fn.length - 1; + assertArgFn(fn[last], 'fn'); + $inject = fn.slice(0, last); + } else { + assertArgFn(fn, 'fn', true); + } + return $inject; +} + +/////////////////////////////////////// + +/** + * @ngdoc service + * @name $injector + * + * @description + * + * `$injector` is used to retrieve object instances as defined by + * {@link auto.$provide provider}, instantiate types, invoke methods, + * and load modules. + * + * The following always holds true: + * + * ```js + * var $injector = angular.injector(); + * expect($injector.get('$injector')).toBe($injector); + * expect($injector.invoke(function($injector) { + * return $injector; + * })).toBe($injector); + * ``` + * + * # Injection Function Annotation + * + * JavaScript does not have annotations, and annotations are needed for dependency injection. The + * following are all valid ways of annotating function with injection arguments and are equivalent. + * + * ```js + * // inferred (only works if code not minified/obfuscated) + * $injector.invoke(function(serviceA){}); + * + * // annotated + * function explicit(serviceA) {}; + * explicit.$inject = ['serviceA']; + * $injector.invoke(explicit); + * + * // inline + * $injector.invoke(['serviceA', function(serviceA){}]); + * ``` + * + * ## Inference + * + * In JavaScript calling `toString()` on a function returns the function definition. The definition + * can then be parsed and the function arguments can be extracted. This method of discovering + * annotations is disallowed when the injector is in strict mode. + * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the + * argument names. + * + * ## `$inject` Annotation + * By adding an `$inject` property onto a function the injection parameters can be specified. + * + * ## Inline + * As an array of injection names, where the last item in the array is the function to call. + */ + +/** + * @ngdoc method + * @name $injector#get + * + * @description + * Return an instance of the service. + * + * @param {string} name The name of the instance to retrieve. + * @param {string} caller An optional string to provide the origin of the function call for error messages. + * @return {*} The instance. + */ + +/** + * @ngdoc method + * @name $injector#invoke + * + * @description + * Invoke the method and supply the method arguments from the `$injector`. + * + * @param {!Function} fn The function to invoke. Function parameters are injected according to the + * {@link guide/di $inject Annotation} rules. + * @param {Object=} self The `this` for the invoked method. + * @param {Object=} locals Optional object. If preset then any argument names are read from this + * object first, before the `$injector` is consulted. + * @returns {*} the value returned by the invoked `fn` function. + */ + +/** + * @ngdoc method + * @name $injector#has + * + * @description + * Allows the user to query if the particular service exists. + * + * @param {string} name Name of the service to query. + * @returns {boolean} `true` if injector has given service. + */ + +/** + * @ngdoc method + * @name $injector#instantiate + * @description + * Create a new instance of JS type. The method takes a constructor function, invokes the new + * operator, and supplies all of the arguments to the constructor function as specified by the + * constructor annotation. + * + * @param {Function} Type Annotated constructor function. + * @param {Object=} locals Optional object. If preset then any argument names are read from this + * object first, before the `$injector` is consulted. + * @returns {Object} new instance of `Type`. + */ + +/** + * @ngdoc method + * @name $injector#annotate + * + * @description + * Returns an array of service names which the function is requesting for injection. This API is + * used by the injector to determine which services need to be injected into the function when the + * function is invoked. There are three ways in which the function can be annotated with the needed + * dependencies. + * + * # Argument names + * + * The simplest form is to extract the dependencies from the arguments of the function. This is done + * by converting the function into a string using `toString()` method and extracting the argument + * names. + * ```js + * // Given + * function MyController($scope, $route) { + * // ... + * } + * + * // Then + * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']); + * ``` + * + * You can disallow this method by using strict injection mode. + * + * This method does not work with code minification / obfuscation. For this reason the following + * annotation strategies are supported. + * + * # The `$inject` property + * + * If a function has an `$inject` property and its value is an array of strings, then the strings + * represent names of services to be injected into the function. + * ```js + * // Given + * var MyController = function(obfuscatedScope, obfuscatedRoute) { + * // ... + * } + * // Define function dependencies + * MyController['$inject'] = ['$scope', '$route']; + * + * // Then + * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']); + * ``` + * + * # The array notation + * + * It is often desirable to inline Injected functions and that's when setting the `$inject` property + * is very inconvenient. In these situations using the array notation to specify the dependencies in + * a way that survives minification is a better choice: + * + * ```js + * // We wish to write this (not minification / obfuscation safe) + * injector.invoke(function($compile, $rootScope) { + * // ... + * }); + * + * // We are forced to write break inlining + * var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) { + * // ... + * }; + * tmpFn.$inject = ['$compile', '$rootScope']; + * injector.invoke(tmpFn); + * + * // To better support inline function the inline annotation is supported + * injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) { + * // ... + * }]); + * + * // Therefore + * expect(injector.annotate( + * ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}]) + * ).toEqual(['$compile', '$rootScope']); + * ``` + * + * @param {Function|Array.} fn Function for which dependent service names need to + * be retrieved as described above. + * + * @param {boolean=} [strictDi=false] Disallow argument name annotation inference. + * + * @returns {Array.} The names of the services which the function requires. + */ + + + + +/** + * @ngdoc service + * @name $provide + * + * @description + * + * The {@link auto.$provide $provide} service has a number of methods for registering components + * with the {@link auto.$injector $injector}. Many of these functions are also exposed on + * {@link angular.Module}. + * + * An Angular **service** is a singleton object created by a **service factory**. These **service + * factories** are functions which, in turn, are created by a **service provider**. + * The **service providers** are constructor functions. When instantiated they must contain a + * property called `$get`, which holds the **service factory** function. + * + * When you request a service, the {@link auto.$injector $injector} is responsible for finding the + * correct **service provider**, instantiating it and then calling its `$get` **service factory** + * function to get the instance of the **service**. + * + * Often services have no configuration options and there is no need to add methods to the service + * provider. The provider will be no more than a constructor function with a `$get` property. For + * these cases the {@link auto.$provide $provide} service has additional helper methods to register + * services without specifying a provider. + * + * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the + * {@link auto.$injector $injector} + * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by + * providers and services. + * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by + * services, not providers. + * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`, + * that will be wrapped in a **service provider** object, whose `$get` property will contain the + * given factory function. + * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class` + * that will be wrapped in a **service provider** object, whose `$get` property will instantiate + * a new object using the given constructor function. + * + * See the individual methods for more information and examples. + */ + +/** + * @ngdoc method + * @name $provide#provider + * @description + * + * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions + * are constructor functions, whose instances are responsible for "providing" a factory for a + * service. + * + * Service provider names start with the name of the service they provide followed by `Provider`. + * For example, the {@link ng.$log $log} service has a provider called + * {@link ng.$logProvider $logProvider}. + * + * Service provider objects can have additional methods which allow configuration of the provider + * and its service. Importantly, you can configure what kind of service is created by the `$get` + * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a + * method {@link ng.$logProvider#debugEnabled debugEnabled} + * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the + * console or not. + * + * @param {string} name The name of the instance. NOTE: the provider will be available under `name + + 'Provider'` key. + * @param {(Object|function())} provider If the provider is: + * + * - `Object`: then it should have a `$get` method. The `$get` method will be invoked using + * {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created. + * - `Constructor`: a new instance of the provider will be created using + * {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`. + * + * @returns {Object} registered provider instance + + * @example + * + * The following example shows how to create a simple event tracking service and register it using + * {@link auto.$provide#provider $provide.provider()}. + * + * ```js + * // Define the eventTracker provider + * function EventTrackerProvider() { + * var trackingUrl = '/track'; + * + * // A provider method for configuring where the tracked events should been saved + * this.setTrackingUrl = function(url) { + * trackingUrl = url; + * }; + * + * // The service factory function + * this.$get = ['$http', function($http) { + * var trackedEvents = {}; + * return { + * // Call this to track an event + * event: function(event) { + * var count = trackedEvents[event] || 0; + * count += 1; + * trackedEvents[event] = count; + * return count; + * }, + * // Call this to save the tracked events to the trackingUrl + * save: function() { + * $http.post(trackingUrl, trackedEvents); + * } + * }; + * }]; + * } + * + * describe('eventTracker', function() { + * var postSpy; + * + * beforeEach(module(function($provide) { + * // Register the eventTracker provider + * $provide.provider('eventTracker', EventTrackerProvider); + * })); + * + * beforeEach(module(function(eventTrackerProvider) { + * // Configure eventTracker provider + * eventTrackerProvider.setTrackingUrl('/custom-track'); + * })); + * + * it('tracks events', inject(function(eventTracker) { + * expect(eventTracker.event('login')).toEqual(1); + * expect(eventTracker.event('login')).toEqual(2); + * })); + * + * it('saves to the tracking url', inject(function(eventTracker, $http) { + * postSpy = spyOn($http, 'post'); + * eventTracker.event('login'); + * eventTracker.save(); + * expect(postSpy).toHaveBeenCalled(); + * expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track'); + * expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track'); + * expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 }); + * })); + * }); + * ``` + */ + +/** + * @ngdoc method + * @name $provide#factory + * @description + * + * Register a **service factory**, which will be called to return the service instance. + * This is short for registering a service where its provider consists of only a `$get` property, + * which is the given service factory function. + * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to + * configure your service in a provider. + * + * @param {string} name The name of the instance. + * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand + * for `$provide.provider(name, {$get: $getFn})`. + * @returns {Object} registered provider instance + * + * @example + * Here is an example of registering a service + * ```js + * $provide.factory('ping', ['$http', function($http) { + * return function ping() { + * return $http.send('/ping'); + * }; + * }]); + * ``` + * You would then inject and use this service like this: + * ```js + * someModule.controller('Ctrl', ['ping', function(ping) { + * ping(); + * }]); + * ``` + */ + + +/** + * @ngdoc method + * @name $provide#service + * @description + * + * Register a **service constructor**, which will be invoked with `new` to create the service + * instance. + * This is short for registering a service where its provider's `$get` property is the service + * constructor function that will be used to instantiate the service instance. + * + * You should use {@link auto.$provide#service $provide.service(class)} if you define your service + * as a type/class. + * + * @param {string} name The name of the instance. + * @param {Function} constructor A class (constructor function) that will be instantiated. + * @returns {Object} registered provider instance + * + * @example + * Here is an example of registering a service using + * {@link auto.$provide#service $provide.service(class)}. + * ```js + * var Ping = function($http) { + * this.$http = $http; + * }; + * + * Ping.$inject = ['$http']; + * + * Ping.prototype.send = function() { + * return this.$http.get('/ping'); + * }; + * $provide.service('ping', Ping); + * ``` + * You would then inject and use this service like this: + * ```js + * someModule.controller('Ctrl', ['ping', function(ping) { + * ping.send(); + * }]); + * ``` + */ + + +/** + * @ngdoc method + * @name $provide#value + * @description + * + * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a + * number, an array, an object or a function. This is short for registering a service where its + * provider's `$get` property is a factory function that takes no arguments and returns the **value + * service**. + * + * Value services are similar to constant services, except that they cannot be injected into a + * module configuration function (see {@link angular.Module#config}) but they can be overridden by + * an Angular + * {@link auto.$provide#decorator decorator}. + * + * @param {string} name The name of the instance. + * @param {*} value The value. + * @returns {Object} registered provider instance + * + * @example + * Here are some examples of creating value services. + * ```js + * $provide.value('ADMIN_USER', 'admin'); + * + * $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 }); + * + * $provide.value('halfOf', function(value) { + * return value / 2; + * }); + * ``` + */ + + +/** + * @ngdoc method + * @name $provide#constant + * @description + * + * Register a **constant service**, such as a string, a number, an array, an object or a function, + * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be + * injected into a module configuration function (see {@link angular.Module#config}) and it cannot + * be overridden by an Angular {@link auto.$provide#decorator decorator}. + * + * @param {string} name The name of the constant. + * @param {*} value The constant value. + * @returns {Object} registered instance + * + * @example + * Here a some examples of creating constants: + * ```js + * $provide.constant('SHARD_HEIGHT', 306); + * + * $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']); + * + * $provide.constant('double', function(value) { + * return value * 2; + * }); + * ``` + */ + + +/** + * @ngdoc method + * @name $provide#decorator + * @description + * + * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator + * intercepts the creation of a service, allowing it to override or modify the behaviour of the + * service. The object returned by the decorator may be the original service, or a new service + * object which replaces or wraps and delegates to the original service. + * + * @param {string} name The name of the service to decorate. + * @param {function()} decorator This function will be invoked when the service needs to be + * instantiated and should return the decorated service instance. The function is called using + * the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable. + * Local injection arguments: + * + * * `$delegate` - The original service instance, which can be monkey patched, configured, + * decorated or delegated to. + * + * @example + * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting + * calls to {@link ng.$log#error $log.warn()}. + * ```js + * $provide.decorator('$log', ['$delegate', function($delegate) { + * $delegate.warn = $delegate.error; + * return $delegate; + * }]); + * ``` + */ + + +function createInjector(modulesToLoad, strictDi) { + strictDi = (strictDi === true); + var INSTANTIATING = {}, + providerSuffix = 'Provider', + path = [], + loadedModules = new HashMap([], true), + providerCache = { + $provide: { + provider: supportObject(provider), + factory: supportObject(factory), + service: supportObject(service), + value: supportObject(value), + constant: supportObject(constant), + decorator: decorator + } + }, + providerInjector = (providerCache.$injector = + createInternalInjector(providerCache, function(serviceName, caller) { + if (angular.isString(caller)) { + path.push(caller); + } + throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- ')); + })), + instanceCache = {}, + instanceInjector = (instanceCache.$injector = + createInternalInjector(instanceCache, function(serviceName, caller) { + var provider = providerInjector.get(serviceName + providerSuffix, caller); + return instanceInjector.invoke(provider.$get, provider, undefined, serviceName); + })); + + + forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); }); + + return instanceInjector; + + //////////////////////////////////// + // $provider + //////////////////////////////////// + + function supportObject(delegate) { + return function(key, value) { + if (isObject(key)) { + forEach(key, reverseParams(delegate)); + } else { + return delegate(key, value); + } + }; + } + + function provider(name, provider_) { + assertNotHasOwnProperty(name, 'service'); + if (isFunction(provider_) || isArray(provider_)) { + provider_ = providerInjector.instantiate(provider_); + } + if (!provider_.$get) { + throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name); + } + return providerCache[name + providerSuffix] = provider_; + } + + function enforceReturnValue(name, factory) { + return function enforcedReturnValue() { + var result = instanceInjector.invoke(factory, this); + if (isUndefined(result)) { + throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name); + } + return result; + }; + } + + function factory(name, factoryFn, enforce) { + return provider(name, { + $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn + }); + } + + function service(name, constructor) { + return factory(name, ['$injector', function($injector) { + return $injector.instantiate(constructor); + }]); + } + + function value(name, val) { return factory(name, valueFn(val), false); } + + function constant(name, value) { + assertNotHasOwnProperty(name, 'constant'); + providerCache[name] = value; + instanceCache[name] = value; + } + + function decorator(serviceName, decorFn) { + var origProvider = providerInjector.get(serviceName + providerSuffix), + orig$get = origProvider.$get; + + origProvider.$get = function() { + var origInstance = instanceInjector.invoke(orig$get, origProvider); + return instanceInjector.invoke(decorFn, null, {$delegate: origInstance}); + }; + } + + //////////////////////////////////// + // Module Loading + //////////////////////////////////// + function loadModules(modulesToLoad) { + var runBlocks = [], moduleFn; + forEach(modulesToLoad, function(module) { + if (loadedModules.get(module)) return; + loadedModules.put(module, true); + + function runInvokeQueue(queue) { + var i, ii; + for (i = 0, ii = queue.length; i < ii; i++) { + var invokeArgs = queue[i], + provider = providerInjector.get(invokeArgs[0]); + + provider[invokeArgs[1]].apply(provider, invokeArgs[2]); + } + } + + try { + if (isString(module)) { + moduleFn = angularModule(module); + runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks); + runInvokeQueue(moduleFn._invokeQueue); + runInvokeQueue(moduleFn._configBlocks); + } else if (isFunction(module)) { + runBlocks.push(providerInjector.invoke(module)); + } else if (isArray(module)) { + runBlocks.push(providerInjector.invoke(module)); + } else { + assertArgFn(module, 'module'); + } + } catch (e) { + if (isArray(module)) { + module = module[module.length - 1]; + } + if (e.message && e.stack && e.stack.indexOf(e.message) == -1) { + // Safari & FF's stack traces don't contain error.message content + // unlike those of Chrome and IE + // So if stack doesn't contain message, we create a new string that contains both. + // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here. + /* jshint -W022 */ + e = e.message + '\n' + e.stack; + } + throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}", + module, e.stack || e.message || e); + } + }); + return runBlocks; + } + + //////////////////////////////////// + // internal Injector + //////////////////////////////////// + + function createInternalInjector(cache, factory) { + + function getService(serviceName, caller) { + if (cache.hasOwnProperty(serviceName)) { + if (cache[serviceName] === INSTANTIATING) { + throw $injectorMinErr('cdep', 'Circular dependency found: {0}', + serviceName + ' <- ' + path.join(' <- ')); + } + return cache[serviceName]; + } else { + try { + path.unshift(serviceName); + cache[serviceName] = INSTANTIATING; + return cache[serviceName] = factory(serviceName, caller); + } catch (err) { + if (cache[serviceName] === INSTANTIATING) { + delete cache[serviceName]; + } + throw err; + } finally { + path.shift(); + } + } + } + + function invoke(fn, self, locals, serviceName) { + if (typeof locals === 'string') { + serviceName = locals; + locals = null; + } + + var args = [], + $inject = createInjector.$$annotate(fn, strictDi, serviceName), + length, i, + key; + + for (i = 0, length = $inject.length; i < length; i++) { + key = $inject[i]; + if (typeof key !== 'string') { + throw $injectorMinErr('itkn', + 'Incorrect injection token! Expected service name as string, got {0}', key); + } + args.push( + locals && locals.hasOwnProperty(key) + ? locals[key] + : getService(key, serviceName) + ); + } + if (isArray(fn)) { + fn = fn[length]; + } + + // http://jsperf.com/angularjs-invoke-apply-vs-switch + // #5388 + return fn.apply(self, args); + } + + function instantiate(Type, locals, serviceName) { + // Check if Type is annotated and use just the given function at n-1 as parameter + // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]); + // Object creation: http://jsperf.com/create-constructor/2 + var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null); + var returnedValue = invoke(Type, instance, locals, serviceName); + + return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance; + } + + return { + invoke: invoke, + instantiate: instantiate, + get: getService, + annotate: createInjector.$$annotate, + has: function(name) { + return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name); + } + }; + } +} + +createInjector.$$annotate = annotate; + +/** + * @ngdoc provider + * @name $anchorScrollProvider + * + * @description + * Use `$anchorScrollProvider` to disable automatic scrolling whenever + * {@link ng.$location#hash $location.hash()} changes. + */ +function $AnchorScrollProvider() { + + var autoScrollingEnabled = true; + + /** + * @ngdoc method + * @name $anchorScrollProvider#disableAutoScrolling + * + * @description + * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to + * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.
    + * Use this method to disable automatic scrolling. + * + * If automatic scrolling is disabled, one must explicitly call + * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the + * current hash. + */ + this.disableAutoScrolling = function() { + autoScrollingEnabled = false; + }; + + /** + * @ngdoc service + * @name $anchorScroll + * @kind function + * @requires $window + * @requires $location + * @requires $rootScope + * + * @description + * When called, it checks the current value of {@link ng.$location#hash $location.hash()} and + * scrolls to the related element, according to the rules specified in the + * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document). + * + * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to + * match any anchor whenever it changes. This can be disabled by calling + * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}. + * + * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a + * vertical scroll-offset (either fixed or dynamic). + * + * @property {(number|function|jqLite)} yOffset + * If set, specifies a vertical scroll-offset. This is often useful when there are fixed + * positioned elements at the top of the page, such as navbars, headers etc. + * + * `yOffset` can be specified in various ways: + * - **number**: A fixed number of pixels to be used as offset.

    + * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return + * a number representing the offset (in pixels).

    + * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from + * the top of the page to the element's bottom will be used as offset.
    + * **Note**: The element will be taken into account only as long as its `position` is set to + * `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust + * their height and/or positioning according to the viewport's size. + * + *
    + *
    + * In order for `yOffset` to work properly, scrolling should take place on the document's root and + * not some child element. + *
    + * + * @example + + +
    + Go to bottom + You're at the bottom! +
    +
    + + angular.module('anchorScrollExample', []) + .controller('ScrollController', ['$scope', '$location', '$anchorScroll', + function ($scope, $location, $anchorScroll) { + $scope.gotoBottom = function() { + // set the location.hash to the id of + // the element you wish to scroll to. + $location.hash('bottom'); + + // call $anchorScroll() + $anchorScroll(); + }; + }]); + + + #scrollArea { + height: 280px; + overflow: auto; + } + + #bottom { + display: block; + margin-top: 2000px; + } + +
    + * + *
    + * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value). + * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details. + * + * @example + + + +
    + Anchor {{x}} of 5 +
    +
    + + angular.module('anchorScrollOffsetExample', []) + .run(['$anchorScroll', function($anchorScroll) { + $anchorScroll.yOffset = 50; // always scroll by 50 extra pixels + }]) + .controller('headerCtrl', ['$anchorScroll', '$location', '$scope', + function ($anchorScroll, $location, $scope) { + $scope.gotoAnchor = function(x) { + var newHash = 'anchor' + x; + if ($location.hash() !== newHash) { + // set the $location.hash to `newHash` and + // $anchorScroll will automatically scroll to it + $location.hash('anchor' + x); + } else { + // call $anchorScroll() explicitly, + // since $location.hash hasn't changed + $anchorScroll(); + } + }; + } + ]); + + + body { + padding-top: 50px; + } + + .anchor { + border: 2px dashed DarkOrchid; + padding: 10px 10px 200px 10px; + } + + .fixed-header { + background-color: rgba(0, 0, 0, 0.2); + height: 50px; + position: fixed; + top: 0; left: 0; right: 0; + } + + .fixed-header > a { + display: inline-block; + margin: 5px 15px; + } + +
    + */ + this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) { + var document = $window.document; + + // Helper function to get first anchor from a NodeList + // (using `Array#some()` instead of `angular#forEach()` since it's more performant + // and working in all supported browsers.) + function getFirstAnchor(list) { + var result = null; + Array.prototype.some.call(list, function(element) { + if (nodeName_(element) === 'a') { + result = element; + return true; + } + }); + return result; + } + + function getYOffset() { + + var offset = scroll.yOffset; + + if (isFunction(offset)) { + offset = offset(); + } else if (isElement(offset)) { + var elem = offset[0]; + var style = $window.getComputedStyle(elem); + if (style.position !== 'fixed') { + offset = 0; + } else { + offset = elem.getBoundingClientRect().bottom; + } + } else if (!isNumber(offset)) { + offset = 0; + } + + return offset; + } + + function scrollTo(elem) { + if (elem) { + elem.scrollIntoView(); + + var offset = getYOffset(); + + if (offset) { + // `offset` is the number of pixels we should scroll UP in order to align `elem` properly. + // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the + // top of the viewport. + // + // IF the number of pixels from the top of `elem` to the end of the page's content is less + // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some + // way down the page. + // + // This is often the case for elements near the bottom of the page. + // + // In such cases we do not need to scroll the whole `offset` up, just the difference between + // the top of the element and the offset, which is enough to align the top of `elem` at the + // desired position. + var elemTop = elem.getBoundingClientRect().top; + $window.scrollBy(0, elemTop - offset); + } + } else { + $window.scrollTo(0, 0); + } + } + + function scroll() { + var hash = $location.hash(), elm; + + // empty hash, scroll to the top of the page + if (!hash) scrollTo(null); + + // element with given id + else if ((elm = document.getElementById(hash))) scrollTo(elm); + + // first anchor with given name :-D + else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm); + + // no element and hash == 'top', scroll to the top of the page + else if (hash === 'top') scrollTo(null); + } + + // does not scroll when user clicks on anchor link that is currently on + // (no url change, no $location.hash() change), browser native does scroll + if (autoScrollingEnabled) { + $rootScope.$watch(function autoScrollWatch() {return $location.hash();}, + function autoScrollWatchAction(newVal, oldVal) { + // skip the initial scroll if $location.hash is empty + if (newVal === oldVal && newVal === '') return; + + jqLiteDocumentLoaded(function() { + $rootScope.$evalAsync(scroll); + }); + }); + } + + return scroll; + }]; +} + +var $animateMinErr = minErr('$animate'); + +/** + * @ngdoc provider + * @name $animateProvider + * + * @description + * Default implementation of $animate that doesn't perform any animations, instead just + * synchronously performs DOM + * updates and calls done() callbacks. + * + * In order to enable animations the ngAnimate module has to be loaded. + * + * To see the functional implementation check out src/ngAnimate/animate.js + */ +var $AnimateProvider = ['$provide', function($provide) { + + + this.$$selectors = {}; + + + /** + * @ngdoc method + * @name $animateProvider#register + * + * @description + * Registers a new injectable animation factory function. The factory function produces the + * animation object which contains callback functions for each event that is expected to be + * animated. + * + * * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction` + * must be called once the element animation is complete. If a function is returned then the + * animation service will use this function to cancel the animation whenever a cancel event is + * triggered. + * + * + * ```js + * return { + * eventFn : function(element, done) { + * //code to run the animation + * //once complete, then run done() + * return function cancellationFunction() { + * //code to cancel the animation + * } + * } + * } + * ``` + * + * @param {string} name The name of the animation. + * @param {Function} factory The factory function that will be executed to return the animation + * object. + */ + this.register = function(name, factory) { + var key = name + '-animation'; + if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel', + "Expecting class selector starting with '.' got '{0}'.", name); + this.$$selectors[name.substr(1)] = key; + $provide.factory(key, factory); + }; + + /** + * @ngdoc method + * @name $animateProvider#classNameFilter + * + * @description + * Sets and/or returns the CSS class regular expression that is checked when performing + * an animation. Upon bootstrap the classNameFilter value is not set at all and will + * therefore enable $animate to attempt to perform an animation on any element. + * When setting the classNameFilter value, animations will only be performed on elements + * that successfully match the filter expression. This in turn can boost performance + * for low-powered devices as well as applications containing a lot of structural operations. + * @param {RegExp=} expression The className expression which will be checked against all animations + * @return {RegExp} The current CSS className expression value. If null then there is no expression value + */ + this.classNameFilter = function(expression) { + if (arguments.length === 1) { + this.$$classNameFilter = (expression instanceof RegExp) ? expression : null; + } + return this.$$classNameFilter; + }; + + this.$get = ['$$q', '$$asyncCallback', '$rootScope', function($$q, $$asyncCallback, $rootScope) { + + var currentDefer; + + function runAnimationPostDigest(fn) { + var cancelFn, defer = $$q.defer(); + defer.promise.$$cancelFn = function ngAnimateMaybeCancel() { + cancelFn && cancelFn(); + }; + + $rootScope.$$postDigest(function ngAnimatePostDigest() { + cancelFn = fn(function ngAnimateNotifyComplete() { + defer.resolve(); + }); + }); + + return defer.promise; + } + + function resolveElementClasses(element, classes) { + var toAdd = [], toRemove = []; + + var hasClasses = createMap(); + forEach((element.attr('class') || '').split(/\s+/), function(className) { + hasClasses[className] = true; + }); + + forEach(classes, function(status, className) { + var hasClass = hasClasses[className]; + + // If the most recent class manipulation (via $animate) was to remove the class, and the + // element currently has the class, the class is scheduled for removal. Otherwise, if + // the most recent class manipulation (via $animate) was to add the class, and the + // element does not currently have the class, the class is scheduled to be added. + if (status === false && hasClass) { + toRemove.push(className); + } else if (status === true && !hasClass) { + toAdd.push(className); + } + }); + + return (toAdd.length + toRemove.length) > 0 && + [toAdd.length ? toAdd : null, toRemove.length ? toRemove : null]; + } + + function cachedClassManipulation(cache, classes, op) { + for (var i=0, ii = classes.length; i < ii; ++i) { + var className = classes[i]; + cache[className] = op; + } + } + + function asyncPromise() { + // only serve one instance of a promise in order to save CPU cycles + if (!currentDefer) { + currentDefer = $$q.defer(); + $$asyncCallback(function() { + currentDefer.resolve(); + currentDefer = null; + }); + } + return currentDefer.promise; + } + + function applyStyles(element, options) { + if (angular.isObject(options)) { + var styles = extend(options.from || {}, options.to || {}); + element.css(styles); + } + } + + /** + * + * @ngdoc service + * @name $animate + * @description The $animate service provides rudimentary DOM manipulation functions to + * insert, remove and move elements within the DOM, as well as adding and removing classes. + * This service is the core service used by the ngAnimate $animator service which provides + * high-level animation hooks for CSS and JavaScript. + * + * $animate is available in the AngularJS core, however, the ngAnimate module must be included + * to enable full out animation support. Otherwise, $animate will only perform simple DOM + * manipulation operations. + * + * To learn more about enabling animation support, click here to visit the {@link ngAnimate + * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service + * page}. + */ + return { + animate: function(element, from, to) { + applyStyles(element, { from: from, to: to }); + return asyncPromise(); + }, + + /** + * + * @ngdoc method + * @name $animate#enter + * @kind function + * @description Inserts the element into the DOM either after the `after` element or + * as the first child within the `parent` element. When the function is called a promise + * is returned that will be resolved at a later time. + * @param {DOMElement} element the element which will be inserted into the DOM + * @param {DOMElement} parent the parent element which will append the element as + * a child (if the after element is not present) + * @param {DOMElement} after the sibling element which will append the element + * after itself + * @param {object=} options an optional collection of styles that will be applied to the element. + * @return {Promise} the animation callback promise + */ + enter: function(element, parent, after, options) { + applyStyles(element, options); + after ? after.after(element) + : parent.prepend(element); + return asyncPromise(); + }, + + /** + * + * @ngdoc method + * @name $animate#leave + * @kind function + * @description Removes the element from the DOM. When the function is called a promise + * is returned that will be resolved at a later time. + * @param {DOMElement} element the element which will be removed from the DOM + * @param {object=} options an optional collection of options that will be applied to the element. + * @return {Promise} the animation callback promise + */ + leave: function(element, options) { + element.remove(); + return asyncPromise(); + }, + + /** + * + * @ngdoc method + * @name $animate#move + * @kind function + * @description Moves the position of the provided element within the DOM to be placed + * either after the `after` element or inside of the `parent` element. When the function + * is called a promise is returned that will be resolved at a later time. + * + * @param {DOMElement} element the element which will be moved around within the + * DOM + * @param {DOMElement} parent the parent element where the element will be + * inserted into (if the after element is not present) + * @param {DOMElement} after the sibling element where the element will be + * positioned next to + * @param {object=} options an optional collection of options that will be applied to the element. + * @return {Promise} the animation callback promise + */ + move: function(element, parent, after, options) { + // Do not remove element before insert. Removing will cause data associated with the + // element to be dropped. Insert will implicitly do the remove. + return this.enter(element, parent, after, options); + }, + + /** + * + * @ngdoc method + * @name $animate#addClass + * @kind function + * @description Adds the provided className CSS class value to the provided element. + * When the function is called a promise is returned that will be resolved at a later time. + * @param {DOMElement} element the element which will have the className value + * added to it + * @param {string} className the CSS class which will be added to the element + * @param {object=} options an optional collection of options that will be applied to the element. + * @return {Promise} the animation callback promise + */ + addClass: function(element, className, options) { + return this.setClass(element, className, [], options); + }, + + $$addClassImmediately: function(element, className, options) { + element = jqLite(element); + className = !isString(className) + ? (isArray(className) ? className.join(' ') : '') + : className; + forEach(element, function(element) { + jqLiteAddClass(element, className); + }); + applyStyles(element, options); + return asyncPromise(); + }, + + /** + * + * @ngdoc method + * @name $animate#removeClass + * @kind function + * @description Removes the provided className CSS class value from the provided element. + * When the function is called a promise is returned that will be resolved at a later time. + * @param {DOMElement} element the element which will have the className value + * removed from it + * @param {string} className the CSS class which will be removed from the element + * @param {object=} options an optional collection of options that will be applied to the element. + * @return {Promise} the animation callback promise + */ + removeClass: function(element, className, options) { + return this.setClass(element, [], className, options); + }, + + $$removeClassImmediately: function(element, className, options) { + element = jqLite(element); + className = !isString(className) + ? (isArray(className) ? className.join(' ') : '') + : className; + forEach(element, function(element) { + jqLiteRemoveClass(element, className); + }); + applyStyles(element, options); + return asyncPromise(); + }, + + /** + * + * @ngdoc method + * @name $animate#setClass + * @kind function + * @description Adds and/or removes the given CSS classes to and from the element. + * When the function is called a promise is returned that will be resolved at a later time. + * @param {DOMElement} element the element which will have its CSS classes changed + * removed from it + * @param {string} add the CSS classes which will be added to the element + * @param {string} remove the CSS class which will be removed from the element + * @param {object=} options an optional collection of options that will be applied to the element. + * @return {Promise} the animation callback promise + */ + setClass: function(element, add, remove, options) { + var self = this; + var STORAGE_KEY = '$$animateClasses'; + var createdCache = false; + element = jqLite(element); + + var cache = element.data(STORAGE_KEY); + if (!cache) { + cache = { + classes: {}, + options: options + }; + createdCache = true; + } else if (options && cache.options) { + cache.options = angular.extend(cache.options || {}, options); + } + + var classes = cache.classes; + + add = isArray(add) ? add : add.split(' '); + remove = isArray(remove) ? remove : remove.split(' '); + cachedClassManipulation(classes, add, true); + cachedClassManipulation(classes, remove, false); + + if (createdCache) { + cache.promise = runAnimationPostDigest(function(done) { + var cache = element.data(STORAGE_KEY); + element.removeData(STORAGE_KEY); + + // in the event that the element is removed before postDigest + // is run then the cache will be undefined and there will be + // no need anymore to add or remove and of the element classes + if (cache) { + var classes = resolveElementClasses(element, cache.classes); + if (classes) { + self.$$setClassImmediately(element, classes[0], classes[1], cache.options); + } + } + + done(); + }); + element.data(STORAGE_KEY, cache); + } + + return cache.promise; + }, + + $$setClassImmediately: function(element, add, remove, options) { + add && this.$$addClassImmediately(element, add); + remove && this.$$removeClassImmediately(element, remove); + applyStyles(element, options); + return asyncPromise(); + }, + + enabled: noop, + cancel: noop + }; + }]; +}]; + +function $$AsyncCallbackProvider() { + this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) { + return $$rAF.supported + ? function(fn) { return $$rAF(fn); } + : function(fn) { + return $timeout(fn, 0, false); + }; + }]; +} + +/* global stripHash: true */ + +/** + * ! This is a private undocumented service ! + * + * @name $browser + * @requires $log + * @description + * This object has two goals: + * + * - hide all the global state in the browser caused by the window object + * - abstract away all the browser specific features and inconsistencies + * + * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser` + * service, which can be used for convenient testing of the application without the interaction with + * the real browser apis. + */ +/** + * @param {object} window The global window object. + * @param {object} document jQuery wrapped document. + * @param {object} $log window.console or an object with the same interface. + * @param {object} $sniffer $sniffer service + */ +function Browser(window, document, $log, $sniffer) { + var self = this, + rawDocument = document[0], + location = window.location, + history = window.history, + setTimeout = window.setTimeout, + clearTimeout = window.clearTimeout, + pendingDeferIds = {}; + + self.isMock = false; + + var outstandingRequestCount = 0; + var outstandingRequestCallbacks = []; + + // TODO(vojta): remove this temporary api + self.$$completeOutstandingRequest = completeOutstandingRequest; + self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; }; + + /** + * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks` + * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed. + */ + function completeOutstandingRequest(fn) { + try { + fn.apply(null, sliceArgs(arguments, 1)); + } finally { + outstandingRequestCount--; + if (outstandingRequestCount === 0) { + while (outstandingRequestCallbacks.length) { + try { + outstandingRequestCallbacks.pop()(); + } catch (e) { + $log.error(e); + } + } + } + } + } + + function getHash(url) { + var index = url.indexOf('#'); + return index === -1 ? '' : url.substr(index + 1); + } + + /** + * @private + * Note: this method is used only by scenario runner + * TODO(vojta): prefix this method with $$ ? + * @param {function()} callback Function that will be called when no outstanding request + */ + self.notifyWhenNoOutstandingRequests = function(callback) { + // force browser to execute all pollFns - this is needed so that cookies and other pollers fire + // at some deterministic time in respect to the test runner's actions. Leaving things up to the + // regular poller would result in flaky tests. + forEach(pollFns, function(pollFn) { pollFn(); }); + + if (outstandingRequestCount === 0) { + callback(); + } else { + outstandingRequestCallbacks.push(callback); + } + }; + + ////////////////////////////////////////////////////////////// + // Poll Watcher API + ////////////////////////////////////////////////////////////// + var pollFns = [], + pollTimeout; + + /** + * @name $browser#addPollFn + * + * @param {function()} fn Poll function to add + * + * @description + * Adds a function to the list of functions that poller periodically executes, + * and starts polling if not started yet. + * + * @returns {function()} the added function + */ + self.addPollFn = function(fn) { + if (isUndefined(pollTimeout)) startPoller(100, setTimeout); + pollFns.push(fn); + return fn; + }; + + /** + * @param {number} interval How often should browser call poll functions (ms) + * @param {function()} setTimeout Reference to a real or fake `setTimeout` function. + * + * @description + * Configures the poller to run in the specified intervals, using the specified + * setTimeout fn and kicks it off. + */ + function startPoller(interval, setTimeout) { + (function check() { + forEach(pollFns, function(pollFn) { pollFn(); }); + pollTimeout = setTimeout(check, interval); + })(); + } + + ////////////////////////////////////////////////////////////// + // URL API + ////////////////////////////////////////////////////////////// + + var cachedState, lastHistoryState, + lastBrowserUrl = location.href, + baseElement = document.find('base'), + reloadLocation = null; + + cacheState(); + lastHistoryState = cachedState; + + /** + * @name $browser#url + * + * @description + * GETTER: + * Without any argument, this method just returns current value of location.href. + * + * SETTER: + * With at least one argument, this method sets url to new value. + * If html5 history api supported, pushState/replaceState is used, otherwise + * location.href/location.replace is used. + * Returns its own instance to allow chaining + * + * NOTE: this api is intended for use only by the $location service. Please use the + * {@link ng.$location $location service} to change url. + * + * @param {string} url New url (when used as setter) + * @param {boolean=} replace Should new url replace current history record? + * @param {object=} state object to use with pushState/replaceState + */ + self.url = function(url, replace, state) { + // In modern browsers `history.state` is `null` by default; treating it separately + // from `undefined` would cause `$browser.url('/foo')` to change `history.state` + // to undefined via `pushState`. Instead, let's change `undefined` to `null` here. + if (isUndefined(state)) { + state = null; + } + + // Android Browser BFCache causes location, history reference to become stale. + if (location !== window.location) location = window.location; + if (history !== window.history) history = window.history; + + // setter + if (url) { + var sameState = lastHistoryState === state; + + // Don't change anything if previous and current URLs and states match. This also prevents + // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode. + // See https://github.com/angular/angular.js/commit/ffb2701 + if (lastBrowserUrl === url && (!$sniffer.history || sameState)) { + return self; + } + var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url); + lastBrowserUrl = url; + lastHistoryState = state; + // Don't use history API if only the hash changed + // due to a bug in IE10/IE11 which leads + // to not firing a `hashchange` nor `popstate` event + // in some cases (see #9143). + if ($sniffer.history && (!sameBase || !sameState)) { + history[replace ? 'replaceState' : 'pushState'](state, '', url); + cacheState(); + // Do the assignment again so that those two variables are referentially identical. + lastHistoryState = cachedState; + } else { + if (!sameBase) { + reloadLocation = url; + } + if (replace) { + location.replace(url); + } else if (!sameBase) { + location.href = url; + } else { + location.hash = getHash(url); + } + } + return self; + // getter + } else { + // - reloadLocation is needed as browsers don't allow to read out + // the new location.href if a reload happened. + // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172 + return reloadLocation || location.href.replace(/%27/g,"'"); + } + }; + + /** + * @name $browser#state + * + * @description + * This method is a getter. + * + * Return history.state or null if history.state is undefined. + * + * @returns {object} state + */ + self.state = function() { + return cachedState; + }; + + var urlChangeListeners = [], + urlChangeInit = false; + + function cacheStateAndFireUrlChange() { + cacheState(); + fireUrlChange(); + } + + // This variable should be used *only* inside the cacheState function. + var lastCachedState = null; + function cacheState() { + // This should be the only place in $browser where `history.state` is read. + cachedState = window.history.state; + cachedState = isUndefined(cachedState) ? null : cachedState; + + // Prevent callbacks fo fire twice if both hashchange & popstate were fired. + if (equals(cachedState, lastCachedState)) { + cachedState = lastCachedState; + } + lastCachedState = cachedState; + } + + function fireUrlChange() { + if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) { + return; + } + + lastBrowserUrl = self.url(); + lastHistoryState = cachedState; + forEach(urlChangeListeners, function(listener) { + listener(self.url(), cachedState); + }); + } + + /** + * @name $browser#onUrlChange + * + * @description + * Register callback function that will be called, when url changes. + * + * It's only called when the url is changed from outside of angular: + * - user types different url into address bar + * - user clicks on history (forward/back) button + * - user clicks on a link + * + * It's not called when url is changed by $browser.url() method + * + * The listener gets called with new url as parameter. + * + * NOTE: this api is intended for use only by the $location service. Please use the + * {@link ng.$location $location service} to monitor url changes in angular apps. + * + * @param {function(string)} listener Listener function to be called when url changes. + * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous. + */ + self.onUrlChange = function(callback) { + // TODO(vojta): refactor to use node's syntax for events + if (!urlChangeInit) { + // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera) + // don't fire popstate when user change the address bar and don't fire hashchange when url + // changed by push/replaceState + + // html5 history api - popstate event + if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange); + // hashchange event + jqLite(window).on('hashchange', cacheStateAndFireUrlChange); + + urlChangeInit = true; + } + + urlChangeListeners.push(callback); + return callback; + }; + + /** + * Checks whether the url has changed outside of Angular. + * Needs to be exported to be able to check for changes that have been done in sync, + * as hashchange/popstate events fire in async. + */ + self.$$checkUrlChange = fireUrlChange; + + ////////////////////////////////////////////////////////////// + // Misc API + ////////////////////////////////////////////////////////////// + + /** + * @name $browser#baseHref + * + * @description + * Returns current + * (always relative - without domain) + * + * @returns {string} The current base href + */ + self.baseHref = function() { + var href = baseElement.attr('href'); + return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : ''; + }; + + ////////////////////////////////////////////////////////////// + // Cookies API + ////////////////////////////////////////////////////////////// + var lastCookies = {}; + var lastCookieString = ''; + var cookiePath = self.baseHref(); + + function safeDecodeURIComponent(str) { + try { + return decodeURIComponent(str); + } catch (e) { + return str; + } + } + + /** + * @name $browser#cookies + * + * @param {string=} name Cookie name + * @param {string=} value Cookie value + * + * @description + * The cookies method provides a 'private' low level access to browser cookies. + * It is not meant to be used directly, use the $cookie service instead. + * + * The return values vary depending on the arguments that the method was called with as follows: + * + * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify + * it + * - cookies(name, value) -> set name to value, if value is undefined delete the cookie + * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that + * way) + * + * @returns {Object} Hash of all cookies (if called without any parameter) + */ + self.cookies = function(name, value) { + var cookieLength, cookieArray, cookie, i, index; + + if (name) { + if (value === undefined) { + rawDocument.cookie = encodeURIComponent(name) + "=;path=" + cookiePath + + ";expires=Thu, 01 Jan 1970 00:00:00 GMT"; + } else { + if (isString(value)) { + cookieLength = (rawDocument.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value) + + ';path=' + cookiePath).length + 1; + + // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum: + // - 300 cookies + // - 20 cookies per unique domain + // - 4096 bytes per cookie + if (cookieLength > 4096) { + $log.warn("Cookie '" + name + + "' possibly not set or overflowed because it was too large (" + + cookieLength + " > 4096 bytes)!"); + } + } + } + } else { + if (rawDocument.cookie !== lastCookieString) { + lastCookieString = rawDocument.cookie; + cookieArray = lastCookieString.split("; "); + lastCookies = {}; + + for (i = 0; i < cookieArray.length; i++) { + cookie = cookieArray[i]; + index = cookie.indexOf('='); + if (index > 0) { //ignore nameless cookies + name = safeDecodeURIComponent(cookie.substring(0, index)); + // the first value that is seen for a cookie is the most + // specific one. values for the same cookie name that + // follow are for less specific paths. + if (lastCookies[name] === undefined) { + lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1)); + } + } + } + } + return lastCookies; + } + }; + + + /** + * @name $browser#defer + * @param {function()} fn A function, who's execution should be deferred. + * @param {number=} [delay=0] of milliseconds to defer the function execution. + * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`. + * + * @description + * Executes a fn asynchronously via `setTimeout(fn, delay)`. + * + * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using + * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed + * via `$browser.defer.flush()`. + * + */ + self.defer = function(fn, delay) { + var timeoutId; + outstandingRequestCount++; + timeoutId = setTimeout(function() { + delete pendingDeferIds[timeoutId]; + completeOutstandingRequest(fn); + }, delay || 0); + pendingDeferIds[timeoutId] = true; + return timeoutId; + }; + + + /** + * @name $browser#defer.cancel + * + * @description + * Cancels a deferred task identified with `deferId`. + * + * @param {*} deferId Token returned by the `$browser.defer` function. + * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully + * canceled. + */ + self.defer.cancel = function(deferId) { + if (pendingDeferIds[deferId]) { + delete pendingDeferIds[deferId]; + clearTimeout(deferId); + completeOutstandingRequest(noop); + return true; + } + return false; + }; + +} + +function $BrowserProvider() { + this.$get = ['$window', '$log', '$sniffer', '$document', + function($window, $log, $sniffer, $document) { + return new Browser($window, $document, $log, $sniffer); + }]; +} + +/** + * @ngdoc service + * @name $cacheFactory + * + * @description + * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to + * them. + * + * ```js + * + * var cache = $cacheFactory('cacheId'); + * expect($cacheFactory.get('cacheId')).toBe(cache); + * expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined(); + * + * cache.put("key", "value"); + * cache.put("another key", "another value"); + * + * // We've specified no options on creation + * expect(cache.info()).toEqual({id: 'cacheId', size: 2}); + * + * ``` + * + * + * @param {string} cacheId Name or id of the newly created cache. + * @param {object=} options Options object that specifies the cache behavior. Properties: + * + * - `{number=}` `capacity` — turns the cache into LRU cache. + * + * @returns {object} Newly created cache object with the following set of methods: + * + * - `{object}` `info()` — Returns id, size, and options of cache. + * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns + * it. + * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss. + * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache. + * - `{void}` `removeAll()` — Removes all cached values. + * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory. + * + * @example + + +
    + + + + +

    Cached Values

    +
    + + : + +
    + +

    Cache Info

    +
    + + : + +
    +
    +
    + + angular.module('cacheExampleApp', []). + controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) { + $scope.keys = []; + $scope.cache = $cacheFactory('cacheId'); + $scope.put = function(key, value) { + if ($scope.cache.get(key) === undefined) { + $scope.keys.push(key); + } + $scope.cache.put(key, value === undefined ? null : value); + }; + }]); + + + p { + margin: 10px 0 3px; + } + +
    + */ +function $CacheFactoryProvider() { + + this.$get = function() { + var caches = {}; + + function cacheFactory(cacheId, options) { + if (cacheId in caches) { + throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId); + } + + var size = 0, + stats = extend({}, options, {id: cacheId}), + data = {}, + capacity = (options && options.capacity) || Number.MAX_VALUE, + lruHash = {}, + freshEnd = null, + staleEnd = null; + + /** + * @ngdoc type + * @name $cacheFactory.Cache + * + * @description + * A cache object used to store and retrieve data, primarily used by + * {@link $http $http} and the {@link ng.directive:script script} directive to cache + * templates and other data. + * + * ```js + * angular.module('superCache') + * .factory('superCache', ['$cacheFactory', function($cacheFactory) { + * return $cacheFactory('super-cache'); + * }]); + * ``` + * + * Example test: + * + * ```js + * it('should behave like a cache', inject(function(superCache) { + * superCache.put('key', 'value'); + * superCache.put('another key', 'another value'); + * + * expect(superCache.info()).toEqual({ + * id: 'super-cache', + * size: 2 + * }); + * + * superCache.remove('another key'); + * expect(superCache.get('another key')).toBeUndefined(); + * + * superCache.removeAll(); + * expect(superCache.info()).toEqual({ + * id: 'super-cache', + * size: 0 + * }); + * })); + * ``` + */ + return caches[cacheId] = { + + /** + * @ngdoc method + * @name $cacheFactory.Cache#put + * @kind function + * + * @description + * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be + * retrieved later, and incrementing the size of the cache if the key was not already + * present in the cache. If behaving like an LRU cache, it will also remove stale + * entries from the set. + * + * It will not insert undefined values into the cache. + * + * @param {string} key the key under which the cached data is stored. + * @param {*} value the value to store alongside the key. If it is undefined, the key + * will not be stored. + * @returns {*} the value stored. + */ + put: function(key, value) { + if (capacity < Number.MAX_VALUE) { + var lruEntry = lruHash[key] || (lruHash[key] = {key: key}); + + refresh(lruEntry); + } + + if (isUndefined(value)) return; + if (!(key in data)) size++; + data[key] = value; + + if (size > capacity) { + this.remove(staleEnd.key); + } + + return value; + }, + + /** + * @ngdoc method + * @name $cacheFactory.Cache#get + * @kind function + * + * @description + * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object. + * + * @param {string} key the key of the data to be retrieved + * @returns {*} the value stored. + */ + get: function(key) { + if (capacity < Number.MAX_VALUE) { + var lruEntry = lruHash[key]; + + if (!lruEntry) return; + + refresh(lruEntry); + } + + return data[key]; + }, + + + /** + * @ngdoc method + * @name $cacheFactory.Cache#remove + * @kind function + * + * @description + * Removes an entry from the {@link $cacheFactory.Cache Cache} object. + * + * @param {string} key the key of the entry to be removed + */ + remove: function(key) { + if (capacity < Number.MAX_VALUE) { + var lruEntry = lruHash[key]; + + if (!lruEntry) return; + + if (lruEntry == freshEnd) freshEnd = lruEntry.p; + if (lruEntry == staleEnd) staleEnd = lruEntry.n; + link(lruEntry.n,lruEntry.p); + + delete lruHash[key]; + } + + delete data[key]; + size--; + }, + + + /** + * @ngdoc method + * @name $cacheFactory.Cache#removeAll + * @kind function + * + * @description + * Clears the cache object of any entries. + */ + removeAll: function() { + data = {}; + size = 0; + lruHash = {}; + freshEnd = staleEnd = null; + }, + + + /** + * @ngdoc method + * @name $cacheFactory.Cache#destroy + * @kind function + * + * @description + * Destroys the {@link $cacheFactory.Cache Cache} object entirely, + * removing it from the {@link $cacheFactory $cacheFactory} set. + */ + destroy: function() { + data = null; + stats = null; + lruHash = null; + delete caches[cacheId]; + }, + + + /** + * @ngdoc method + * @name $cacheFactory.Cache#info + * @kind function + * + * @description + * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}. + * + * @returns {object} an object with the following properties: + *
      + *
    • **id**: the id of the cache instance
    • + *
    • **size**: the number of entries kept in the cache instance
    • + *
    • **...**: any additional properties from the options object when creating the + * cache.
    • + *
    + */ + info: function() { + return extend({}, stats, {size: size}); + } + }; + + + /** + * makes the `entry` the freshEnd of the LRU linked list + */ + function refresh(entry) { + if (entry != freshEnd) { + if (!staleEnd) { + staleEnd = entry; + } else if (staleEnd == entry) { + staleEnd = entry.n; + } + + link(entry.n, entry.p); + link(entry, freshEnd); + freshEnd = entry; + freshEnd.n = null; + } + } + + + /** + * bidirectionally links two entries of the LRU linked list + */ + function link(nextEntry, prevEntry) { + if (nextEntry != prevEntry) { + if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify + if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify + } + } + } + + + /** + * @ngdoc method + * @name $cacheFactory#info + * + * @description + * Get information about all the caches that have been created + * + * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info` + */ + cacheFactory.info = function() { + var info = {}; + forEach(caches, function(cache, cacheId) { + info[cacheId] = cache.info(); + }); + return info; + }; + + + /** + * @ngdoc method + * @name $cacheFactory#get + * + * @description + * Get access to a cache object by the `cacheId` used when it was created. + * + * @param {string} cacheId Name or id of a cache to access. + * @returns {object} Cache object identified by the cacheId or undefined if no such cache. + */ + cacheFactory.get = function(cacheId) { + return caches[cacheId]; + }; + + + return cacheFactory; + }; +} + +/** + * @ngdoc service + * @name $templateCache + * + * @description + * The first time a template is used, it is loaded in the template cache for quick retrieval. You + * can load templates directly into the cache in a `script` tag, or by consuming the + * `$templateCache` service directly. + * + * Adding via the `script` tag: + * + * ```html + * + * ``` + * + * **Note:** the `script` tag containing the template does not need to be included in the `head` of + * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE, + * element with ng-app attribute), otherwise the template will be ignored. + * + * Adding via the $templateCache service: + * + * ```js + * var myApp = angular.module('myApp', []); + * myApp.run(function($templateCache) { + * $templateCache.put('templateId.html', 'This is the content of the template'); + * }); + * ``` + * + * To retrieve the template later, simply use it in your HTML: + * ```html + *
    + * ``` + * + * or get it via Javascript: + * ```js + * $templateCache.get('templateId.html') + * ``` + * + * See {@link ng.$cacheFactory $cacheFactory}. + * + */ +function $TemplateCacheProvider() { + this.$get = ['$cacheFactory', function($cacheFactory) { + return $cacheFactory('templates'); + }]; +} + +/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE! + * + * DOM-related variables: + * + * - "node" - DOM Node + * - "element" - DOM Element or Node + * - "$node" or "$element" - jqLite-wrapped node or element + * + * + * Compiler related stuff: + * + * - "linkFn" - linking fn of a single directive + * - "nodeLinkFn" - function that aggregates all linking fns for a particular node + * - "childLinkFn" - function that aggregates all linking fns for child nodes of a particular node + * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList) + */ + + +/** + * @ngdoc service + * @name $compile + * @kind function + * + * @description + * Compiles an HTML string or DOM into a template and produces a template function, which + * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together. + * + * The compilation is a process of walking the DOM tree and matching DOM elements to + * {@link ng.$compileProvider#directive directives}. + * + *
    + * **Note:** This document is an in-depth reference of all directive options. + * For a gentle introduction to directives with examples of common use cases, + * see the {@link guide/directive directive guide}. + *
    + * + * ## Comprehensive Directive API + * + * There are many different options for a directive. + * + * The difference resides in the return value of the factory function. + * You can either return a "Directive Definition Object" (see below) that defines the directive properties, + * or just the `postLink` function (all other properties will have the default values). + * + *
    + * **Best Practice:** It's recommended to use the "directive definition object" form. + *
    + * + * Here's an example directive declared with a Directive Definition Object: + * + * ```js + * var myModule = angular.module(...); + * + * myModule.directive('directiveName', function factory(injectables) { + * var directiveDefinitionObject = { + * priority: 0, + * template: '
    ', // or // function(tElement, tAttrs) { ... }, + * // or + * // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... }, + * transclude: false, + * restrict: 'A', + * templateNamespace: 'html', + * scope: false, + * controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... }, + * controllerAs: 'stringAlias', + * require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'], + * compile: function compile(tElement, tAttrs, transclude) { + * return { + * pre: function preLink(scope, iElement, iAttrs, controller) { ... }, + * post: function postLink(scope, iElement, iAttrs, controller) { ... } + * } + * // or + * // return function postLink( ... ) { ... } + * }, + * // or + * // link: { + * // pre: function preLink(scope, iElement, iAttrs, controller) { ... }, + * // post: function postLink(scope, iElement, iAttrs, controller) { ... } + * // } + * // or + * // link: function postLink( ... ) { ... } + * }; + * return directiveDefinitionObject; + * }); + * ``` + * + *
    + * **Note:** Any unspecified options will use the default value. You can see the default values below. + *
    + * + * Therefore the above can be simplified as: + * + * ```js + * var myModule = angular.module(...); + * + * myModule.directive('directiveName', function factory(injectables) { + * var directiveDefinitionObject = { + * link: function postLink(scope, iElement, iAttrs) { ... } + * }; + * return directiveDefinitionObject; + * // or + * // return function postLink(scope, iElement, iAttrs) { ... } + * }); + * ``` + * + * + * + * ### Directive Definition Object + * + * The directive definition object provides instructions to the {@link ng.$compile + * compiler}. The attributes are: + * + * #### `multiElement` + * When this property is set to true, the HTML compiler will collect DOM nodes between + * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them + * together as the directive elements. It is recommended that this feature be used on directives + * which are not strictly behavioural (such as {@link ngClick}), and which + * do not manipulate or replace child nodes (such as {@link ngInclude}). + * + * #### `priority` + * When there are multiple directives defined on a single DOM element, sometimes it + * is necessary to specify the order in which the directives are applied. The `priority` is used + * to sort the directives before their `compile` functions get called. Priority is defined as a + * number. Directives with greater numerical `priority` are compiled first. Pre-link functions + * are also run in priority order, but post-link functions are run in reverse order. The order + * of directives with the same priority is undefined. The default priority is `0`. + * + * #### `terminal` + * If set to true then the current `priority` will be the last set of directives + * which will execute (any directives at the current priority will still execute + * as the order of execution on same `priority` is undefined). Note that expressions + * and other directives used in the directive's template will also be excluded from execution. + * + * #### `scope` + * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the + * same element request a new scope, only one new scope is created. The new scope rule does not + * apply for the root of the template since the root of the template always gets a new scope. + * + * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from + * normal scope in that it does not prototypically inherit from the parent scope. This is useful + * when creating reusable components, which should not accidentally read or modify data in the + * parent scope. + * + * The 'isolate' scope takes an object hash which defines a set of local scope properties + * derived from the parent scope. These local properties are useful for aliasing values for + * templates. Locals definition is a hash of local scope property to its source: + * + * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is + * always a string since DOM attributes are strings. If no `attr` name is specified then the + * attribute name is assumed to be the same as the local name. + * Given `` and widget definition + * of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect + * the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the + * `localName` property on the widget scope. The `name` is read from the parent scope (not + * component scope). + * + * * `=` or `=attr` - set up bi-directional binding between a local scope property and the + * parent scope property of name defined via the value of the `attr` attribute. If no `attr` + * name is specified then the attribute name is assumed to be the same as the local name. + * Given `` and widget definition of + * `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the + * value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected + * in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent + * scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You + * can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. If + * you want to shallow watch for changes (i.e. $watchCollection instead of $watch) you can use + * `=*` or `=*attr` (`=*?` or `=*?attr` if the property is optional). + * + * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope. + * If no `attr` name is specified then the attribute name is assumed to be the same as the + * local name. Given `` and widget definition of + * `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to + * a function wrapper for the `count = count + value` expression. Often it's desirable to + * pass data from the isolated scope via an expression to the parent scope, this can be + * done by passing a map of local variable names and values into the expression wrapper fn. + * For example, if the expression is `increment(amount)` then we can specify the amount value + * by calling the `localFn` as `localFn({amount: 22})`. + * + * + * #### `bindToController` + * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will + * allow a component to have its properties bound to the controller, rather than to scope. When the controller + * is instantiated, the initial values of the isolate scope bindings are already available. + * + * #### `controller` + * Controller constructor function. The controller is instantiated before the + * pre-linking phase and it is shared with other directives (see + * `require` attribute). This allows the directives to communicate with each other and augment + * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals: + * + * * `$scope` - Current scope associated with the element + * * `$element` - Current element + * * `$attrs` - Current attributes object for the element + * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope: + * `function([scope], cloneLinkingFn, futureParentElement)`. + * * `scope`: optional argument to override the scope. + * * `cloneLinkingFn`: optional argument to create clones of the original transcluded content. + * * `futureParentElement`: + * * defines the parent to which the `cloneLinkingFn` will add the cloned elements. + * * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`. + * * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements) + * and when the `cloneLinkinFn` is passed, + * as those elements need to created and cloned in a special way when they are defined outside their + * usual containers (e.g. like ``). + * * See also the `directive.templateNamespace` property. + * + * + * #### `require` + * Require another directive and inject its controller as the fourth argument to the linking function. The + * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the + * injected argument will be an array in corresponding order. If no such directive can be + * found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with: + * + * * (no prefix) - Locate the required controller on the current element. Throw an error if not found. + * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found. + * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found. + * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found. + * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass + * `null` to the `link` fn if not found. + * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass + * `null` to the `link` fn if not found. + * + * + * #### `controllerAs` + * Controller alias at the directive scope. An alias for the controller so it + * can be referenced at the directive template. The directive needs to define a scope for this + * configuration to be used. Useful in the case when directive is used as component. + * + * + * #### `restrict` + * String of subset of `EACM` which restricts the directive to a specific directive + * declaration style. If omitted, the defaults (elements and attributes) are used. + * + * * `E` - Element name (default): `` + * * `A` - Attribute (default): `
    ` + * * `C` - Class: `
    ` + * * `M` - Comment: `` + * + * + * #### `templateNamespace` + * String representing the document type used by the markup in the template. + * AngularJS needs this information as those elements need to be created and cloned + * in a special way when they are defined outside their usual containers like `` and ``. + * + * * `html` - All root nodes in the template are HTML. Root nodes may also be + * top-level elements such as `` or ``. + * * `svg` - The root nodes in the template are SVG elements (excluding ``). + * * `math` - The root nodes in the template are MathML elements (excluding ``). + * + * If no `templateNamespace` is specified, then the namespace is considered to be `html`. + * + * #### `template` + * HTML markup that may: + * * Replace the contents of the directive's element (default). + * * Replace the directive's element itself (if `replace` is true - DEPRECATED). + * * Wrap the contents of the directive's element (if `transclude` is true). + * + * Value may be: + * + * * A string. For example `
    {{delete_str}}
    `. + * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile` + * function api below) and returns a string value. + * + * + * #### `templateUrl` + * This is similar to `template` but the template is loaded from the specified URL, asynchronously. + * + * Because template loading is asynchronous the compiler will suspend compilation of directives on that element + * for later when the template has been resolved. In the meantime it will continue to compile and link + * sibling and parent elements as though this element had not contained any directives. + * + * The compiler does not suspend the entire compilation to wait for templates to be loaded because this + * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the + * case when only one deeply nested directive has `templateUrl`. + * + * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache} + * + * You can specify `templateUrl` as a string representing the URL or as a function which takes two + * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns + * a string value representing the url. In either case, the template URL is passed through {@link + * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}. + * + * + * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0) + * specify what the template should replace. Defaults to `false`. + * + * * `true` - the template will replace the directive's element. + * * `false` - the template will replace the contents of the directive's element. + * + * The replacement process migrates all of the attributes / classes from the old element to the new + * one. See the {@link guide/directive#template-expanding-directive + * Directives Guide} for an example. + * + * There are very few scenarios where element replacement is required for the application function, + * the main one being reusable custom components that are used within SVG contexts + * (because SVG doesn't work with custom elements in the DOM tree). + * + * #### `transclude` + * Extract the contents of the element where the directive appears and make it available to the directive. + * The contents are compiled and provided to the directive as a **transclusion function**. See the + * {@link $compile#transclusion Transclusion} section below. + * + * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the + * directive's element or the entire element: + * + * * `true` - transclude the content (i.e. the child nodes) of the directive's element. + * * `'element'` - transclude the whole of the directive's element including any directives on this + * element that defined at a lower priority than this directive. When used, the `template` + * property is ignored. + * + * + * #### `compile` + * + * ```js + * function compile(tElement, tAttrs, transclude) { ... } + * ``` + * + * The compile function deals with transforming the template DOM. Since most directives do not do + * template transformation, it is not used often. The compile function takes the following arguments: + * + * * `tElement` - template element - The element where the directive has been declared. It is + * safe to do template transformation on the element and child elements only. + * + * * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared + * between all directive compile functions. + * + * * `transclude` - [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)` + * + *
    + * **Note:** The template instance and the link instance may be different objects if the template has + * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that + * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration + * should be done in a linking function rather than in a compile function. + *
    + + *
    + * **Note:** The compile function cannot handle directives that recursively use themselves in their + * own templates or compile functions. Compiling these directives results in an infinite loop and a + * stack overflow errors. + * + * This can be avoided by manually using $compile in the postLink function to imperatively compile + * a directive's template instead of relying on automatic template compilation via `template` or + * `templateUrl` declaration or manual compilation inside the compile function. + *
    + * + *
    + * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it + * e.g. does not know about the right outer scope. Please use the transclude function that is passed + * to the link function instead. + *
    + + * A compile function can have a return value which can be either a function or an object. + * + * * returning a (post-link) function - is equivalent to registering the linking function via the + * `link` property of the config object when the compile function is empty. + * + * * returning an object with function(s) registered via `pre` and `post` properties - allows you to + * control when a linking function should be called during the linking phase. See info about + * pre-linking and post-linking functions below. + * + * + * #### `link` + * This property is used only if the `compile` property is not defined. + * + * ```js + * function link(scope, iElement, iAttrs, controller, transcludeFn) { ... } + * ``` + * + * The link function is responsible for registering DOM listeners as well as updating the DOM. It is + * executed after the template has been cloned. This is where most of the directive logic will be + * put. + * + * * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the + * directive for registering {@link ng.$rootScope.Scope#$watch watches}. + * + * * `iElement` - instance element - The element where the directive is to be used. It is safe to + * manipulate the children of the element only in `postLink` function since the children have + * already been linked. + * + * * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared + * between all directive linking functions. + * + * * `controller` - a controller instance - A controller instance if at least one directive on the + * element defines a controller. The controller is shared among all the directives, which allows + * the directives to use the controllers as a communication channel. + * + * * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope. + * This is the same as the `$transclude` + * parameter of directive controllers, see there for details. + * `function([scope], cloneLinkingFn, futureParentElement)`. + * + * #### Pre-linking function + * + * Executed before the child elements are linked. Not safe to do DOM transformation since the + * compiler linking function will fail to locate the correct elements for linking. + * + * #### Post-linking function + * + * Executed after the child elements are linked. + * + * Note that child elements that contain `templateUrl` directives will not have been compiled + * and linked since they are waiting for their template to load asynchronously and their own + * compilation and linking has been suspended until that occurs. + * + * It is safe to do DOM transformation in the post-linking function on elements that are not waiting + * for their async templates to be resolved. + * + * + * ### Transclusion + * + * Transclusion is the process of extracting a collection of DOM element from one part of the DOM and + * copying them to another part of the DOM, while maintaining their connection to the original AngularJS + * scope from where they were taken. + * + * Transclusion is used (often with {@link ngTransclude}) to insert the + * original contents of a directive's element into a specified place in the template of the directive. + * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded + * content has access to the properties on the scope from which it was taken, even if the directive + * has isolated scope. + * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}. + * + * This makes it possible for the widget to have private state for its template, while the transcluded + * content has access to its originating scope. + * + *
    + * **Note:** When testing an element transclude directive you must not place the directive at the root of the + * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives + * Testing Transclusion Directives}. + *
    + * + * #### Transclusion Functions + * + * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion + * function** to the directive's `link` function and `controller`. This transclusion function is a special + * **linking function** that will return the compiled contents linked to a new transclusion scope. + * + *
    + * If you are just using {@link ngTransclude} then you don't need to worry about this function, since + * ngTransclude will deal with it for us. + *
    + * + * If you want to manually control the insertion and removal of the transcluded content in your directive + * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery + * object that contains the compiled DOM, which is linked to the correct transclusion scope. + * + * When you call a transclusion function you can pass in a **clone attach function**. This function accepts + * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded + * content and the `scope` is the newly created transclusion scope, to which the clone is bound. + * + *
    + * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function + * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope. + *
    + * + * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone + * attach function**: + * + * ```js + * var transcludedContent, transclusionScope; + * + * $transclude(function(clone, scope) { + * element.append(clone); + * transcludedContent = clone; + * transclusionScope = scope; + * }); + * ``` + * + * Later, if you want to remove the transcluded content from your DOM then you should also destroy the + * associated transclusion scope: + * + * ```js + * transcludedContent.remove(); + * transclusionScope.$destroy(); + * ``` + * + *
    + * **Best Practice**: if you intend to add and remove transcluded content manually in your directive + * (by calling the transclude function to get the DOM and and calling `element.remove()` to remove it), + * then you are also responsible for calling `$destroy` on the transclusion scope. + *
    + * + * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat} + * automatically destroy their transluded clones as necessary so you do not need to worry about this if + * you are simply using {@link ngTransclude} to inject the transclusion into your directive. + * + * + * #### Transclusion Scopes + * + * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion + * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed + * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it + * was taken. + * + * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look + * like this: + * + * ```html + *
    + *
    + *
    + *
    + *
    + *
    + * ``` + * + * The `$parent` scope hierarchy will look like this: + * + * ``` + * - $rootScope + * - isolate + * - transclusion + * ``` + * + * but the scopes will inherit prototypically from different scopes to their `$parent`. + * + * ``` + * - $rootScope + * - transclusion + * - isolate + * ``` + * + * + * ### Attributes + * + * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the + * `link()` or `compile()` functions. It has a variety of uses. + * + * accessing *Normalized attribute names:* + * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'. + * the attributes object allows for normalized access to + * the attributes. + * + * * *Directive inter-communication:* All directives share the same instance of the attributes + * object which allows the directives to use the attributes object as inter directive + * communication. + * + * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object + * allowing other directives to read the interpolated value. + * + * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes + * that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also + * the only way to easily get the actual value because during the linking phase the interpolation + * hasn't been evaluated yet and so the value is at this time set to `undefined`. + * + * ```js + * function linkingFn(scope, elm, attrs, ctrl) { + * // get the attribute value + * console.log(attrs.ngModel); + * + * // change the attribute + * attrs.$set('ngModel', 'new value'); + * + * // observe changes to interpolated attribute + * attrs.$observe('ngModel', function(value) { + * console.log('ngModel has changed value to ' + value); + * }); + * } + * ``` + * + * ## Example + * + *
    + * **Note**: Typically directives are registered with `module.directive`. The example below is + * to illustrate how `$compile` works. + *
    + * + + + +
    +
    +
    +
    +
    +
    + + it('should auto compile', function() { + var textarea = $('textarea'); + var output = $('div[compile]'); + // The initial state reads 'Hello Angular'. + expect(output.getText()).toBe('Hello Angular'); + textarea.clear(); + textarea.sendKeys('{{name}}!'); + expect(output.getText()).toBe('Angular!'); + }); + +
    + + * + * + * @param {string|DOMElement} element Element or HTML string to compile into a template function. + * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED. + * + *
    + * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it + * e.g. will not use the right outer scope. Please pass the transclude function as a + * `parentBoundTranscludeFn` to the link function instead. + *
    + * + * @param {number} maxPriority only apply directives lower than given priority (Only effects the + * root element(s), not their children) + * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template + * (a DOM element/tree) to a scope. Where: + * + * * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to. + * * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the + * `template` and call the `cloneAttachFn` function allowing the caller to attach the + * cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is + * called as:
    `cloneAttachFn(clonedElement, scope)` where: + * + * * `clonedElement` - is a clone of the original `element` passed into the compiler. + * * `scope` - is the current scope with which the linking function is working with. + * + * * `options` - An optional object hash with linking options. If `options` is provided, then the following + * keys may be used to control linking behavior: + * + * * `parentBoundTranscludeFn` - the transclude function made available to + * directives; if given, it will be passed through to the link functions of + * directives found in `element` during compilation. + * * `transcludeControllers` - an object hash with keys that map controller names + * to controller instances; if given, it will make the controllers + * available to directives. + * * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add + * the cloned elements; only needed for transcludes that are allowed to contain non html + * elements (e.g. SVG elements). See also the directive.controller property. + * + * Calling the linking function returns the element of the template. It is either the original + * element passed in, or the clone of the element if the `cloneAttachFn` is provided. + * + * After linking the view is not updated until after a call to $digest which typically is done by + * Angular automatically. + * + * If you need access to the bound view, there are two ways to do it: + * + * - If you are not asking the linking function to clone the template, create the DOM element(s) + * before you send them to the compiler and keep this reference around. + * ```js + * var element = $compile('

    {{total}}

    ')(scope); + * ``` + * + * - if on the other hand, you need the element to be cloned, the view reference from the original + * example would not point to the clone, but rather to the original template that was cloned. In + * this case, you can access the clone via the cloneAttachFn: + * ```js + * var templateElement = angular.element('

    {{total}}

    '), + * scope = ....; + * + * var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) { + * //attach the clone to DOM document at the right place + * }); + * + * //now we have reference to the cloned DOM via `clonedElement` + * ``` + * + * + * For information on how the compiler works, see the + * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide. + */ + +var $compileMinErr = minErr('$compile'); + +/** + * @ngdoc provider + * @name $compileProvider + * + * @description + */ +$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider']; +function $CompileProvider($provide, $$sanitizeUriProvider) { + var hasDirectives = {}, + Suffix = 'Directive', + COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/, + CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/, + ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'), + REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/; + + // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes + // The assumption is that future DOM event attribute names will begin with + // 'on' and be composed of only English letters. + var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/; + + function parseIsolateBindings(scope, directiveName) { + var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/; + + var bindings = {}; + + forEach(scope, function(definition, scopeName) { + var match = definition.match(LOCAL_REGEXP); + + if (!match) { + throw $compileMinErr('iscp', + "Invalid isolate scope definition for directive '{0}'." + + " Definition: {... {1}: '{2}' ...}", + directiveName, scopeName, definition); + } + + bindings[scopeName] = { + mode: match[1][0], + collection: match[2] === '*', + optional: match[3] === '?', + attrName: match[4] || scopeName + }; + }); + + return bindings; + } + + /** + * @ngdoc method + * @name $compileProvider#directive + * @kind function + * + * @description + * Register a new directive with the compiler. + * + * @param {string|Object} name Name of the directive in camel-case (i.e. ngBind which + * will match as ng-bind), or an object map of directives where the keys are the + * names and the values are the factories. + * @param {Function|Array} directiveFactory An injectable directive factory function. See + * {@link guide/directive} for more info. + * @returns {ng.$compileProvider} Self for chaining. + */ + this.directive = function registerDirective(name, directiveFactory) { + assertNotHasOwnProperty(name, 'directive'); + if (isString(name)) { + assertArg(directiveFactory, 'directiveFactory'); + if (!hasDirectives.hasOwnProperty(name)) { + hasDirectives[name] = []; + $provide.factory(name + Suffix, ['$injector', '$exceptionHandler', + function($injector, $exceptionHandler) { + var directives = []; + forEach(hasDirectives[name], function(directiveFactory, index) { + try { + var directive = $injector.invoke(directiveFactory); + if (isFunction(directive)) { + directive = { compile: valueFn(directive) }; + } else if (!directive.compile && directive.link) { + directive.compile = valueFn(directive.link); + } + directive.priority = directive.priority || 0; + directive.index = index; + directive.name = directive.name || name; + directive.require = directive.require || (directive.controller && directive.name); + directive.restrict = directive.restrict || 'EA'; + if (isObject(directive.scope)) { + directive.$$isolateBindings = parseIsolateBindings(directive.scope, directive.name); + } + directives.push(directive); + } catch (e) { + $exceptionHandler(e); + } + }); + return directives; + }]); + } + hasDirectives[name].push(directiveFactory); + } else { + forEach(name, reverseParams(registerDirective)); + } + return this; + }; + + + /** + * @ngdoc method + * @name $compileProvider#aHrefSanitizationWhitelist + * @kind function + * + * @description + * Retrieves or overrides the default regular expression that is used for whitelisting of safe + * urls during a[href] sanitization. + * + * The sanitization is a security measure aimed at preventing XSS attacks via html links. + * + * Any url about to be assigned to a[href] via data-binding is first normalized and turned into + * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist` + * regular expression. If a match is found, the original url is written into the dom. Otherwise, + * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM. + * + * @param {RegExp=} regexp New regexp to whitelist urls with. + * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for + * chaining otherwise. + */ + this.aHrefSanitizationWhitelist = function(regexp) { + if (isDefined(regexp)) { + $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp); + return this; + } else { + return $$sanitizeUriProvider.aHrefSanitizationWhitelist(); + } + }; + + + /** + * @ngdoc method + * @name $compileProvider#imgSrcSanitizationWhitelist + * @kind function + * + * @description + * Retrieves or overrides the default regular expression that is used for whitelisting of safe + * urls during img[src] sanitization. + * + * The sanitization is a security measure aimed at prevent XSS attacks via html links. + * + * Any url about to be assigned to img[src] via data-binding is first normalized and turned into + * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist` + * regular expression. If a match is found, the original url is written into the dom. Otherwise, + * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM. + * + * @param {RegExp=} regexp New regexp to whitelist urls with. + * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for + * chaining otherwise. + */ + this.imgSrcSanitizationWhitelist = function(regexp) { + if (isDefined(regexp)) { + $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp); + return this; + } else { + return $$sanitizeUriProvider.imgSrcSanitizationWhitelist(); + } + }; + + /** + * @ngdoc method + * @name $compileProvider#debugInfoEnabled + * + * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the + * current debugInfoEnabled state + * @returns {*} current value if used as getter or itself (chaining) if used as setter + * + * @kind function + * + * @description + * Call this method to enable/disable various debug runtime information in the compiler such as adding + * binding information and a reference to the current scope on to DOM elements. + * If enabled, the compiler will add the following to DOM elements that have been bound to the scope + * * `ng-binding` CSS class + * * `$binding` data property containing an array of the binding expressions + * + * You may want to disable this in production for a significant performance boost. See + * {@link guide/production#disabling-debug-data Disabling Debug Data} for more. + * + * The default value is true. + */ + var debugInfoEnabled = true; + this.debugInfoEnabled = function(enabled) { + if (isDefined(enabled)) { + debugInfoEnabled = enabled; + return this; + } + return debugInfoEnabled; + }; + + this.$get = [ + '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse', + '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri', + function($injector, $interpolate, $exceptionHandler, $templateRequest, $parse, + $controller, $rootScope, $document, $sce, $animate, $$sanitizeUri) { + + var Attributes = function(element, attributesToCopy) { + if (attributesToCopy) { + var keys = Object.keys(attributesToCopy); + var i, l, key; + + for (i = 0, l = keys.length; i < l; i++) { + key = keys[i]; + this[key] = attributesToCopy[key]; + } + } else { + this.$attr = {}; + } + + this.$$element = element; + }; + + Attributes.prototype = { + /** + * @ngdoc method + * @name $compile.directive.Attributes#$normalize + * @kind function + * + * @description + * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or + * `data-`) to its normalized, camelCase form. + * + * Also there is special case for Moz prefix starting with upper case letter. + * + * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives} + * + * @param {string} name Name to normalize + */ + $normalize: directiveNormalize, + + + /** + * @ngdoc method + * @name $compile.directive.Attributes#$addClass + * @kind function + * + * @description + * Adds the CSS class value specified by the classVal parameter to the element. If animations + * are enabled then an animation will be triggered for the class addition. + * + * @param {string} classVal The className value that will be added to the element + */ + $addClass: function(classVal) { + if (classVal && classVal.length > 0) { + $animate.addClass(this.$$element, classVal); + } + }, + + /** + * @ngdoc method + * @name $compile.directive.Attributes#$removeClass + * @kind function + * + * @description + * Removes the CSS class value specified by the classVal parameter from the element. If + * animations are enabled then an animation will be triggered for the class removal. + * + * @param {string} classVal The className value that will be removed from the element + */ + $removeClass: function(classVal) { + if (classVal && classVal.length > 0) { + $animate.removeClass(this.$$element, classVal); + } + }, + + /** + * @ngdoc method + * @name $compile.directive.Attributes#$updateClass + * @kind function + * + * @description + * Adds and removes the appropriate CSS class values to the element based on the difference + * between the new and old CSS class values (specified as newClasses and oldClasses). + * + * @param {string} newClasses The current CSS className value + * @param {string} oldClasses The former CSS className value + */ + $updateClass: function(newClasses, oldClasses) { + var toAdd = tokenDifference(newClasses, oldClasses); + if (toAdd && toAdd.length) { + $animate.addClass(this.$$element, toAdd); + } + + var toRemove = tokenDifference(oldClasses, newClasses); + if (toRemove && toRemove.length) { + $animate.removeClass(this.$$element, toRemove); + } + }, + + /** + * Set a normalized attribute on the element in a way such that all directives + * can share the attribute. This function properly handles boolean attributes. + * @param {string} key Normalized key. (ie ngAttribute) + * @param {string|boolean} value The value to set. If `null` attribute will be deleted. + * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute. + * Defaults to true. + * @param {string=} attrName Optional none normalized name. Defaults to key. + */ + $set: function(key, value, writeAttr, attrName) { + // TODO: decide whether or not to throw an error if "class" + //is set through this function since it may cause $updateClass to + //become unstable. + + var node = this.$$element[0], + booleanKey = getBooleanAttrName(node, key), + aliasedKey = getAliasedAttrName(node, key), + observer = key, + nodeName; + + if (booleanKey) { + this.$$element.prop(key, value); + attrName = booleanKey; + } else if (aliasedKey) { + this[aliasedKey] = value; + observer = aliasedKey; + } + + this[key] = value; + + // translate normalized key to actual key + if (attrName) { + this.$attr[key] = attrName; + } else { + attrName = this.$attr[key]; + if (!attrName) { + this.$attr[key] = attrName = snake_case(key, '-'); + } + } + + nodeName = nodeName_(this.$$element); + + if ((nodeName === 'a' && key === 'href') || + (nodeName === 'img' && key === 'src')) { + // sanitize a[href] and img[src] values + this[key] = value = $$sanitizeUri(value, key === 'src'); + } else if (nodeName === 'img' && key === 'srcset') { + // sanitize img[srcset] values + var result = ""; + + // first check if there are spaces because it's not the same pattern + var trimmedSrcset = trim(value); + // ( 999x ,| 999w ,| ,|, ) + var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/; + var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/; + + // split srcset into tuple of uri and descriptor except for the last item + var rawUris = trimmedSrcset.split(pattern); + + // for each tuples + var nbrUrisWith2parts = Math.floor(rawUris.length / 2); + for (var i = 0; i < nbrUrisWith2parts; i++) { + var innerIdx = i * 2; + // sanitize the uri + result += $$sanitizeUri(trim(rawUris[innerIdx]), true); + // add the descriptor + result += (" " + trim(rawUris[innerIdx + 1])); + } + + // split the last item into uri and descriptor + var lastTuple = trim(rawUris[i * 2]).split(/\s/); + + // sanitize the last uri + result += $$sanitizeUri(trim(lastTuple[0]), true); + + // and add the last descriptor if any + if (lastTuple.length === 2) { + result += (" " + trim(lastTuple[1])); + } + this[key] = value = result; + } + + if (writeAttr !== false) { + if (value === null || value === undefined) { + this.$$element.removeAttr(attrName); + } else { + this.$$element.attr(attrName, value); + } + } + + // fire observers + var $$observers = this.$$observers; + $$observers && forEach($$observers[observer], function(fn) { + try { + fn(value); + } catch (e) { + $exceptionHandler(e); + } + }); + }, + + + /** + * @ngdoc method + * @name $compile.directive.Attributes#$observe + * @kind function + * + * @description + * Observes an interpolated attribute. + * + * The observer function will be invoked once during the next `$digest` following + * compilation. The observer is then invoked whenever the interpolated value + * changes. + * + * @param {string} key Normalized key. (ie ngAttribute) . + * @param {function(interpolatedValue)} fn Function that will be called whenever + the interpolated value of the attribute changes. + * See the {@link guide/directive#text-and-attribute-bindings Directives} guide for more info. + * @returns {function()} Returns a deregistration function for this observer. + */ + $observe: function(key, fn) { + var attrs = this, + $$observers = (attrs.$$observers || (attrs.$$observers = createMap())), + listeners = ($$observers[key] || ($$observers[key] = [])); + + listeners.push(fn); + $rootScope.$evalAsync(function() { + if (!listeners.$$inter && attrs.hasOwnProperty(key)) { + // no one registered attribute interpolation function, so lets call it manually + fn(attrs[key]); + } + }); + + return function() { + arrayRemove(listeners, fn); + }; + } + }; + + + function safeAddClass($element, className) { + try { + $element.addClass(className); + } catch (e) { + // ignore, since it means that we are trying to set class on + // SVG element, where class name is read-only. + } + } + + + var startSymbol = $interpolate.startSymbol(), + endSymbol = $interpolate.endSymbol(), + denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}') + ? identity + : function denormalizeTemplate(template) { + return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol); + }, + NG_ATTR_BINDING = /^ngAttr[A-Z]/; + + compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) { + var bindings = $element.data('$binding') || []; + + if (isArray(binding)) { + bindings = bindings.concat(binding); + } else { + bindings.push(binding); + } + + $element.data('$binding', bindings); + } : noop; + + compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) { + safeAddClass($element, 'ng-binding'); + } : noop; + + compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) { + var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope'; + $element.data(dataName, scope); + } : noop; + + compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) { + safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope'); + } : noop; + + return compile; + + //================================ + + function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, + previousCompileContext) { + if (!($compileNodes instanceof jqLite)) { + // jquery always rewraps, whereas we need to preserve the original selector so that we can + // modify it. + $compileNodes = jqLite($compileNodes); + } + // We can not compile top level text elements since text nodes can be merged and we will + // not be able to attach scope data to them, so we will wrap them in + forEach($compileNodes, function(node, index) { + if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */ ) { + $compileNodes[index] = jqLite(node).wrap('').parent()[0]; + } + }); + var compositeLinkFn = + compileNodes($compileNodes, transcludeFn, $compileNodes, + maxPriority, ignoreDirective, previousCompileContext); + compile.$$addScopeClass($compileNodes); + var namespace = null; + return function publicLinkFn(scope, cloneConnectFn, options) { + assertArg(scope, 'scope'); + + options = options || {}; + var parentBoundTranscludeFn = options.parentBoundTranscludeFn, + transcludeControllers = options.transcludeControllers, + futureParentElement = options.futureParentElement; + + // When `parentBoundTranscludeFn` is passed, it is a + // `controllersBoundTransclude` function (it was previously passed + // as `transclude` to directive.link) so we must unwrap it to get + // its `boundTranscludeFn` + if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) { + parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude; + } + + if (!namespace) { + namespace = detectNamespaceForChildElements(futureParentElement); + } + var $linkNode; + if (namespace !== 'html') { + // When using a directive with replace:true and templateUrl the $compileNodes + // (or a child element inside of them) + // might change, so we need to recreate the namespace adapted compileNodes + // for call to the link function. + // Note: This will already clone the nodes... + $linkNode = jqLite( + wrapTemplate(namespace, jqLite('
    ').append($compileNodes).html()) + ); + } else if (cloneConnectFn) { + // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart + // and sometimes changes the structure of the DOM. + $linkNode = JQLitePrototype.clone.call($compileNodes); + } else { + $linkNode = $compileNodes; + } + + if (transcludeControllers) { + for (var controllerName in transcludeControllers) { + $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance); + } + } + + compile.$$addScopeInfo($linkNode, scope); + + if (cloneConnectFn) cloneConnectFn($linkNode, scope); + if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn); + return $linkNode; + }; + } + + function detectNamespaceForChildElements(parentElement) { + // TODO: Make this detect MathML as well... + var node = parentElement && parentElement[0]; + if (!node) { + return 'html'; + } else { + return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html'; + } + } + + /** + * Compile function matches each node in nodeList against the directives. Once all directives + * for a particular node are collected their compile functions are executed. The compile + * functions return values - the linking functions - are combined into a composite linking + * function, which is the a linking function for the node. + * + * @param {NodeList} nodeList an array of nodes or NodeList to compile + * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the + * scope argument is auto-generated to the new child of the transcluded parent scope. + * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then + * the rootElement must be set the jqLite collection of the compile root. This is + * needed so that the jqLite collection items can be replaced with widgets. + * @param {number=} maxPriority Max directive priority. + * @returns {Function} A composite linking function of all of the matched directives or null. + */ + function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective, + previousCompileContext) { + var linkFns = [], + attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound; + + for (var i = 0; i < nodeList.length; i++) { + attrs = new Attributes(); + + // we must always refer to nodeList[i] since the nodes can be replaced underneath us. + directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined, + ignoreDirective); + + nodeLinkFn = (directives.length) + ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement, + null, [], [], previousCompileContext) + : null; + + if (nodeLinkFn && nodeLinkFn.scope) { + compile.$$addScopeClass(attrs.$$element); + } + + childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || + !(childNodes = nodeList[i].childNodes) || + !childNodes.length) + ? null + : compileNodes(childNodes, + nodeLinkFn ? ( + (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement) + && nodeLinkFn.transclude) : transcludeFn); + + if (nodeLinkFn || childLinkFn) { + linkFns.push(i, nodeLinkFn, childLinkFn); + linkFnFound = true; + nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn; + } + + //use the previous context only for the first element in the virtual group + previousCompileContext = null; + } + + // return a linking function if we have found anything, null otherwise + return linkFnFound ? compositeLinkFn : null; + + function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) { + var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn; + var stableNodeList; + + + if (nodeLinkFnFound) { + // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our + // offsets don't get screwed up + var nodeListLength = nodeList.length; + stableNodeList = new Array(nodeListLength); + + // create a sparse array by only copying the elements which have a linkFn + for (i = 0; i < linkFns.length; i+=3) { + idx = linkFns[i]; + stableNodeList[idx] = nodeList[idx]; + } + } else { + stableNodeList = nodeList; + } + + for (i = 0, ii = linkFns.length; i < ii;) { + node = stableNodeList[linkFns[i++]]; + nodeLinkFn = linkFns[i++]; + childLinkFn = linkFns[i++]; + + if (nodeLinkFn) { + if (nodeLinkFn.scope) { + childScope = scope.$new(); + compile.$$addScopeInfo(jqLite(node), childScope); + } else { + childScope = scope; + } + + if (nodeLinkFn.transcludeOnThisElement) { + childBoundTranscludeFn = createBoundTranscludeFn( + scope, nodeLinkFn.transclude, parentBoundTranscludeFn, + nodeLinkFn.elementTranscludeOnThisElement); + + } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) { + childBoundTranscludeFn = parentBoundTranscludeFn; + + } else if (!parentBoundTranscludeFn && transcludeFn) { + childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn); + + } else { + childBoundTranscludeFn = null; + } + + nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn); + + } else if (childLinkFn) { + childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn); + } + } + } + } + + function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn, elementTransclusion) { + + var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) { + + if (!transcludedScope) { + transcludedScope = scope.$new(false, containingScope); + transcludedScope.$$transcluded = true; + } + + return transcludeFn(transcludedScope, cloneFn, { + parentBoundTranscludeFn: previousBoundTranscludeFn, + transcludeControllers: controllers, + futureParentElement: futureParentElement + }); + }; + + return boundTranscludeFn; + } + + /** + * Looks for directives on the given node and adds them to the directive collection which is + * sorted. + * + * @param node Node to search. + * @param directives An array to which the directives are added to. This array is sorted before + * the function returns. + * @param attrs The shared attrs object which is used to populate the normalized attributes. + * @param {number=} maxPriority Max directive priority. + */ + function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) { + var nodeType = node.nodeType, + attrsMap = attrs.$attr, + match, + className; + + switch (nodeType) { + case NODE_TYPE_ELEMENT: /* Element */ + // use the node name: + addDirective(directives, + directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective); + + // iterate over the attributes + for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes, + j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) { + var attrStartName = false; + var attrEndName = false; + + attr = nAttrs[j]; + name = attr.name; + value = trim(attr.value); + + // support ngAttr attribute binding + ngAttrName = directiveNormalize(name); + if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) { + name = name.replace(PREFIX_REGEXP, '') + .substr(8).replace(/_(.)/g, function(match, letter) { + return letter.toUpperCase(); + }); + } + + var directiveNName = ngAttrName.replace(/(Start|End)$/, ''); + if (directiveIsMultiElement(directiveNName)) { + if (ngAttrName === directiveNName + 'Start') { + attrStartName = name; + attrEndName = name.substr(0, name.length - 5) + 'end'; + name = name.substr(0, name.length - 6); + } + } + + nName = directiveNormalize(name.toLowerCase()); + attrsMap[nName] = name; + if (isNgAttr || !attrs.hasOwnProperty(nName)) { + attrs[nName] = value; + if (getBooleanAttrName(node, nName)) { + attrs[nName] = true; // presence means true + } + } + addAttrInterpolateDirective(node, directives, value, nName, isNgAttr); + addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName, + attrEndName); + } + + // use class as directive + className = node.className; + if (isObject(className)) { + // Maybe SVGAnimatedString + className = className.animVal; + } + if (isString(className) && className !== '') { + while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) { + nName = directiveNormalize(match[2]); + if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) { + attrs[nName] = trim(match[3]); + } + className = className.substr(match.index + match[0].length); + } + } + break; + case NODE_TYPE_TEXT: /* Text Node */ + addTextInterpolateDirective(directives, node.nodeValue); + break; + case NODE_TYPE_COMMENT: /* Comment */ + try { + match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue); + if (match) { + nName = directiveNormalize(match[1]); + if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) { + attrs[nName] = trim(match[2]); + } + } + } catch (e) { + // turns out that under some circumstances IE9 throws errors when one attempts to read + // comment's node value. + // Just ignore it and continue. (Can't seem to reproduce in test case.) + } + break; + } + + directives.sort(byPriority); + return directives; + } + + /** + * Given a node with an directive-start it collects all of the siblings until it finds + * directive-end. + * @param node + * @param attrStart + * @param attrEnd + * @returns {*} + */ + function groupScan(node, attrStart, attrEnd) { + var nodes = []; + var depth = 0; + if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) { + do { + if (!node) { + throw $compileMinErr('uterdir', + "Unterminated attribute, found '{0}' but no matching '{1}' found.", + attrStart, attrEnd); + } + if (node.nodeType == NODE_TYPE_ELEMENT) { + if (node.hasAttribute(attrStart)) depth++; + if (node.hasAttribute(attrEnd)) depth--; + } + nodes.push(node); + node = node.nextSibling; + } while (depth > 0); + } else { + nodes.push(node); + } + + return jqLite(nodes); + } + + /** + * Wrapper for linking function which converts normal linking function into a grouped + * linking function. + * @param linkFn + * @param attrStart + * @param attrEnd + * @returns {Function} + */ + function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) { + return function(scope, element, attrs, controllers, transcludeFn) { + element = groupScan(element[0], attrStart, attrEnd); + return linkFn(scope, element, attrs, controllers, transcludeFn); + }; + } + + /** + * Once the directives have been collected, their compile functions are executed. This method + * is responsible for inlining directive templates as well as terminating the application + * of the directives if the terminal directive has been reached. + * + * @param {Array} directives Array of collected directives to execute their compile function. + * this needs to be pre-sorted by priority order. + * @param {Node} compileNode The raw DOM node to apply the compile functions to + * @param {Object} templateAttrs The shared attribute function + * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the + * scope argument is auto-generated to the new + * child of the transcluded parent scope. + * @param {JQLite} jqCollection If we are working on the root of the compile tree then this + * argument has the root jqLite array so that we can replace nodes + * on it. + * @param {Object=} originalReplaceDirective An optional directive that will be ignored when + * compiling the transclusion. + * @param {Array.} preLinkFns + * @param {Array.} postLinkFns + * @param {Object} previousCompileContext Context used for previous compilation of the current + * node + * @returns {Function} linkFn + */ + function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, + jqCollection, originalReplaceDirective, preLinkFns, postLinkFns, + previousCompileContext) { + previousCompileContext = previousCompileContext || {}; + + var terminalPriority = -Number.MAX_VALUE, + newScopeDirective, + controllerDirectives = previousCompileContext.controllerDirectives, + controllers, + newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective, + templateDirective = previousCompileContext.templateDirective, + nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective, + hasTranscludeDirective = false, + hasTemplate = false, + hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective, + $compileNode = templateAttrs.$$element = jqLite(compileNode), + directive, + directiveName, + $template, + replaceDirective = originalReplaceDirective, + childTranscludeFn = transcludeFn, + linkFn, + directiveValue; + + // executes all directives on the current element + for (var i = 0, ii = directives.length; i < ii; i++) { + directive = directives[i]; + var attrStart = directive.$$start; + var attrEnd = directive.$$end; + + // collect multiblock sections + if (attrStart) { + $compileNode = groupScan(compileNode, attrStart, attrEnd); + } + $template = undefined; + + if (terminalPriority > directive.priority) { + break; // prevent further processing of directives + } + + if (directiveValue = directive.scope) { + + // skip the check for directives with async templates, we'll check the derived sync + // directive when the template arrives + if (!directive.templateUrl) { + if (isObject(directiveValue)) { + // This directive is trying to add an isolated scope. + // Check that there is no scope of any kind already + assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective, + directive, $compileNode); + newIsolateScopeDirective = directive; + } else { + // This directive is trying to add a child scope. + // Check that there is no isolated scope already + assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive, + $compileNode); + } + } + + newScopeDirective = newScopeDirective || directive; + } + + directiveName = directive.name; + + if (!directive.templateUrl && directive.controller) { + directiveValue = directive.controller; + controllerDirectives = controllerDirectives || {}; + assertNoDuplicate("'" + directiveName + "' controller", + controllerDirectives[directiveName], directive, $compileNode); + controllerDirectives[directiveName] = directive; + } + + if (directiveValue = directive.transclude) { + hasTranscludeDirective = true; + + // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion. + // This option should only be used by directives that know how to safely handle element transclusion, + // where the transcluded nodes are added or replaced after linking. + if (!directive.$$tlb) { + assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode); + nonTlbTranscludeDirective = directive; + } + + if (directiveValue == 'element') { + hasElementTranscludeDirective = true; + terminalPriority = directive.priority; + $template = $compileNode; + $compileNode = templateAttrs.$$element = + jqLite(document.createComment(' ' + directiveName + ': ' + + templateAttrs[directiveName] + ' ')); + compileNode = $compileNode[0]; + replaceWith(jqCollection, sliceArgs($template), compileNode); + + childTranscludeFn = compile($template, transcludeFn, terminalPriority, + replaceDirective && replaceDirective.name, { + // Don't pass in: + // - controllerDirectives - otherwise we'll create duplicates controllers + // - newIsolateScopeDirective or templateDirective - combining templates with + // element transclusion doesn't make sense. + // + // We need only nonTlbTranscludeDirective so that we prevent putting transclusion + // on the same element more than once. + nonTlbTranscludeDirective: nonTlbTranscludeDirective + }); + } else { + $template = jqLite(jqLiteClone(compileNode)).contents(); + $compileNode.empty(); // clear contents + childTranscludeFn = compile($template, transcludeFn); + } + } + + if (directive.template) { + hasTemplate = true; + assertNoDuplicate('template', templateDirective, directive, $compileNode); + templateDirective = directive; + + directiveValue = (isFunction(directive.template)) + ? directive.template($compileNode, templateAttrs) + : directive.template; + + directiveValue = denormalizeTemplate(directiveValue); + + if (directive.replace) { + replaceDirective = directive; + if (jqLiteIsTextNode(directiveValue)) { + $template = []; + } else { + $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue))); + } + compileNode = $template[0]; + + if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) { + throw $compileMinErr('tplrt', + "Template for directive '{0}' must have exactly one root element. {1}", + directiveName, ''); + } + + replaceWith(jqCollection, $compileNode, compileNode); + + var newTemplateAttrs = {$attr: {}}; + + // combine directives from the original node and from the template: + // - take the array of directives for this element + // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed) + // - collect directives from the template and sort them by priority + // - combine directives as: processed + template + unprocessed + var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs); + var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1)); + + if (newIsolateScopeDirective) { + markDirectivesAsIsolate(templateDirectives); + } + directives = directives.concat(templateDirectives).concat(unprocessedDirectives); + mergeTemplateAttributes(templateAttrs, newTemplateAttrs); + + ii = directives.length; + } else { + $compileNode.html(directiveValue); + } + } + + if (directive.templateUrl) { + hasTemplate = true; + assertNoDuplicate('template', templateDirective, directive, $compileNode); + templateDirective = directive; + + if (directive.replace) { + replaceDirective = directive; + } + + nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode, + templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, { + controllerDirectives: controllerDirectives, + newIsolateScopeDirective: newIsolateScopeDirective, + templateDirective: templateDirective, + nonTlbTranscludeDirective: nonTlbTranscludeDirective + }); + ii = directives.length; + } else if (directive.compile) { + try { + linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn); + if (isFunction(linkFn)) { + addLinkFns(null, linkFn, attrStart, attrEnd); + } else if (linkFn) { + addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd); + } + } catch (e) { + $exceptionHandler(e, startingTag($compileNode)); + } + } + + if (directive.terminal) { + nodeLinkFn.terminal = true; + terminalPriority = Math.max(terminalPriority, directive.priority); + } + + } + + nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true; + nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective; + nodeLinkFn.elementTranscludeOnThisElement = hasElementTranscludeDirective; + nodeLinkFn.templateOnThisElement = hasTemplate; + nodeLinkFn.transclude = childTranscludeFn; + + previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective; + + // might be normal or delayed nodeLinkFn depending on if templateUrl is present + return nodeLinkFn; + + //////////////////// + + function addLinkFns(pre, post, attrStart, attrEnd) { + if (pre) { + if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd); + pre.require = directive.require; + pre.directiveName = directiveName; + if (newIsolateScopeDirective === directive || directive.$$isolateScope) { + pre = cloneAndAnnotateFn(pre, {isolateScope: true}); + } + preLinkFns.push(pre); + } + if (post) { + if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd); + post.require = directive.require; + post.directiveName = directiveName; + if (newIsolateScopeDirective === directive || directive.$$isolateScope) { + post = cloneAndAnnotateFn(post, {isolateScope: true}); + } + postLinkFns.push(post); + } + } + + + function getControllers(directiveName, require, $element, elementControllers) { + var value, retrievalMethod = 'data', optional = false; + var $searchElement = $element; + var match; + if (isString(require)) { + match = require.match(REQUIRE_PREFIX_REGEXP); + require = require.substring(match[0].length); + + if (match[3]) { + if (match[1]) match[3] = null; + else match[1] = match[3]; + } + if (match[1] === '^') { + retrievalMethod = 'inheritedData'; + } else if (match[1] === '^^') { + retrievalMethod = 'inheritedData'; + $searchElement = $element.parent(); + } + if (match[2] === '?') { + optional = true; + } + + value = null; + + if (elementControllers && retrievalMethod === 'data') { + if (value = elementControllers[require]) { + value = value.instance; + } + } + value = value || $searchElement[retrievalMethod]('$' + require + 'Controller'); + + if (!value && !optional) { + throw $compileMinErr('ctreq', + "Controller '{0}', required by directive '{1}', can't be found!", + require, directiveName); + } + return value || null; + } else if (isArray(require)) { + value = []; + forEach(require, function(require) { + value.push(getControllers(directiveName, require, $element, elementControllers)); + }); + } + return value; + } + + + function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) { + var i, ii, linkFn, controller, isolateScope, elementControllers, transcludeFn, $element, + attrs; + + if (compileNode === linkNode) { + attrs = templateAttrs; + $element = templateAttrs.$$element; + } else { + $element = jqLite(linkNode); + attrs = new Attributes($element, templateAttrs); + } + + if (newIsolateScopeDirective) { + isolateScope = scope.$new(true); + } + + if (boundTranscludeFn) { + // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn` + // is later passed as `parentBoundTranscludeFn` to `publicLinkFn` + transcludeFn = controllersBoundTransclude; + transcludeFn.$$boundTransclude = boundTranscludeFn; + } + + if (controllerDirectives) { + // TODO: merge `controllers` and `elementControllers` into single object. + controllers = {}; + elementControllers = {}; + forEach(controllerDirectives, function(directive) { + var locals = { + $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope, + $element: $element, + $attrs: attrs, + $transclude: transcludeFn + }, controllerInstance; + + controller = directive.controller; + if (controller == '@') { + controller = attrs[directive.name]; + } + + controllerInstance = $controller(controller, locals, true, directive.controllerAs); + + // For directives with element transclusion the element is a comment, + // but jQuery .data doesn't support attaching data to comment nodes as it's hard to + // clean up (http://bugs.jquery.com/ticket/8335). + // Instead, we save the controllers for the element in a local hash and attach to .data + // later, once we have the actual element. + elementControllers[directive.name] = controllerInstance; + if (!hasElementTranscludeDirective) { + $element.data('$' + directive.name + 'Controller', controllerInstance.instance); + } + + controllers[directive.name] = controllerInstance; + }); + } + + if (newIsolateScopeDirective) { + compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective || + templateDirective === newIsolateScopeDirective.$$originalDirective))); + compile.$$addScopeClass($element, true); + + var isolateScopeController = controllers && controllers[newIsolateScopeDirective.name]; + var isolateBindingContext = isolateScope; + if (isolateScopeController && isolateScopeController.identifier && + newIsolateScopeDirective.bindToController === true) { + isolateBindingContext = isolateScopeController.instance; + } + + forEach(isolateScope.$$isolateBindings = newIsolateScopeDirective.$$isolateBindings, function(definition, scopeName) { + var attrName = definition.attrName, + optional = definition.optional, + mode = definition.mode, // @, =, or & + lastValue, + parentGet, parentSet, compare; + + switch (mode) { + + case '@': + attrs.$observe(attrName, function(value) { + isolateBindingContext[scopeName] = value; + }); + attrs.$$observers[attrName].$$scope = scope; + if (attrs[attrName]) { + // If the attribute has been provided then we trigger an interpolation to ensure + // the value is there for use in the link fn + isolateBindingContext[scopeName] = $interpolate(attrs[attrName])(scope); + } + break; + + case '=': + if (optional && !attrs[attrName]) { + return; + } + parentGet = $parse(attrs[attrName]); + if (parentGet.literal) { + compare = equals; + } else { + compare = function(a, b) { return a === b || (a !== a && b !== b); }; + } + parentSet = parentGet.assign || function() { + // reset the change, or we will throw this exception on every $digest + lastValue = isolateBindingContext[scopeName] = parentGet(scope); + throw $compileMinErr('nonassign', + "Expression '{0}' used with directive '{1}' is non-assignable!", + attrs[attrName], newIsolateScopeDirective.name); + }; + lastValue = isolateBindingContext[scopeName] = parentGet(scope); + var parentValueWatch = function parentValueWatch(parentValue) { + if (!compare(parentValue, isolateBindingContext[scopeName])) { + // we are out of sync and need to copy + if (!compare(parentValue, lastValue)) { + // parent changed and it has precedence + isolateBindingContext[scopeName] = parentValue; + } else { + // if the parent can be assigned then do so + parentSet(scope, parentValue = isolateBindingContext[scopeName]); + } + } + return lastValue = parentValue; + }; + parentValueWatch.$stateful = true; + var unwatch; + if (definition.collection) { + unwatch = scope.$watchCollection(attrs[attrName], parentValueWatch); + } else { + unwatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal); + } + isolateScope.$on('$destroy', unwatch); + break; + + case '&': + parentGet = $parse(attrs[attrName]); + isolateBindingContext[scopeName] = function(locals) { + return parentGet(scope, locals); + }; + break; + } + }); + } + if (controllers) { + forEach(controllers, function(controller) { + controller(); + }); + controllers = null; + } + + // PRELINKING + for (i = 0, ii = preLinkFns.length; i < ii; i++) { + linkFn = preLinkFns[i]; + invokeLinkFn(linkFn, + linkFn.isolateScope ? isolateScope : scope, + $element, + attrs, + linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), + transcludeFn + ); + } + + // RECURSION + // We only pass the isolate scope, if the isolate directive has a template, + // otherwise the child elements do not belong to the isolate directive. + var scopeToChild = scope; + if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) { + scopeToChild = isolateScope; + } + childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn); + + // POSTLINKING + for (i = postLinkFns.length - 1; i >= 0; i--) { + linkFn = postLinkFns[i]; + invokeLinkFn(linkFn, + linkFn.isolateScope ? isolateScope : scope, + $element, + attrs, + linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), + transcludeFn + ); + } + + // This is the function that is injected as `$transclude`. + // Note: all arguments are optional! + function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement) { + var transcludeControllers; + + // No scope passed in: + if (!isScope(scope)) { + futureParentElement = cloneAttachFn; + cloneAttachFn = scope; + scope = undefined; + } + + if (hasElementTranscludeDirective) { + transcludeControllers = elementControllers; + } + if (!futureParentElement) { + futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element; + } + return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild); + } + } + } + + function markDirectivesAsIsolate(directives) { + // mark all directives as needing isolate scope. + for (var j = 0, jj = directives.length; j < jj; j++) { + directives[j] = inherit(directives[j], {$$isolateScope: true}); + } + } + + /** + * looks up the directive and decorates it with exception handling and proper parameters. We + * call this the boundDirective. + * + * @param {string} name name of the directive to look up. + * @param {string} location The directive must be found in specific format. + * String containing any of theses characters: + * + * * `E`: element name + * * `A': attribute + * * `C`: class + * * `M`: comment + * @returns {boolean} true if directive was added. + */ + function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName, + endAttrName) { + if (name === ignoreDirective) return null; + var match = null; + if (hasDirectives.hasOwnProperty(name)) { + for (var directive, directives = $injector.get(name + Suffix), + i = 0, ii = directives.length; i < ii; i++) { + try { + directive = directives[i]; + if ((maxPriority === undefined || maxPriority > directive.priority) && + directive.restrict.indexOf(location) != -1) { + if (startAttrName) { + directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName}); + } + tDirectives.push(directive); + match = directive; + } + } catch (e) { $exceptionHandler(e); } + } + } + return match; + } + + + /** + * looks up the directive and returns true if it is a multi-element directive, + * and therefore requires DOM nodes between -start and -end markers to be grouped + * together. + * + * @param {string} name name of the directive to look up. + * @returns true if directive was registered as multi-element. + */ + function directiveIsMultiElement(name) { + if (hasDirectives.hasOwnProperty(name)) { + for (var directive, directives = $injector.get(name + Suffix), + i = 0, ii = directives.length; i < ii; i++) { + directive = directives[i]; + if (directive.multiElement) { + return true; + } + } + } + return false; + } + + /** + * When the element is replaced with HTML template then the new attributes + * on the template need to be merged with the existing attributes in the DOM. + * The desired effect is to have both of the attributes present. + * + * @param {object} dst destination attributes (original DOM) + * @param {object} src source attributes (from the directive template) + */ + function mergeTemplateAttributes(dst, src) { + var srcAttr = src.$attr, + dstAttr = dst.$attr, + $element = dst.$$element; + + // reapply the old attributes to the new element + forEach(dst, function(value, key) { + if (key.charAt(0) != '$') { + if (src[key] && src[key] !== value) { + value += (key === 'style' ? ';' : ' ') + src[key]; + } + dst.$set(key, value, true, srcAttr[key]); + } + }); + + // copy the new attributes on the old attrs object + forEach(src, function(value, key) { + if (key == 'class') { + safeAddClass($element, value); + dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value; + } else if (key == 'style') { + $element.attr('style', $element.attr('style') + ';' + value); + dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value; + // `dst` will never contain hasOwnProperty as DOM parser won't let it. + // You will get an "InvalidCharacterError: DOM Exception 5" error if you + // have an attribute like "has-own-property" or "data-has-own-property", etc. + } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) { + dst[key] = value; + dstAttr[key] = srcAttr[key]; + } + }); + } + + + function compileTemplateUrl(directives, $compileNode, tAttrs, + $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) { + var linkQueue = [], + afterTemplateNodeLinkFn, + afterTemplateChildLinkFn, + beforeTemplateCompileNode = $compileNode[0], + origAsyncDirective = directives.shift(), + derivedSyncDirective = inherit(origAsyncDirective, { + templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective + }), + templateUrl = (isFunction(origAsyncDirective.templateUrl)) + ? origAsyncDirective.templateUrl($compileNode, tAttrs) + : origAsyncDirective.templateUrl, + templateNamespace = origAsyncDirective.templateNamespace; + + $compileNode.empty(); + + $templateRequest($sce.getTrustedResourceUrl(templateUrl)) + .then(function(content) { + var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn; + + content = denormalizeTemplate(content); + + if (origAsyncDirective.replace) { + if (jqLiteIsTextNode(content)) { + $template = []; + } else { + $template = removeComments(wrapTemplate(templateNamespace, trim(content))); + } + compileNode = $template[0]; + + if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) { + throw $compileMinErr('tplrt', + "Template for directive '{0}' must have exactly one root element. {1}", + origAsyncDirective.name, templateUrl); + } + + tempTemplateAttrs = {$attr: {}}; + replaceWith($rootElement, $compileNode, compileNode); + var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs); + + if (isObject(origAsyncDirective.scope)) { + markDirectivesAsIsolate(templateDirectives); + } + directives = templateDirectives.concat(directives); + mergeTemplateAttributes(tAttrs, tempTemplateAttrs); + } else { + compileNode = beforeTemplateCompileNode; + $compileNode.html(content); + } + + directives.unshift(derivedSyncDirective); + + afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, + childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns, + previousCompileContext); + forEach($rootElement, function(node, i) { + if (node == compileNode) { + $rootElement[i] = $compileNode[0]; + } + }); + afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn); + + while (linkQueue.length) { + var scope = linkQueue.shift(), + beforeTemplateLinkNode = linkQueue.shift(), + linkRootElement = linkQueue.shift(), + boundTranscludeFn = linkQueue.shift(), + linkNode = $compileNode[0]; + + if (scope.$$destroyed) continue; + + if (beforeTemplateLinkNode !== beforeTemplateCompileNode) { + var oldClasses = beforeTemplateLinkNode.className; + + if (!(previousCompileContext.hasElementTranscludeDirective && + origAsyncDirective.replace)) { + // it was cloned therefore we have to clone as well. + linkNode = jqLiteClone(compileNode); + } + replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode); + + // Copy in CSS classes from original node + safeAddClass(jqLite(linkNode), oldClasses); + } + if (afterTemplateNodeLinkFn.transcludeOnThisElement) { + childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn); + } else { + childBoundTranscludeFn = boundTranscludeFn; + } + afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement, + childBoundTranscludeFn); + } + linkQueue = null; + }); + + return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) { + var childBoundTranscludeFn = boundTranscludeFn; + if (scope.$$destroyed) return; + if (linkQueue) { + linkQueue.push(scope, + node, + rootElement, + childBoundTranscludeFn); + } else { + if (afterTemplateNodeLinkFn.transcludeOnThisElement) { + childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn); + } + afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn); + } + }; + } + + + /** + * Sorting function for bound directives. + */ + function byPriority(a, b) { + var diff = b.priority - a.priority; + if (diff !== 0) return diff; + if (a.name !== b.name) return (a.name < b.name) ? -1 : 1; + return a.index - b.index; + } + + + function assertNoDuplicate(what, previousDirective, directive, element) { + if (previousDirective) { + throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}', + previousDirective.name, directive.name, what, startingTag(element)); + } + } + + + function addTextInterpolateDirective(directives, text) { + var interpolateFn = $interpolate(text, true); + if (interpolateFn) { + directives.push({ + priority: 0, + compile: function textInterpolateCompileFn(templateNode) { + var templateNodeParent = templateNode.parent(), + hasCompileParent = !!templateNodeParent.length; + + // When transcluding a template that has bindings in the root + // we don't have a parent and thus need to add the class during linking fn. + if (hasCompileParent) compile.$$addBindingClass(templateNodeParent); + + return function textInterpolateLinkFn(scope, node) { + var parent = node.parent(); + if (!hasCompileParent) compile.$$addBindingClass(parent); + compile.$$addBindingInfo(parent, interpolateFn.expressions); + scope.$watch(interpolateFn, function interpolateFnWatchAction(value) { + node[0].nodeValue = value; + }); + }; + } + }); + } + } + + + function wrapTemplate(type, template) { + type = lowercase(type || 'html'); + switch (type) { + case 'svg': + case 'math': + var wrapper = document.createElement('div'); + wrapper.innerHTML = '<' + type + '>' + template + ''; + return wrapper.childNodes[0].childNodes; + default: + return template; + } + } + + + function getTrustedContext(node, attrNormalizedName) { + if (attrNormalizedName == "srcdoc") { + return $sce.HTML; + } + var tag = nodeName_(node); + // maction[xlink:href] can source SVG. It's not limited to . + if (attrNormalizedName == "xlinkHref" || + (tag == "form" && attrNormalizedName == "action") || + (tag != "img" && (attrNormalizedName == "src" || + attrNormalizedName == "ngSrc"))) { + return $sce.RESOURCE_URL; + } + } + + + function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) { + var trustedContext = getTrustedContext(node, name); + allOrNothing = ALL_OR_NOTHING_ATTRS[name] || allOrNothing; + + var interpolateFn = $interpolate(value, true, trustedContext, allOrNothing); + + // no interpolation found -> ignore + if (!interpolateFn) return; + + + if (name === "multiple" && nodeName_(node) === "select") { + throw $compileMinErr("selmulti", + "Binding to the 'multiple' attribute is not supported. Element: {0}", + startingTag(node)); + } + + directives.push({ + priority: 100, + compile: function() { + return { + pre: function attrInterpolatePreLinkFn(scope, element, attr) { + var $$observers = (attr.$$observers || (attr.$$observers = {})); + + if (EVENT_HANDLER_ATTR_REGEXP.test(name)) { + throw $compileMinErr('nodomevents', + "Interpolations for HTML DOM event attributes are disallowed. Please use the " + + "ng- versions (such as ng-click instead of onclick) instead."); + } + + // If the attribute has changed since last $interpolate()ed + var newValue = attr[name]; + if (newValue !== value) { + // we need to interpolate again since the attribute value has been updated + // (e.g. by another directive's compile function) + // ensure unset/empty values make interpolateFn falsy + interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing); + value = newValue; + } + + // if attribute was updated so that there is no interpolation going on we don't want to + // register any observers + if (!interpolateFn) return; + + // initialize attr object so that it's ready in case we need the value for isolate + // scope initialization, otherwise the value would not be available from isolate + // directive's linking fn during linking phase + attr[name] = interpolateFn(scope); + + ($$observers[name] || ($$observers[name] = [])).$$inter = true; + (attr.$$observers && attr.$$observers[name].$$scope || scope). + $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) { + //special case for class attribute addition + removal + //so that class changes can tap into the animation + //hooks provided by the $animate service. Be sure to + //skip animations when the first digest occurs (when + //both the new and the old values are the same) since + //the CSS classes are the non-interpolated values + if (name === 'class' && newValue != oldValue) { + attr.$updateClass(newValue, oldValue); + } else { + attr.$set(name, newValue); + } + }); + } + }; + } + }); + } + + + /** + * This is a special jqLite.replaceWith, which can replace items which + * have no parents, provided that the containing jqLite collection is provided. + * + * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes + * in the root of the tree. + * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep + * the shell, but replace its DOM node reference. + * @param {Node} newNode The new DOM node. + */ + function replaceWith($rootElement, elementsToRemove, newNode) { + var firstElementToRemove = elementsToRemove[0], + removeCount = elementsToRemove.length, + parent = firstElementToRemove.parentNode, + i, ii; + + if ($rootElement) { + for (i = 0, ii = $rootElement.length; i < ii; i++) { + if ($rootElement[i] == firstElementToRemove) { + $rootElement[i++] = newNode; + for (var j = i, j2 = j + removeCount - 1, + jj = $rootElement.length; + j < jj; j++, j2++) { + if (j2 < jj) { + $rootElement[j] = $rootElement[j2]; + } else { + delete $rootElement[j]; + } + } + $rootElement.length -= removeCount - 1; + + // If the replaced element is also the jQuery .context then replace it + // .context is a deprecated jQuery api, so we should set it only when jQuery set it + // http://api.jquery.com/context/ + if ($rootElement.context === firstElementToRemove) { + $rootElement.context = newNode; + } + break; + } + } + } + + if (parent) { + parent.replaceChild(newNode, firstElementToRemove); + } + + // TODO(perf): what's this document fragment for? is it needed? can we at least reuse it? + var fragment = document.createDocumentFragment(); + fragment.appendChild(firstElementToRemove); + + // Copy over user data (that includes Angular's $scope etc.). Don't copy private + // data here because there's no public interface in jQuery to do that and copying over + // event listeners (which is the main use of private data) wouldn't work anyway. + jqLite(newNode).data(jqLite(firstElementToRemove).data()); + + // Remove data of the replaced element. We cannot just call .remove() + // on the element it since that would deallocate scope that is needed + // for the new node. Instead, remove the data "manually". + if (!jQuery) { + delete jqLite.cache[firstElementToRemove[jqLite.expando]]; + } else { + // jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after + // the replaced element. The cleanData version monkey-patched by Angular would cause + // the scope to be trashed and we do need the very same scope to work with the new + // element. However, we cannot just cache the non-patched version and use it here as + // that would break if another library patches the method after Angular does (one + // example is jQuery UI). Instead, set a flag indicating scope destroying should be + // skipped this one time. + skipDestroyOnNextJQueryCleanData = true; + jQuery.cleanData([firstElementToRemove]); + } + + for (var k = 1, kk = elementsToRemove.length; k < kk; k++) { + var element = elementsToRemove[k]; + jqLite(element).remove(); // must do this way to clean up expando + fragment.appendChild(element); + delete elementsToRemove[k]; + } + + elementsToRemove[0] = newNode; + elementsToRemove.length = 1; + } + + + function cloneAndAnnotateFn(fn, annotation) { + return extend(function() { return fn.apply(null, arguments); }, fn, annotation); + } + + + function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) { + try { + linkFn(scope, $element, attrs, controllers, transcludeFn); + } catch (e) { + $exceptionHandler(e, startingTag($element)); + } + } + }]; +} + +var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i; +/** + * Converts all accepted directives format into proper directive name. + * @param name Name to normalize + */ +function directiveNormalize(name) { + return camelCase(name.replace(PREFIX_REGEXP, '')); +} + +/** + * @ngdoc type + * @name $compile.directive.Attributes + * + * @description + * A shared object between directive compile / linking functions which contains normalized DOM + * element attributes. The values reflect current binding state `{{ }}`. The normalization is + * needed since all of these are treated as equivalent in Angular: + * + * ``` + * + * ``` + */ + +/** + * @ngdoc property + * @name $compile.directive.Attributes#$attr + * + * @description + * A map of DOM element attribute names to the normalized name. This is + * needed to do reverse lookup from normalized name back to actual name. + */ + + +/** + * @ngdoc method + * @name $compile.directive.Attributes#$set + * @kind function + * + * @description + * Set DOM element attribute value. + * + * + * @param {string} name Normalized element attribute name of the property to modify. The name is + * reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr} + * property to the original name. + * @param {string} value Value to set the attribute to. The value can be an interpolated string. + */ + + + +/** + * Closure compiler type information + */ + +function nodesetLinkingFn( + /* angular.Scope */ scope, + /* NodeList */ nodeList, + /* Element */ rootElement, + /* function(Function) */ boundTranscludeFn +) {} + +function directiveLinkingFn( + /* nodesetLinkingFn */ nodesetLinkingFn, + /* angular.Scope */ scope, + /* Node */ node, + /* Element */ rootElement, + /* function(Function) */ boundTranscludeFn +) {} + +function tokenDifference(str1, str2) { + var values = '', + tokens1 = str1.split(/\s+/), + tokens2 = str2.split(/\s+/); + + outer: + for (var i = 0; i < tokens1.length; i++) { + var token = tokens1[i]; + for (var j = 0; j < tokens2.length; j++) { + if (token == tokens2[j]) continue outer; + } + values += (values.length > 0 ? ' ' : '') + token; + } + return values; +} + +function removeComments(jqNodes) { + jqNodes = jqLite(jqNodes); + var i = jqNodes.length; + + if (i <= 1) { + return jqNodes; + } + + while (i--) { + var node = jqNodes[i]; + if (node.nodeType === NODE_TYPE_COMMENT) { + splice.call(jqNodes, i, 1); + } + } + return jqNodes; +} + +var $controllerMinErr = minErr('$controller'); + +/** + * @ngdoc provider + * @name $controllerProvider + * @description + * The {@link ng.$controller $controller service} is used by Angular to create new + * controllers. + * + * This provider allows controller registration via the + * {@link ng.$controllerProvider#register register} method. + */ +function $ControllerProvider() { + var controllers = {}, + globals = false, + CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/; + + + /** + * @ngdoc method + * @name $controllerProvider#register + * @param {string|Object} name Controller name, or an object map of controllers where the keys are + * the names and the values are the constructors. + * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI + * annotations in the array notation). + */ + this.register = function(name, constructor) { + assertNotHasOwnProperty(name, 'controller'); + if (isObject(name)) { + extend(controllers, name); + } else { + controllers[name] = constructor; + } + }; + + /** + * @ngdoc method + * @name $controllerProvider#allowGlobals + * @description If called, allows `$controller` to find controller constructors on `window` + */ + this.allowGlobals = function() { + globals = true; + }; + + + this.$get = ['$injector', '$window', function($injector, $window) { + + /** + * @ngdoc service + * @name $controller + * @requires $injector + * + * @param {Function|string} constructor If called with a function then it's considered to be the + * controller constructor function. Otherwise it's considered to be a string which is used + * to retrieve the controller constructor using the following steps: + * + * * check if a controller with given name is registered via `$controllerProvider` + * * check if evaluating the string on the current scope returns a constructor + * * if $controllerProvider#allowGlobals, check `window[constructor]` on the global + * `window` object (not recommended) + * + * The string can use the `controller as property` syntax, where the controller instance is published + * as the specified property on the `scope`; the `scope` must be injected into `locals` param for this + * to work correctly. + * + * @param {Object} locals Injection locals for Controller. + * @return {Object} Instance of given controller. + * + * @description + * `$controller` service is responsible for instantiating controllers. + * + * It's just a simple call to {@link auto.$injector $injector}, but extracted into + * a service, so that one can override this service with [BC version](https://gist.github.com/1649788). + */ + return function(expression, locals, later, ident) { + // PRIVATE API: + // param `later` --- indicates that the controller's constructor is invoked at a later time. + // If true, $controller will allocate the object with the correct + // prototype chain, but will not invoke the controller until a returned + // callback is invoked. + // param `ident` --- An optional label which overrides the label parsed from the controller + // expression, if any. + var instance, match, constructor, identifier; + later = later === true; + if (ident && isString(ident)) { + identifier = ident; + } + + if (isString(expression)) { + match = expression.match(CNTRL_REG); + if (!match) { + throw $controllerMinErr('ctrlfmt', + "Badly formed controller string '{0}'. " + + "Must match `__name__ as __id__` or `__name__`.", expression); + } + constructor = match[1], + identifier = identifier || match[3]; + expression = controllers.hasOwnProperty(constructor) + ? controllers[constructor] + : getter(locals.$scope, constructor, true) || + (globals ? getter($window, constructor, true) : undefined); + + assertArgFn(expression, constructor, true); + } + + if (later) { + // Instantiate controller later: + // This machinery is used to create an instance of the object before calling the + // controller's constructor itself. + // + // This allows properties to be added to the controller before the constructor is + // invoked. Primarily, this is used for isolate scope bindings in $compile. + // + // This feature is not intended for use by applications, and is thus not documented + // publicly. + // Object creation: http://jsperf.com/create-constructor/2 + var controllerPrototype = (isArray(expression) ? + expression[expression.length - 1] : expression).prototype; + instance = Object.create(controllerPrototype || null); + + if (identifier) { + addIdentifier(locals, identifier, instance, constructor || expression.name); + } + + return extend(function() { + $injector.invoke(expression, instance, locals, constructor); + return instance; + }, { + instance: instance, + identifier: identifier + }); + } + + instance = $injector.instantiate(expression, locals, constructor); + + if (identifier) { + addIdentifier(locals, identifier, instance, constructor || expression.name); + } + + return instance; + }; + + function addIdentifier(locals, identifier, instance, name) { + if (!(locals && isObject(locals.$scope))) { + throw minErr('$controller')('noscp', + "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.", + name, identifier); + } + + locals.$scope[identifier] = instance; + } + }]; +} + +/** + * @ngdoc service + * @name $document + * @requires $window + * + * @description + * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object. + * + * @example + + +
    +

    $document title:

    +

    window.document title:

    +
    +
    + + angular.module('documentExample', []) + .controller('ExampleController', ['$scope', '$document', function($scope, $document) { + $scope.title = $document[0].title; + $scope.windowTitle = angular.element(window.document)[0].title; + }]); + +
    + */ +function $DocumentProvider() { + this.$get = ['$window', function(window) { + return jqLite(window.document); + }]; +} + +/** + * @ngdoc service + * @name $exceptionHandler + * @requires ng.$log + * + * @description + * Any uncaught exception in angular expressions is delegated to this service. + * The default implementation simply delegates to `$log.error` which logs it into + * the browser console. + * + * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by + * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing. + * + * ## Example: + * + * ```js + * angular.module('exceptionOverride', []).factory('$exceptionHandler', function() { + * return function(exception, cause) { + * exception.message += ' (caused by "' + cause + '")'; + * throw exception; + * }; + * }); + * ``` + * + * This example will override the normal action of `$exceptionHandler`, to make angular + * exceptions fail hard when they happen, instead of just logging to the console. + * + *
    + * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind` + * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler} + * (unless executed during a digest). + * + * If you wish, you can manually delegate exceptions, e.g. + * `try { ... } catch(e) { $exceptionHandler(e); }` + * + * @param {Error} exception Exception associated with the error. + * @param {string=} cause optional information about the context in which + * the error was thrown. + * + */ +function $ExceptionHandlerProvider() { + this.$get = ['$log', function($log) { + return function(exception, cause) { + $log.error.apply($log, arguments); + }; + }]; +} + +var APPLICATION_JSON = 'application/json'; +var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'}; +var JSON_START = /^\[|^\{(?!\{)/; +var JSON_ENDS = { + '[': /]$/, + '{': /}$/ +}; +var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/; + +function defaultHttpResponseTransform(data, headers) { + if (isString(data)) { + // Strip json vulnerability protection prefix and trim whitespace + var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim(); + + if (tempData) { + var contentType = headers('Content-Type'); + if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) { + data = fromJson(tempData); + } + } + } + + return data; +} + +function isJsonLike(str) { + var jsonStart = str.match(JSON_START); + return jsonStart && JSON_ENDS[jsonStart[0]].test(str); +} + +/** + * Parse headers into key value object + * + * @param {string} headers Raw headers as a string + * @returns {Object} Parsed headers as key value object + */ +function parseHeaders(headers) { + var parsed = createMap(), key, val, i; + + if (!headers) return parsed; + + forEach(headers.split('\n'), function(line) { + i = line.indexOf(':'); + key = lowercase(trim(line.substr(0, i))); + val = trim(line.substr(i + 1)); + + if (key) { + parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val; + } + }); + + return parsed; +} + + +/** + * Returns a function that provides access to parsed headers. + * + * Headers are lazy parsed when first requested. + * @see parseHeaders + * + * @param {(string|Object)} headers Headers to provide access to. + * @returns {function(string=)} Returns a getter function which if called with: + * + * - if called with single an argument returns a single header value or null + * - if called with no arguments returns an object containing all headers. + */ +function headersGetter(headers) { + var headersObj = isObject(headers) ? headers : undefined; + + return function(name) { + if (!headersObj) headersObj = parseHeaders(headers); + + if (name) { + var value = headersObj[lowercase(name)]; + if (value === void 0) { + value = null; + } + return value; + } + + return headersObj; + }; +} + + +/** + * Chain all given functions + * + * This function is used for both request and response transforming + * + * @param {*} data Data to transform. + * @param {function(string=)} headers HTTP headers getter fn. + * @param {number} status HTTP status code of the response. + * @param {(Function|Array.)} fns Function or an array of functions. + * @returns {*} Transformed data. + */ +function transformData(data, headers, status, fns) { + if (isFunction(fns)) + return fns(data, headers, status); + + forEach(fns, function(fn) { + data = fn(data, headers, status); + }); + + return data; +} + + +function isSuccess(status) { + return 200 <= status && status < 300; +} + + +/** + * @ngdoc provider + * @name $httpProvider + * @description + * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service. + * */ +function $HttpProvider() { + /** + * @ngdoc property + * @name $httpProvider#defaults + * @description + * + * Object containing default values for all {@link ng.$http $http} requests. + * + * - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`} + * that will provide the cache for all requests who set their `cache` property to `true`. + * If you set the `default.cache = false` then only requests that specify their own custom + * cache object will be cached. See {@link $http#caching $http Caching} for more information. + * + * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token. + * Defaults value is `'XSRF-TOKEN'`. + * + * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the + * XSRF token. Defaults value is `'X-XSRF-TOKEN'`. + * + * - **`defaults.headers`** - {Object} - Default headers for all $http requests. + * Refer to {@link ng.$http#setting-http-headers $http} for documentation on + * setting default headers. + * - **`defaults.headers.common`** + * - **`defaults.headers.post`** + * - **`defaults.headers.put`** + * - **`defaults.headers.patch`** + * + **/ + var defaults = this.defaults = { + // transform incoming response data + transformResponse: [defaultHttpResponseTransform], + + // transform outgoing request data + transformRequest: [function(d) { + return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d; + }], + + // default headers + headers: { + common: { + 'Accept': 'application/json, text/plain, */*' + }, + post: shallowCopy(CONTENT_TYPE_APPLICATION_JSON), + put: shallowCopy(CONTENT_TYPE_APPLICATION_JSON), + patch: shallowCopy(CONTENT_TYPE_APPLICATION_JSON) + }, + + xsrfCookieName: 'XSRF-TOKEN', + xsrfHeaderName: 'X-XSRF-TOKEN' + }; + + var useApplyAsync = false; + /** + * @ngdoc method + * @name $httpProvider#useApplyAsync + * @description + * + * Configure $http service to combine processing of multiple http responses received at around + * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in + * significant performance improvement for bigger applications that make many HTTP requests + * concurrently (common during application bootstrap). + * + * Defaults to false. If no value is specifed, returns the current configured value. + * + * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred + * "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window + * to load and share the same digest cycle. + * + * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining. + * otherwise, returns the current configured value. + **/ + this.useApplyAsync = function(value) { + if (isDefined(value)) { + useApplyAsync = !!value; + return this; + } + return useApplyAsync; + }; + + /** + * @ngdoc property + * @name $httpProvider#interceptors + * @description + * + * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http} + * pre-processing of request or postprocessing of responses. + * + * These service factories are ordered by request, i.e. they are applied in the same order as the + * array, on request, but reverse order, on response. + * + * {@link ng.$http#interceptors Interceptors detailed info} + **/ + var interceptorFactories = this.interceptors = []; + + this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector', + function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) { + + var defaultCache = $cacheFactory('$http'); + + /** + * Interceptors stored in reverse order. Inner interceptors before outer interceptors. + * The reversal is needed so that we can build up the interception chain around the + * server request. + */ + var reversedInterceptors = []; + + forEach(interceptorFactories, function(interceptorFactory) { + reversedInterceptors.unshift(isString(interceptorFactory) + ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory)); + }); + + /** + * @ngdoc service + * @kind function + * @name $http + * @requires ng.$httpBackend + * @requires $cacheFactory + * @requires $rootScope + * @requires $q + * @requires $injector + * + * @description + * The `$http` service is a core Angular service that facilitates communication with the remote + * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest) + * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP). + * + * For unit testing applications that use `$http` service, see + * {@link ngMock.$httpBackend $httpBackend mock}. + * + * For a higher level of abstraction, please check out the {@link ngResource.$resource + * $resource} service. + * + * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by + * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage + * it is important to familiarize yourself with these APIs and the guarantees they provide. + * + * + * ## General usage + * The `$http` service is a function which takes a single argument — a configuration object — + * that is used to generate an HTTP request and returns a {@link ng.$q promise} + * with two $http specific methods: `success` and `error`. + * + * ```js + * // Simple GET request example : + * $http.get('/someUrl'). + * success(function(data, status, headers, config) { + * // this callback will be called asynchronously + * // when the response is available + * }). + * error(function(data, status, headers, config) { + * // called asynchronously if an error occurs + * // or server returns response with an error status. + * }); + * ``` + * + * ```js + * // Simple POST request example (passing data) : + * $http.post('/someUrl', {msg:'hello word!'}). + * success(function(data, status, headers, config) { + * // this callback will be called asynchronously + * // when the response is available + * }). + * error(function(data, status, headers, config) { + * // called asynchronously if an error occurs + * // or server returns response with an error status. + * }); + * ``` + * + * + * Since the returned value of calling the $http function is a `promise`, you can also use + * the `then` method to register callbacks, and these callbacks will receive a single argument – + * an object representing the response. See the API signature and type info below for more + * details. + * + * A response status code between 200 and 299 is considered a success status and + * will result in the success callback being called. Note that if the response is a redirect, + * XMLHttpRequest will transparently follow it, meaning that the error callback will not be + * called for such responses. + * + * ## Writing Unit Tests that use $http + * When unit testing (using {@link ngMock ngMock}), it is necessary to call + * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending + * request using trained responses. + * + * ``` + * $httpBackend.expectGET(...); + * $http.get(...); + * $httpBackend.flush(); + * ``` + * + * ## Shortcut methods + * + * Shortcut methods are also available. All shortcut methods require passing in the URL, and + * request data must be passed in for POST/PUT requests. + * + * ```js + * $http.get('/someUrl').success(successCallback); + * $http.post('/someUrl', data).success(successCallback); + * ``` + * + * Complete list of shortcut methods: + * + * - {@link ng.$http#get $http.get} + * - {@link ng.$http#head $http.head} + * - {@link ng.$http#post $http.post} + * - {@link ng.$http#put $http.put} + * - {@link ng.$http#delete $http.delete} + * - {@link ng.$http#jsonp $http.jsonp} + * - {@link ng.$http#patch $http.patch} + * + * + * ## Setting HTTP Headers + * + * The $http service will automatically add certain HTTP headers to all requests. These defaults + * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration + * object, which currently contains this default configuration: + * + * - `$httpProvider.defaults.headers.common` (headers that are common for all requests): + * - `Accept: application/json, text/plain, * / *` + * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests) + * - `Content-Type: application/json` + * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests) + * - `Content-Type: application/json` + * + * To add or overwrite these defaults, simply add or remove a property from these configuration + * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object + * with the lowercased HTTP method name as the key, e.g. + * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }. + * + * The defaults can also be set at runtime via the `$http.defaults` object in the same + * fashion. For example: + * + * ``` + * module.run(function($http) { + * $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w' + * }); + * ``` + * + * In addition, you can supply a `headers` property in the config object passed when + * calling `$http(config)`, which overrides the defaults without changing them globally. + * + * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis, + * Use the `headers` property, setting the desired header to `undefined`. For example: + * + * ```js + * var req = { + * method: 'POST', + * url: 'http://example.com', + * headers: { + * 'Content-Type': undefined + * }, + * data: { test: 'test' }, + * } + * + * $http(req).success(function(){...}).error(function(){...}); + * ``` + * + * ## Transforming Requests and Responses + * + * Both requests and responses can be transformed using transformation functions: `transformRequest` + * and `transformResponse`. These properties can be a single function that returns + * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions, + * which allows you to `push` or `unshift` a new transformation function into the transformation chain. + * + * ### Default Transformations + * + * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and + * `defaults.transformResponse` properties. If a request does not provide its own transformations + * then these will be applied. + * + * You can augment or replace the default transformations by modifying these properties by adding to or + * replacing the array. + * + * Angular provides the following default transformations: + * + * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`): + * + * - If the `data` property of the request configuration object contains an object, serialize it + * into JSON format. + * + * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`): + * + * - If XSRF prefix is detected, strip it (see Security Considerations section below). + * - If JSON response is detected, deserialize it using a JSON parser. + * + * + * ### Overriding the Default Transformations Per Request + * + * If you wish override the request/response transformations only for a single request then provide + * `transformRequest` and/or `transformResponse` properties on the configuration object passed + * into `$http`. + * + * Note that if you provide these properties on the config object the default transformations will be + * overwritten. If you wish to augment the default transformations then you must include them in your + * local transformation array. + * + * The following code demonstrates adding a new response transformation to be run after the default response + * transformations have been run. + * + * ```js + * function appendTransform(defaults, transform) { + * + * // We can't guarantee that the default transformation is an array + * defaults = angular.isArray(defaults) ? defaults : [defaults]; + * + * // Append the new transformation to the defaults + * return defaults.concat(transform); + * } + * + * $http({ + * url: '...', + * method: 'GET', + * transformResponse: appendTransform($http.defaults.transformResponse, function(value) { + * return doTransform(value); + * }) + * }); + * ``` + * + * + * ## Caching + * + * To enable caching, set the request configuration `cache` property to `true` (to use default + * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}). + * When the cache is enabled, `$http` stores the response from the server in the specified + * cache. The next time the same request is made, the response is served from the cache without + * sending a request to the server. + * + * Note that even if the response is served from cache, delivery of the data is asynchronous in + * the same way that real requests are. + * + * If there are multiple GET requests for the same URL that should be cached using the same + * cache, but the cache is not populated yet, only one request to the server will be made and + * the remaining requests will be fulfilled using the response from the first request. + * + * You can change the default cache to a new object (built with + * {@link ng.$cacheFactory `$cacheFactory`}) by updating the + * {@link ng.$http#defaults `$http.defaults.cache`} property. All requests who set + * their `cache` property to `true` will now use this cache object. + * + * If you set the default cache to `false` then only requests that specify their own custom + * cache object will be cached. + * + * ## Interceptors + * + * Before you start creating interceptors, be sure to understand the + * {@link ng.$q $q and deferred/promise APIs}. + * + * For purposes of global error handling, authentication, or any kind of synchronous or + * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be + * able to intercept requests before they are handed to the server and + * responses before they are handed over to the application code that + * initiated these requests. The interceptors leverage the {@link ng.$q + * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing. + * + * The interceptors are service factories that are registered with the `$httpProvider` by + * adding them to the `$httpProvider.interceptors` array. The factory is called and + * injected with dependencies (if specified) and returns the interceptor. + * + * There are two kinds of interceptors (and two kinds of rejection interceptors): + * + * * `request`: interceptors get called with a http `config` object. The function is free to + * modify the `config` object or create a new one. The function needs to return the `config` + * object directly, or a promise containing the `config` or a new `config` object. + * * `requestError`: interceptor gets called when a previous interceptor threw an error or + * resolved with a rejection. + * * `response`: interceptors get called with http `response` object. The function is free to + * modify the `response` object or create a new one. The function needs to return the `response` + * object directly, or as a promise containing the `response` or a new `response` object. + * * `responseError`: interceptor gets called when a previous interceptor threw an error or + * resolved with a rejection. + * + * + * ```js + * // register the interceptor as a service + * $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) { + * return { + * // optional method + * 'request': function(config) { + * // do something on success + * return config; + * }, + * + * // optional method + * 'requestError': function(rejection) { + * // do something on error + * if (canRecover(rejection)) { + * return responseOrNewPromise + * } + * return $q.reject(rejection); + * }, + * + * + * + * // optional method + * 'response': function(response) { + * // do something on success + * return response; + * }, + * + * // optional method + * 'responseError': function(rejection) { + * // do something on error + * if (canRecover(rejection)) { + * return responseOrNewPromise + * } + * return $q.reject(rejection); + * } + * }; + * }); + * + * $httpProvider.interceptors.push('myHttpInterceptor'); + * + * + * // alternatively, register the interceptor via an anonymous factory + * $httpProvider.interceptors.push(function($q, dependency1, dependency2) { + * return { + * 'request': function(config) { + * // same as above + * }, + * + * 'response': function(response) { + * // same as above + * } + * }; + * }); + * ``` + * + * ## Security Considerations + * + * When designing web applications, consider security threats from: + * + * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx) + * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) + * + * Both server and the client must cooperate in order to eliminate these threats. Angular comes + * pre-configured with strategies that address these issues, but for this to work backend server + * cooperation is required. + * + * ### JSON Vulnerability Protection + * + * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx) + * allows third party website to turn your JSON resource URL into + * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To + * counter this your server can prefix all JSON requests with following string `")]}',\n"`. + * Angular will automatically strip the prefix before processing it as JSON. + * + * For example if your server needs to return: + * ```js + * ['one','two'] + * ``` + * + * which is vulnerable to attack, your server can return: + * ```js + * )]}', + * ['one','two'] + * ``` + * + * Angular will strip the prefix, before processing the JSON. + * + * + * ### Cross Site Request Forgery (XSRF) Protection + * + * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which + * an unauthorized site can gain your user's private data. Angular provides a mechanism + * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie + * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only + * JavaScript that runs on your domain could read the cookie, your server can be assured that + * the XHR came from JavaScript running on your domain. The header will not be set for + * cross-domain requests. + * + * To take advantage of this, your server needs to set a token in a JavaScript readable session + * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the + * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure + * that only JavaScript running on your domain could have sent the request. The token must be + * unique for each user and must be verifiable by the server (to prevent the JavaScript from + * making up its own tokens). We recommend that the token is a digest of your site's + * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography)) + * for added security. + * + * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName + * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time, + * or the per-request config object. + * + * + * @param {object} config Object describing the request to be made and how it should be + * processed. The object has following properties: + * + * - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc) + * - **url** – `{string}` – Absolute or relative URL of the resource that is being requested. + * - **params** – `{Object.}` – Map of strings or objects which will be turned + * to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be + * JSONified. + * - **data** – `{string|Object}` – Data to be sent as the request message data. + * - **headers** – `{Object}` – Map of strings or functions which return strings representing + * HTTP headers to send to the server. If the return value of a function is null, the + * header will not be sent. + * - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token. + * - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token. + * - **transformRequest** – + * `{function(data, headersGetter)|Array.}` – + * transform function or an array of such functions. The transform function takes the http + * request body and headers and returns its transformed (typically serialized) version. + * See {@link ng.$http#overriding-the-default-transformations-per-request + * Overriding the Default Transformations} + * - **transformResponse** – + * `{function(data, headersGetter, status)|Array.}` – + * transform function or an array of such functions. The transform function takes the http + * response body, headers and status and returns its transformed (typically deserialized) version. + * See {@link ng.$http#overriding-the-default-transformations-per-request + * Overriding the Default Transformations} + * - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the + * GET request, otherwise if a cache instance built with + * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for + * caching. + * - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} + * that should abort the request when resolved. + * - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the + * XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials) + * for more information. + * - **responseType** - `{string}` - see + * [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType). + * + * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the + * standard `then` method and two http specific methods: `success` and `error`. The `then` + * method takes two arguments a success and an error callback which will be called with a + * response object. The `success` and `error` methods take a single argument - a function that + * will be called when the request succeeds or fails respectively. The arguments passed into + * these functions are destructured representation of the response object passed into the + * `then` method. The response object has these properties: + * + * - **data** – `{string|Object}` – The response body transformed with the transform + * functions. + * - **status** – `{number}` – HTTP status code of the response. + * - **headers** – `{function([headerName])}` – Header getter function. + * - **config** – `{Object}` – The configuration object that was used to generate the request. + * - **statusText** – `{string}` – HTTP status text of the response. + * + * @property {Array.} pendingRequests Array of config objects for currently pending + * requests. This is primarily meant to be used for debugging purposes. + * + * + * @example + + +
    + + +
    + + + +
    http status code: {{status}}
    +
    http response data: {{data}}
    +
    +
    + + angular.module('httpExample', []) + .controller('FetchController', ['$scope', '$http', '$templateCache', + function($scope, $http, $templateCache) { + $scope.method = 'GET'; + $scope.url = 'http-hello.html'; + + $scope.fetch = function() { + $scope.code = null; + $scope.response = null; + + $http({method: $scope.method, url: $scope.url, cache: $templateCache}). + success(function(data, status) { + $scope.status = status; + $scope.data = data; + }). + error(function(data, status) { + $scope.data = data || "Request failed"; + $scope.status = status; + }); + }; + + $scope.updateModel = function(method, url) { + $scope.method = method; + $scope.url = url; + }; + }]); + + + Hello, $http! + + + var status = element(by.binding('status')); + var data = element(by.binding('data')); + var fetchBtn = element(by.id('fetchbtn')); + var sampleGetBtn = element(by.id('samplegetbtn')); + var sampleJsonpBtn = element(by.id('samplejsonpbtn')); + var invalidJsonpBtn = element(by.id('invalidjsonpbtn')); + + it('should make an xhr GET request', function() { + sampleGetBtn.click(); + fetchBtn.click(); + expect(status.getText()).toMatch('200'); + expect(data.getText()).toMatch(/Hello, \$http!/); + }); + +// Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185 +// it('should make a JSONP request to angularjs.org', function() { +// sampleJsonpBtn.click(); +// fetchBtn.click(); +// expect(status.getText()).toMatch('200'); +// expect(data.getText()).toMatch(/Super Hero!/); +// }); + + it('should make JSONP request to invalid URL and invoke the error handler', + function() { + invalidJsonpBtn.click(); + fetchBtn.click(); + expect(status.getText()).toMatch('0'); + expect(data.getText()).toMatch('Request failed'); + }); + +
    + */ + function $http(requestConfig) { + + if (!angular.isObject(requestConfig)) { + throw minErr('$http')('badreq', 'Http request configuration must be an object. Received: {0}', requestConfig); + } + + var config = extend({ + method: 'get', + transformRequest: defaults.transformRequest, + transformResponse: defaults.transformResponse + }, requestConfig); + + config.headers = mergeHeaders(requestConfig); + config.method = uppercase(config.method); + + var serverRequest = function(config) { + var headers = config.headers; + var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest); + + // strip content-type if data is undefined + if (isUndefined(reqData)) { + forEach(headers, function(value, header) { + if (lowercase(header) === 'content-type') { + delete headers[header]; + } + }); + } + + if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) { + config.withCredentials = defaults.withCredentials; + } + + // send request + return sendReq(config, reqData).then(transformResponse, transformResponse); + }; + + var chain = [serverRequest, undefined]; + var promise = $q.when(config); + + // apply interceptors + forEach(reversedInterceptors, function(interceptor) { + if (interceptor.request || interceptor.requestError) { + chain.unshift(interceptor.request, interceptor.requestError); + } + if (interceptor.response || interceptor.responseError) { + chain.push(interceptor.response, interceptor.responseError); + } + }); + + while (chain.length) { + var thenFn = chain.shift(); + var rejectFn = chain.shift(); + + promise = promise.then(thenFn, rejectFn); + } + + promise.success = function(fn) { + promise.then(function(response) { + fn(response.data, response.status, response.headers, config); + }); + return promise; + }; + + promise.error = function(fn) { + promise.then(null, function(response) { + fn(response.data, response.status, response.headers, config); + }); + return promise; + }; + + return promise; + + function transformResponse(response) { + // make a copy since the response must be cacheable + var resp = extend({}, response); + if (!response.data) { + resp.data = response.data; + } else { + resp.data = transformData(response.data, response.headers, response.status, config.transformResponse); + } + return (isSuccess(response.status)) + ? resp + : $q.reject(resp); + } + + function executeHeaderFns(headers) { + var headerContent, processedHeaders = {}; + + forEach(headers, function(headerFn, header) { + if (isFunction(headerFn)) { + headerContent = headerFn(); + if (headerContent != null) { + processedHeaders[header] = headerContent; + } + } else { + processedHeaders[header] = headerFn; + } + }); + + return processedHeaders; + } + + function mergeHeaders(config) { + var defHeaders = defaults.headers, + reqHeaders = extend({}, config.headers), + defHeaderName, lowercaseDefHeaderName, reqHeaderName; + + defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]); + + // using for-in instead of forEach to avoid unecessary iteration after header has been found + defaultHeadersIteration: + for (defHeaderName in defHeaders) { + lowercaseDefHeaderName = lowercase(defHeaderName); + + for (reqHeaderName in reqHeaders) { + if (lowercase(reqHeaderName) === lowercaseDefHeaderName) { + continue defaultHeadersIteration; + } + } + + reqHeaders[defHeaderName] = defHeaders[defHeaderName]; + } + + // execute if header value is a function for merged headers + return executeHeaderFns(reqHeaders); + } + } + + $http.pendingRequests = []; + + /** + * @ngdoc method + * @name $http#get + * + * @description + * Shortcut method to perform `GET` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + + /** + * @ngdoc method + * @name $http#delete + * + * @description + * Shortcut method to perform `DELETE` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + + /** + * @ngdoc method + * @name $http#head + * + * @description + * Shortcut method to perform `HEAD` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + + /** + * @ngdoc method + * @name $http#jsonp + * + * @description + * Shortcut method to perform `JSONP` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request. + * The name of the callback should be the string `JSON_CALLBACK`. + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + createShortMethods('get', 'delete', 'head', 'jsonp'); + + /** + * @ngdoc method + * @name $http#post + * + * @description + * Shortcut method to perform `POST` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request + * @param {*} data Request content + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + + /** + * @ngdoc method + * @name $http#put + * + * @description + * Shortcut method to perform `PUT` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request + * @param {*} data Request content + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + + /** + * @ngdoc method + * @name $http#patch + * + * @description + * Shortcut method to perform `PATCH` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request + * @param {*} data Request content + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + createShortMethodsWithData('post', 'put', 'patch'); + + /** + * @ngdoc property + * @name $http#defaults + * + * @description + * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of + * default headers, withCredentials as well as request and response transformations. + * + * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above. + */ + $http.defaults = defaults; + + + return $http; + + + function createShortMethods(names) { + forEach(arguments, function(name) { + $http[name] = function(url, config) { + return $http(extend(config || {}, { + method: name, + url: url + })); + }; + }); + } + + + function createShortMethodsWithData(name) { + forEach(arguments, function(name) { + $http[name] = function(url, data, config) { + return $http(extend(config || {}, { + method: name, + url: url, + data: data + })); + }; + }); + } + + + /** + * Makes the request. + * + * !!! ACCESSES CLOSURE VARS: + * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests + */ + function sendReq(config, reqData) { + var deferred = $q.defer(), + promise = deferred.promise, + cache, + cachedResp, + reqHeaders = config.headers, + url = buildUrl(config.url, config.params); + + $http.pendingRequests.push(config); + promise.then(removePendingReq, removePendingReq); + + + if ((config.cache || defaults.cache) && config.cache !== false && + (config.method === 'GET' || config.method === 'JSONP')) { + cache = isObject(config.cache) ? config.cache + : isObject(defaults.cache) ? defaults.cache + : defaultCache; + } + + if (cache) { + cachedResp = cache.get(url); + if (isDefined(cachedResp)) { + if (isPromiseLike(cachedResp)) { + // cached request has already been sent, but there is no response yet + cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult); + } else { + // serving from cache + if (isArray(cachedResp)) { + resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]); + } else { + resolvePromise(cachedResp, 200, {}, 'OK'); + } + } + } else { + // put the promise for the non-transformed response into cache as a placeholder + cache.put(url, promise); + } + } + + + // if we won't have the response in cache, set the xsrf headers and + // send the request to the backend + if (isUndefined(cachedResp)) { + var xsrfValue = urlIsSameOrigin(config.url) + ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName] + : undefined; + if (xsrfValue) { + reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue; + } + + $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout, + config.withCredentials, config.responseType); + } + + return promise; + + + /** + * Callback registered to $httpBackend(): + * - caches the response if desired + * - resolves the raw $http promise + * - calls $apply + */ + function done(status, response, headersString, statusText) { + if (cache) { + if (isSuccess(status)) { + cache.put(url, [status, response, parseHeaders(headersString), statusText]); + } else { + // remove promise from the cache + cache.remove(url); + } + } + + function resolveHttpPromise() { + resolvePromise(response, status, headersString, statusText); + } + + if (useApplyAsync) { + $rootScope.$applyAsync(resolveHttpPromise); + } else { + resolveHttpPromise(); + if (!$rootScope.$$phase) $rootScope.$apply(); + } + } + + + /** + * Resolves the raw $http promise. + */ + function resolvePromise(response, status, headers, statusText) { + // normalize internal statuses to 0 + status = Math.max(status, 0); + + (isSuccess(status) ? deferred.resolve : deferred.reject)({ + data: response, + status: status, + headers: headersGetter(headers), + config: config, + statusText: statusText + }); + } + + function resolvePromiseWithResult(result) { + resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText); + } + + function removePendingReq() { + var idx = $http.pendingRequests.indexOf(config); + if (idx !== -1) $http.pendingRequests.splice(idx, 1); + } + } + + + function buildUrl(url, params) { + if (!params) return url; + var parts = []; + forEachSorted(params, function(value, key) { + if (value === null || isUndefined(value)) return; + if (!isArray(value)) value = [value]; + + forEach(value, function(v) { + if (isObject(v)) { + if (isDate(v)) { + v = v.toISOString(); + } else { + v = toJson(v); + } + } + parts.push(encodeUriQuery(key) + '=' + + encodeUriQuery(v)); + }); + }); + if (parts.length > 0) { + url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&'); + } + return url; + } + }]; +} + +function createXhr() { + return new window.XMLHttpRequest(); +} + +/** + * @ngdoc service + * @name $httpBackend + * @requires $window + * @requires $document + * + * @description + * HTTP backend used by the {@link ng.$http service} that delegates to + * XMLHttpRequest object or JSONP and deals with browser incompatibilities. + * + * You should never need to use this service directly, instead use the higher-level abstractions: + * {@link ng.$http $http} or {@link ngResource.$resource $resource}. + * + * During testing this implementation is swapped with {@link ngMock.$httpBackend mock + * $httpBackend} which can be trained with responses. + */ +function $HttpBackendProvider() { + this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) { + return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]); + }]; +} + +function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) { + // TODO(vojta): fix the signature + return function(method, url, post, callback, headers, timeout, withCredentials, responseType) { + $browser.$$incOutstandingRequestCount(); + url = url || $browser.url(); + + if (lowercase(method) == 'jsonp') { + var callbackId = '_' + (callbacks.counter++).toString(36); + callbacks[callbackId] = function(data) { + callbacks[callbackId].data = data; + callbacks[callbackId].called = true; + }; + + var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId), + callbackId, function(status, text) { + completeRequest(callback, status, callbacks[callbackId].data, "", text); + callbacks[callbackId] = noop; + }); + } else { + + var xhr = createXhr(); + + xhr.open(method, url, true); + forEach(headers, function(value, key) { + if (isDefined(value)) { + xhr.setRequestHeader(key, value); + } + }); + + xhr.onload = function requestLoaded() { + var statusText = xhr.statusText || ''; + + // responseText is the old-school way of retrieving response (supported by IE8 & 9) + // response/responseType properties were introduced in XHR Level2 spec (supported by IE10) + var response = ('response' in xhr) ? xhr.response : xhr.responseText; + + // normalize IE9 bug (http://bugs.jquery.com/ticket/1450) + var status = xhr.status === 1223 ? 204 : xhr.status; + + // fix status code when it is 0 (0 status is undocumented). + // Occurs when accessing file resources or on Android 4.1 stock browser + // while retrieving files from application cache. + if (status === 0) { + status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0; + } + + completeRequest(callback, + status, + response, + xhr.getAllResponseHeaders(), + statusText); + }; + + var requestError = function() { + // The response is always empty + // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error + completeRequest(callback, -1, null, null, ''); + }; + + xhr.onerror = requestError; + xhr.onabort = requestError; + + if (withCredentials) { + xhr.withCredentials = true; + } + + if (responseType) { + try { + xhr.responseType = responseType; + } catch (e) { + // WebKit added support for the json responseType value on 09/03/2013 + // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are + // known to throw when setting the value "json" as the response type. Other older + // browsers implementing the responseType + // + // The json response type can be ignored if not supported, because JSON payloads are + // parsed on the client-side regardless. + if (responseType !== 'json') { + throw e; + } + } + } + + xhr.send(post || null); + } + + if (timeout > 0) { + var timeoutId = $browserDefer(timeoutRequest, timeout); + } else if (isPromiseLike(timeout)) { + timeout.then(timeoutRequest); + } + + + function timeoutRequest() { + jsonpDone && jsonpDone(); + xhr && xhr.abort(); + } + + function completeRequest(callback, status, response, headersString, statusText) { + // cancel timeout and subsequent timeout promise resolution + if (timeoutId !== undefined) { + $browserDefer.cancel(timeoutId); + } + jsonpDone = xhr = null; + + callback(status, response, headersString, statusText); + $browser.$$completeOutstandingRequest(noop); + } + }; + + function jsonpReq(url, callbackId, done) { + // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.: + // - fetches local scripts via XHR and evals them + // - adds and immediately removes script elements from the document + var script = rawDocument.createElement('script'), callback = null; + script.type = "text/javascript"; + script.src = url; + script.async = true; + + callback = function(event) { + removeEventListenerFn(script, "load", callback); + removeEventListenerFn(script, "error", callback); + rawDocument.body.removeChild(script); + script = null; + var status = -1; + var text = "unknown"; + + if (event) { + if (event.type === "load" && !callbacks[callbackId].called) { + event = { type: "error" }; + } + text = event.type; + status = event.type === "error" ? 404 : 200; + } + + if (done) { + done(status, text); + } + }; + + addEventListenerFn(script, "load", callback); + addEventListenerFn(script, "error", callback); + rawDocument.body.appendChild(script); + return callback; + } +} + +var $interpolateMinErr = minErr('$interpolate'); + +/** + * @ngdoc provider + * @name $interpolateProvider + * + * @description + * + * Used for configuring the interpolation markup. Defaults to `{{` and `}}`. + * + * @example + + + +
    + //demo.label// +
    +
    + + it('should interpolate binding with custom symbols', function() { + expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.'); + }); + +
    + */ +function $InterpolateProvider() { + var startSymbol = '{{'; + var endSymbol = '}}'; + + /** + * @ngdoc method + * @name $interpolateProvider#startSymbol + * @description + * Symbol to denote start of expression in the interpolated string. Defaults to `{{`. + * + * @param {string=} value new value to set the starting symbol to. + * @returns {string|self} Returns the symbol when used as getter and self if used as setter. + */ + this.startSymbol = function(value) { + if (value) { + startSymbol = value; + return this; + } else { + return startSymbol; + } + }; + + /** + * @ngdoc method + * @name $interpolateProvider#endSymbol + * @description + * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`. + * + * @param {string=} value new value to set the ending symbol to. + * @returns {string|self} Returns the symbol when used as getter and self if used as setter. + */ + this.endSymbol = function(value) { + if (value) { + endSymbol = value; + return this; + } else { + return endSymbol; + } + }; + + + this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) { + var startSymbolLength = startSymbol.length, + endSymbolLength = endSymbol.length, + escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'), + escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g'); + + function escape(ch) { + return '\\\\\\' + ch; + } + + /** + * @ngdoc service + * @name $interpolate + * @kind function + * + * @requires $parse + * @requires $sce + * + * @description + * + * Compiles a string with markup into an interpolation function. This service is used by the + * HTML {@link ng.$compile $compile} service for data binding. See + * {@link ng.$interpolateProvider $interpolateProvider} for configuring the + * interpolation markup. + * + * + * ```js + * var $interpolate = ...; // injected + * var exp = $interpolate('Hello {{name | uppercase}}!'); + * expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!'); + * ``` + * + * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is + * `true`, the interpolation function will return `undefined` unless all embedded expressions + * evaluate to a value other than `undefined`. + * + * ```js + * var $interpolate = ...; // injected + * var context = {greeting: 'Hello', name: undefined }; + * + * // default "forgiving" mode + * var exp = $interpolate('{{greeting}} {{name}}!'); + * expect(exp(context)).toEqual('Hello !'); + * + * // "allOrNothing" mode + * exp = $interpolate('{{greeting}} {{name}}!', false, null, true); + * expect(exp(context)).toBeUndefined(); + * context.name = 'Angular'; + * expect(exp(context)).toEqual('Hello Angular!'); + * ``` + * + * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior. + * + * ####Escaped Interpolation + * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers + * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash). + * It will be rendered as a regular start/end marker, and will not be interpreted as an expression + * or binding. + * + * This enables web-servers to prevent script injection attacks and defacing attacks, to some + * degree, while also enabling code examples to work without relying on the + * {@link ng.directive:ngNonBindable ngNonBindable} directive. + * + * **For security purposes, it is strongly encouraged that web servers escape user-supplied data, + * replacing angle brackets (<, >) with &lt; and &gt; respectively, and replacing all + * interpolation start/end markers with their escaped counterparts.** + * + * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered + * output when the $interpolate service processes the text. So, for HTML elements interpolated + * by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter + * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such, + * this is typically useful only when user-data is used in rendering a template from the server, or + * when otherwise untrusted data is used by a directive. + * + * + * + *
    + *

    {{apptitle}}: \{\{ username = "defaced value"; \}\} + *

    + *

    {{username}} attempts to inject code which will deface the + * application, but fails to accomplish their task, because the server has correctly + * escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash) + * characters.

    + *

    Instead, the result of the attempted script injection is visible, and can be removed + * from the database by an administrator.

    + *
    + *
    + *
    + * + * @param {string} text The text with markup to interpolate. + * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have + * embedded expression in order to return an interpolation function. Strings with no + * embedded expression will return null for the interpolation function. + * @param {string=} trustedContext when provided, the returned function passes the interpolated + * result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult, + * trustedContext)} before returning it. Refer to the {@link ng.$sce $sce} service that + * provides Strict Contextual Escaping for details. + * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined + * unless all embedded expressions evaluate to a value other than `undefined`. + * @returns {function(context)} an interpolation function which is used to compute the + * interpolated string. The function has these parameters: + * + * - `context`: evaluation context for all expressions embedded in the interpolated text + */ + function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) { + allOrNothing = !!allOrNothing; + var startIndex, + endIndex, + index = 0, + expressions = [], + parseFns = [], + textLength = text.length, + exp, + concat = [], + expressionPositions = []; + + while (index < textLength) { + if (((startIndex = text.indexOf(startSymbol, index)) != -1) && + ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) { + if (index !== startIndex) { + concat.push(unescapeText(text.substring(index, startIndex))); + } + exp = text.substring(startIndex + startSymbolLength, endIndex); + expressions.push(exp); + parseFns.push($parse(exp, parseStringifyInterceptor)); + index = endIndex + endSymbolLength; + expressionPositions.push(concat.length); + concat.push(''); + } else { + // we did not find an interpolation, so we have to add the remainder to the separators array + if (index !== textLength) { + concat.push(unescapeText(text.substring(index))); + } + break; + } + } + + // Concatenating expressions makes it hard to reason about whether some combination of + // concatenated values are unsafe to use and could easily lead to XSS. By requiring that a + // single expression be used for iframe[src], object[src], etc., we ensure that the value + // that's used is assigned or constructed by some JS code somewhere that is more testable or + // make it obvious that you bound the value to some user controlled value. This helps reduce + // the load when auditing for XSS issues. + if (trustedContext && concat.length > 1) { + throw $interpolateMinErr('noconcat', + "Error while interpolating: {0}\nStrict Contextual Escaping disallows " + + "interpolations that concatenate multiple expressions when a trusted value is " + + "required. See http://docs.angularjs.org/api/ng.$sce", text); + } + + if (!mustHaveExpression || expressions.length) { + var compute = function(values) { + for (var i = 0, ii = expressions.length; i < ii; i++) { + if (allOrNothing && isUndefined(values[i])) return; + concat[expressionPositions[i]] = values[i]; + } + return concat.join(''); + }; + + var getValue = function(value) { + return trustedContext ? + $sce.getTrusted(trustedContext, value) : + $sce.valueOf(value); + }; + + var stringify = function(value) { + if (value == null) { // null || undefined + return ''; + } + switch (typeof value) { + case 'string': + break; + case 'number': + value = '' + value; + break; + default: + value = toJson(value); + } + + return value; + }; + + return extend(function interpolationFn(context) { + var i = 0; + var ii = expressions.length; + var values = new Array(ii); + + try { + for (; i < ii; i++) { + values[i] = parseFns[i](context); + } + + return compute(values); + } catch (err) { + var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text, + err.toString()); + $exceptionHandler(newErr); + } + + }, { + // all of these properties are undocumented for now + exp: text, //just for compatibility with regular watchers created via $watch + expressions: expressions, + $$watchDelegate: function(scope, listener, objectEquality) { + var lastValue; + return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) { + var currValue = compute(values); + if (isFunction(listener)) { + listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope); + } + lastValue = currValue; + }, objectEquality); + } + }); + } + + function unescapeText(text) { + return text.replace(escapedStartRegexp, startSymbol). + replace(escapedEndRegexp, endSymbol); + } + + function parseStringifyInterceptor(value) { + try { + value = getValue(value); + return allOrNothing && !isDefined(value) ? value : stringify(value); + } catch (err) { + var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text, + err.toString()); + $exceptionHandler(newErr); + } + } + } + + + /** + * @ngdoc method + * @name $interpolate#startSymbol + * @description + * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`. + * + * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change + * the symbol. + * + * @returns {string} start symbol. + */ + $interpolate.startSymbol = function() { + return startSymbol; + }; + + + /** + * @ngdoc method + * @name $interpolate#endSymbol + * @description + * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`. + * + * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change + * the symbol. + * + * @returns {string} end symbol. + */ + $interpolate.endSymbol = function() { + return endSymbol; + }; + + return $interpolate; + }]; +} + +function $IntervalProvider() { + this.$get = ['$rootScope', '$window', '$q', '$$q', + function($rootScope, $window, $q, $$q) { + var intervals = {}; + + + /** + * @ngdoc service + * @name $interval + * + * @description + * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay` + * milliseconds. + * + * The return value of registering an interval function is a promise. This promise will be + * notified upon each tick of the interval, and will be resolved after `count` iterations, or + * run indefinitely if `count` is not defined. The value of the notification will be the + * number of iterations that have run. + * To cancel an interval, call `$interval.cancel(promise)`. + * + * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to + * move forward by `millis` milliseconds and trigger any functions scheduled to run in that + * time. + * + *
    + * **Note**: Intervals created by this service must be explicitly destroyed when you are finished + * with them. In particular they are not automatically destroyed when a controller's scope or a + * directive's element are destroyed. + * You should take this into consideration and make sure to always cancel the interval at the + * appropriate moment. See the example below for more details on how and when to do this. + *
    + * + * @param {function()} fn A function that should be called repeatedly. + * @param {number} delay Number of milliseconds between each function call. + * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat + * indefinitely. + * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise + * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. + * @returns {promise} A promise which will be notified on each iteration. + * + * @example + * + * + * + * + *
    + *
    + * Date format:
    + * Current time is: + *
    + * Blood 1 : {{blood_1}} + * Blood 2 : {{blood_2}} + * + * + * + *
    + *
    + * + *
    + *
    + */ + function interval(fn, delay, count, invokeApply) { + var setInterval = $window.setInterval, + clearInterval = $window.clearInterval, + iteration = 0, + skipApply = (isDefined(invokeApply) && !invokeApply), + deferred = (skipApply ? $$q : $q).defer(), + promise = deferred.promise; + + count = isDefined(count) ? count : 0; + + promise.then(null, null, fn); + + promise.$$intervalId = setInterval(function tick() { + deferred.notify(iteration++); + + if (count > 0 && iteration >= count) { + deferred.resolve(iteration); + clearInterval(promise.$$intervalId); + delete intervals[promise.$$intervalId]; + } + + if (!skipApply) $rootScope.$apply(); + + }, delay); + + intervals[promise.$$intervalId] = deferred; + + return promise; + } + + + /** + * @ngdoc method + * @name $interval#cancel + * + * @description + * Cancels a task associated with the `promise`. + * + * @param {promise} promise returned by the `$interval` function. + * @returns {boolean} Returns `true` if the task was successfully canceled. + */ + interval.cancel = function(promise) { + if (promise && promise.$$intervalId in intervals) { + intervals[promise.$$intervalId].reject('canceled'); + $window.clearInterval(promise.$$intervalId); + delete intervals[promise.$$intervalId]; + return true; + } + return false; + }; + + return interval; + }]; +} + +/** + * @ngdoc service + * @name $locale + * + * @description + * $locale service provides localization rules for various Angular components. As of right now the + * only public api is: + * + * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`) + */ +function $LocaleProvider() { + this.$get = function() { + return { + id: 'en-us', + + NUMBER_FORMATS: { + DECIMAL_SEP: '.', + GROUP_SEP: ',', + PATTERNS: [ + { // Decimal Pattern + minInt: 1, + minFrac: 0, + maxFrac: 3, + posPre: '', + posSuf: '', + negPre: '-', + negSuf: '', + gSize: 3, + lgSize: 3 + },{ //Currency Pattern + minInt: 1, + minFrac: 2, + maxFrac: 2, + posPre: '\u00A4', + posSuf: '', + negPre: '(\u00A4', + negSuf: ')', + gSize: 3, + lgSize: 3 + } + ], + CURRENCY_SYM: '$' + }, + + DATETIME_FORMATS: { + MONTH: + 'January,February,March,April,May,June,July,August,September,October,November,December' + .split(','), + SHORTMONTH: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','), + DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','), + SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','), + AMPMS: ['AM','PM'], + medium: 'MMM d, y h:mm:ss a', + 'short': 'M/d/yy h:mm a', + fullDate: 'EEEE, MMMM d, y', + longDate: 'MMMM d, y', + mediumDate: 'MMM d, y', + shortDate: 'M/d/yy', + mediumTime: 'h:mm:ss a', + shortTime: 'h:mm a' + }, + + pluralCat: function(num) { + if (num === 1) { + return 'one'; + } + return 'other'; + } + }; + }; +} + +var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/, + DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21}; +var $locationMinErr = minErr('$location'); + + +/** + * Encode path using encodeUriSegment, ignoring forward slashes + * + * @param {string} path Path to encode + * @returns {string} + */ +function encodePath(path) { + var segments = path.split('/'), + i = segments.length; + + while (i--) { + segments[i] = encodeUriSegment(segments[i]); + } + + return segments.join('/'); +} + +function parseAbsoluteUrl(absoluteUrl, locationObj) { + var parsedUrl = urlResolve(absoluteUrl); + + locationObj.$$protocol = parsedUrl.protocol; + locationObj.$$host = parsedUrl.hostname; + locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null; +} + + +function parseAppUrl(relativeUrl, locationObj) { + var prefixed = (relativeUrl.charAt(0) !== '/'); + if (prefixed) { + relativeUrl = '/' + relativeUrl; + } + var match = urlResolve(relativeUrl); + locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ? + match.pathname.substring(1) : match.pathname); + locationObj.$$search = parseKeyValue(match.search); + locationObj.$$hash = decodeURIComponent(match.hash); + + // make sure path starts with '/'; + if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') { + locationObj.$$path = '/' + locationObj.$$path; + } +} + + +/** + * + * @param {string} begin + * @param {string} whole + * @returns {string} returns text from whole after begin or undefined if it does not begin with + * expected string. + */ +function beginsWith(begin, whole) { + if (whole.indexOf(begin) === 0) { + return whole.substr(begin.length); + } +} + + +function stripHash(url) { + var index = url.indexOf('#'); + return index == -1 ? url : url.substr(0, index); +} + +function trimEmptyHash(url) { + return url.replace(/(#.+)|#$/, '$1'); +} + + +function stripFile(url) { + return url.substr(0, stripHash(url).lastIndexOf('/') + 1); +} + +/* return the server only (scheme://host:port) */ +function serverBase(url) { + return url.substring(0, url.indexOf('/', url.indexOf('//') + 2)); +} + + +/** + * LocationHtml5Url represents an url + * This object is exposed as $location service when HTML5 mode is enabled and supported + * + * @constructor + * @param {string} appBase application base URL + * @param {string} basePrefix url path prefix + */ +function LocationHtml5Url(appBase, basePrefix) { + this.$$html5 = true; + basePrefix = basePrefix || ''; + var appBaseNoFile = stripFile(appBase); + parseAbsoluteUrl(appBase, this); + + + /** + * Parse given html5 (regular) url string into properties + * @param {string} url HTML5 url + * @private + */ + this.$$parse = function(url) { + var pathUrl = beginsWith(appBaseNoFile, url); + if (!isString(pathUrl)) { + throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url, + appBaseNoFile); + } + + parseAppUrl(pathUrl, this); + + if (!this.$$path) { + this.$$path = '/'; + } + + this.$$compose(); + }; + + /** + * Compose url and update `absUrl` property + * @private + */ + this.$$compose = function() { + var search = toKeyValue(this.$$search), + hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : ''; + + this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash; + this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/' + }; + + this.$$parseLinkUrl = function(url, relHref) { + if (relHref && relHref[0] === '#') { + // special case for links to hash fragments: + // keep the old url and only replace the hash fragment + this.hash(relHref.slice(1)); + return true; + } + var appUrl, prevAppUrl; + var rewrittenUrl; + + if ((appUrl = beginsWith(appBase, url)) !== undefined) { + prevAppUrl = appUrl; + if ((appUrl = beginsWith(basePrefix, appUrl)) !== undefined) { + rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl); + } else { + rewrittenUrl = appBase + prevAppUrl; + } + } else if ((appUrl = beginsWith(appBaseNoFile, url)) !== undefined) { + rewrittenUrl = appBaseNoFile + appUrl; + } else if (appBaseNoFile == url + '/') { + rewrittenUrl = appBaseNoFile; + } + if (rewrittenUrl) { + this.$$parse(rewrittenUrl); + } + return !!rewrittenUrl; + }; +} + + +/** + * LocationHashbangUrl represents url + * This object is exposed as $location service when developer doesn't opt into html5 mode. + * It also serves as the base class for html5 mode fallback on legacy browsers. + * + * @constructor + * @param {string} appBase application base URL + * @param {string} hashPrefix hashbang prefix + */ +function LocationHashbangUrl(appBase, hashPrefix) { + var appBaseNoFile = stripFile(appBase); + + parseAbsoluteUrl(appBase, this); + + + /** + * Parse given hashbang url into properties + * @param {string} url Hashbang url + * @private + */ + this.$$parse = function(url) { + var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url); + var withoutHashUrl; + + if (withoutBaseUrl.charAt(0) === '#') { + + // The rest of the url starts with a hash so we have + // got either a hashbang path or a plain hash fragment + withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl); + if (isUndefined(withoutHashUrl)) { + // There was no hashbang prefix so we just have a hash fragment + withoutHashUrl = withoutBaseUrl; + } + + } else { + // There was no hashbang path nor hash fragment: + // If we are in HTML5 mode we use what is left as the path; + // Otherwise we ignore what is left + withoutHashUrl = this.$$html5 ? withoutBaseUrl : ''; + } + + parseAppUrl(withoutHashUrl, this); + + this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase); + + this.$$compose(); + + /* + * In Windows, on an anchor node on documents loaded from + * the filesystem, the browser will return a pathname + * prefixed with the drive name ('/C:/path') when a + * pathname without a drive is set: + * * a.setAttribute('href', '/foo') + * * a.pathname === '/C:/foo' //true + * + * Inside of Angular, we're always using pathnames that + * do not include drive names for routing. + */ + function removeWindowsDriveName(path, url, base) { + /* + Matches paths for file protocol on windows, + such as /C:/foo/bar, and captures only /foo/bar. + */ + var windowsFilePathExp = /^\/[A-Z]:(\/.*)/; + + var firstPathSegmentMatch; + + //Get the relative path from the input URL. + if (url.indexOf(base) === 0) { + url = url.replace(base, ''); + } + + // The input URL intentionally contains a first path segment that ends with a colon. + if (windowsFilePathExp.exec(url)) { + return path; + } + + firstPathSegmentMatch = windowsFilePathExp.exec(path); + return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path; + } + }; + + /** + * Compose hashbang url and update `absUrl` property + * @private + */ + this.$$compose = function() { + var search = toKeyValue(this.$$search), + hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : ''; + + this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash; + this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : ''); + }; + + this.$$parseLinkUrl = function(url, relHref) { + if (stripHash(appBase) == stripHash(url)) { + this.$$parse(url); + return true; + } + return false; + }; +} + + +/** + * LocationHashbangUrl represents url + * This object is exposed as $location service when html5 history api is enabled but the browser + * does not support it. + * + * @constructor + * @param {string} appBase application base URL + * @param {string} hashPrefix hashbang prefix + */ +function LocationHashbangInHtml5Url(appBase, hashPrefix) { + this.$$html5 = true; + LocationHashbangUrl.apply(this, arguments); + + var appBaseNoFile = stripFile(appBase); + + this.$$parseLinkUrl = function(url, relHref) { + if (relHref && relHref[0] === '#') { + // special case for links to hash fragments: + // keep the old url and only replace the hash fragment + this.hash(relHref.slice(1)); + return true; + } + + var rewrittenUrl; + var appUrl; + + if (appBase == stripHash(url)) { + rewrittenUrl = url; + } else if ((appUrl = beginsWith(appBaseNoFile, url))) { + rewrittenUrl = appBase + hashPrefix + appUrl; + } else if (appBaseNoFile === url + '/') { + rewrittenUrl = appBaseNoFile; + } + if (rewrittenUrl) { + this.$$parse(rewrittenUrl); + } + return !!rewrittenUrl; + }; + + this.$$compose = function() { + var search = toKeyValue(this.$$search), + hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : ''; + + this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash; + // include hashPrefix in $$absUrl when $$url is empty so IE8 & 9 do not reload page because of removal of '#' + this.$$absUrl = appBase + hashPrefix + this.$$url; + }; + +} + + +var locationPrototype = { + + /** + * Are we in html5 mode? + * @private + */ + $$html5: false, + + /** + * Has any change been replacing? + * @private + */ + $$replace: false, + + /** + * @ngdoc method + * @name $location#absUrl + * + * @description + * This method is getter only. + * + * Return full url representation with all segments encoded according to rules specified in + * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt). + * + * + * ```js + * // given url http://example.com/#/some/path?foo=bar&baz=xoxo + * var absUrl = $location.absUrl(); + * // => "http://example.com/#/some/path?foo=bar&baz=xoxo" + * ``` + * + * @return {string} full url + */ + absUrl: locationGetter('$$absUrl'), + + /** + * @ngdoc method + * @name $location#url + * + * @description + * This method is getter / setter. + * + * Return url (e.g. `/path?a=b#hash`) when called without any parameter. + * + * Change path, search and hash, when called with parameter and return `$location`. + * + * + * ```js + * // given url http://example.com/#/some/path?foo=bar&baz=xoxo + * var url = $location.url(); + * // => "/some/path?foo=bar&baz=xoxo" + * ``` + * + * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`) + * @return {string} url + */ + url: function(url) { + if (isUndefined(url)) + return this.$$url; + + var match = PATH_MATCH.exec(url); + if (match[1] || url === '') this.path(decodeURIComponent(match[1])); + if (match[2] || match[1] || url === '') this.search(match[3] || ''); + this.hash(match[5] || ''); + + return this; + }, + + /** + * @ngdoc method + * @name $location#protocol + * + * @description + * This method is getter only. + * + * Return protocol of current url. + * + * + * ```js + * // given url http://example.com/#/some/path?foo=bar&baz=xoxo + * var protocol = $location.protocol(); + * // => "http" + * ``` + * + * @return {string} protocol of current url + */ + protocol: locationGetter('$$protocol'), + + /** + * @ngdoc method + * @name $location#host + * + * @description + * This method is getter only. + * + * Return host of current url. + * + * + * ```js + * // given url http://example.com/#/some/path?foo=bar&baz=xoxo + * var host = $location.host(); + * // => "example.com" + * ``` + * + * @return {string} host of current url. + */ + host: locationGetter('$$host'), + + /** + * @ngdoc method + * @name $location#port + * + * @description + * This method is getter only. + * + * Return port of current url. + * + * + * ```js + * // given url http://example.com/#/some/path?foo=bar&baz=xoxo + * var port = $location.port(); + * // => 80 + * ``` + * + * @return {Number} port + */ + port: locationGetter('$$port'), + + /** + * @ngdoc method + * @name $location#path + * + * @description + * This method is getter / setter. + * + * Return path of current url when called without any parameter. + * + * Change path when called with parameter and return `$location`. + * + * Note: Path should always begin with forward slash (/), this method will add the forward slash + * if it is missing. + * + * + * ```js + * // given url http://example.com/#/some/path?foo=bar&baz=xoxo + * var path = $location.path(); + * // => "/some/path" + * ``` + * + * @param {(string|number)=} path New path + * @return {string} path + */ + path: locationGetterSetter('$$path', function(path) { + path = path !== null ? path.toString() : ''; + return path.charAt(0) == '/' ? path : '/' + path; + }), + + /** + * @ngdoc method + * @name $location#search + * + * @description + * This method is getter / setter. + * + * Return search part (as object) of current url when called without any parameter. + * + * Change search part when called with parameter and return `$location`. + * + * + * ```js + * // given url http://example.com/#/some/path?foo=bar&baz=xoxo + * var searchObject = $location.search(); + * // => {foo: 'bar', baz: 'xoxo'} + * + * // set foo to 'yipee' + * $location.search('foo', 'yipee'); + * // $location.search() => {foo: 'yipee', baz: 'xoxo'} + * ``` + * + * @param {string|Object.|Object.>} search New search params - string or + * hash object. + * + * When called with a single argument the method acts as a setter, setting the `search` component + * of `$location` to the specified value. + * + * If the argument is a hash object containing an array of values, these values will be encoded + * as duplicate search parameters in the url. + * + * @param {(string|Number|Array|boolean)=} paramValue If `search` is a string or number, then `paramValue` + * will override only a single search property. + * + * If `paramValue` is an array, it will override the property of the `search` component of + * `$location` specified via the first argument. + * + * If `paramValue` is `null`, the property specified via the first argument will be deleted. + * + * If `paramValue` is `true`, the property specified via the first argument will be added with no + * value nor trailing equal sign. + * + * @return {Object} If called with no arguments returns the parsed `search` object. If called with + * one or more arguments returns `$location` object itself. + */ + search: function(search, paramValue) { + switch (arguments.length) { + case 0: + return this.$$search; + case 1: + if (isString(search) || isNumber(search)) { + search = search.toString(); + this.$$search = parseKeyValue(search); + } else if (isObject(search)) { + search = copy(search, {}); + // remove object undefined or null properties + forEach(search, function(value, key) { + if (value == null) delete search[key]; + }); + + this.$$search = search; + } else { + throw $locationMinErr('isrcharg', + 'The first argument of the `$location#search()` call must be a string or an object.'); + } + break; + default: + if (isUndefined(paramValue) || paramValue === null) { + delete this.$$search[search]; + } else { + this.$$search[search] = paramValue; + } + } + + this.$$compose(); + return this; + }, + + /** + * @ngdoc method + * @name $location#hash + * + * @description + * This method is getter / setter. + * + * Return hash fragment when called without any parameter. + * + * Change hash fragment when called with parameter and return `$location`. + * + * + * ```js + * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue + * var hash = $location.hash(); + * // => "hashValue" + * ``` + * + * @param {(string|number)=} hash New hash fragment + * @return {string} hash + */ + hash: locationGetterSetter('$$hash', function(hash) { + return hash !== null ? hash.toString() : ''; + }), + + /** + * @ngdoc method + * @name $location#replace + * + * @description + * If called, all changes to $location during current `$digest` will be replacing current history + * record, instead of adding new one. + */ + replace: function() { + this.$$replace = true; + return this; + } +}; + +forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) { + Location.prototype = Object.create(locationPrototype); + + /** + * @ngdoc method + * @name $location#state + * + * @description + * This method is getter / setter. + * + * Return the history state object when called without any parameter. + * + * Change the history state object when called with one parameter and return `$location`. + * The state object is later passed to `pushState` or `replaceState`. + * + * NOTE: This method is supported only in HTML5 mode and only in browsers supporting + * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support + * older browsers (like IE9 or Android < 4.0), don't use this method. + * + * @param {object=} state State object for pushState or replaceState + * @return {object} state + */ + Location.prototype.state = function(state) { + if (!arguments.length) + return this.$$state; + + if (Location !== LocationHtml5Url || !this.$$html5) { + throw $locationMinErr('nostate', 'History API state support is available only ' + + 'in HTML5 mode and only in browsers supporting HTML5 History API'); + } + // The user might modify `stateObject` after invoking `$location.state(stateObject)` + // but we're changing the $$state reference to $browser.state() during the $digest + // so the modification window is narrow. + this.$$state = isUndefined(state) ? null : state; + + return this; + }; +}); + + +function locationGetter(property) { + return function() { + return this[property]; + }; +} + + +function locationGetterSetter(property, preprocess) { + return function(value) { + if (isUndefined(value)) + return this[property]; + + this[property] = preprocess(value); + this.$$compose(); + + return this; + }; +} + + +/** + * @ngdoc service + * @name $location + * + * @requires $rootElement + * + * @description + * The $location service parses the URL in the browser address bar (based on the + * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL + * available to your application. Changes to the URL in the address bar are reflected into + * $location service and changes to $location are reflected into the browser address bar. + * + * **The $location service:** + * + * - Exposes the current URL in the browser address bar, so you can + * - Watch and observe the URL. + * - Change the URL. + * - Synchronizes the URL with the browser when the user + * - Changes the address bar. + * - Clicks the back or forward button (or clicks a History link). + * - Clicks on a link. + * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash). + * + * For more information see {@link guide/$location Developer Guide: Using $location} + */ + +/** + * @ngdoc provider + * @name $locationProvider + * @description + * Use the `$locationProvider` to configure how the application deep linking paths are stored. + */ +function $LocationProvider() { + var hashPrefix = '', + html5Mode = { + enabled: false, + requireBase: true, + rewriteLinks: true + }; + + /** + * @ngdoc method + * @name $locationProvider#hashPrefix + * @description + * @param {string=} prefix Prefix for hash part (containing path and search) + * @returns {*} current value if used as getter or itself (chaining) if used as setter + */ + this.hashPrefix = function(prefix) { + if (isDefined(prefix)) { + hashPrefix = prefix; + return this; + } else { + return hashPrefix; + } + }; + + /** + * @ngdoc method + * @name $locationProvider#html5Mode + * @description + * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value. + * If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported + * properties: + * - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to + * change urls where supported. Will fall back to hash-prefixed paths in browsers that do not + * support `pushState`. + * - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies + * whether or not a tag is required to be present. If `enabled` and `requireBase` are + * true, and a base tag is not present, an error will be thrown when `$location` is injected. + * See the {@link guide/$location $location guide for more information} + * - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled, + * enables/disables url rewriting for relative links. + * + * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter + */ + this.html5Mode = function(mode) { + if (isBoolean(mode)) { + html5Mode.enabled = mode; + return this; + } else if (isObject(mode)) { + + if (isBoolean(mode.enabled)) { + html5Mode.enabled = mode.enabled; + } + + if (isBoolean(mode.requireBase)) { + html5Mode.requireBase = mode.requireBase; + } + + if (isBoolean(mode.rewriteLinks)) { + html5Mode.rewriteLinks = mode.rewriteLinks; + } + + return this; + } else { + return html5Mode; + } + }; + + /** + * @ngdoc event + * @name $location#$locationChangeStart + * @eventType broadcast on root scope + * @description + * Broadcasted before a URL will change. + * + * This change can be prevented by calling + * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more + * details about event object. Upon successful change + * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired. + * + * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when + * the browser supports the HTML5 History API. + * + * @param {Object} angularEvent Synthetic event object. + * @param {string} newUrl New URL + * @param {string=} oldUrl URL that was before it was changed. + * @param {string=} newState New history state object + * @param {string=} oldState History state object that was before it was changed. + */ + + /** + * @ngdoc event + * @name $location#$locationChangeSuccess + * @eventType broadcast on root scope + * @description + * Broadcasted after a URL was changed. + * + * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when + * the browser supports the HTML5 History API. + * + * @param {Object} angularEvent Synthetic event object. + * @param {string} newUrl New URL + * @param {string=} oldUrl URL that was before it was changed. + * @param {string=} newState New history state object + * @param {string=} oldState History state object that was before it was changed. + */ + + this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window', + function($rootScope, $browser, $sniffer, $rootElement, $window) { + var $location, + LocationMode, + baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to '' + initialUrl = $browser.url(), + appBase; + + if (html5Mode.enabled) { + if (!baseHref && html5Mode.requireBase) { + throw $locationMinErr('nobase', + "$location in HTML5 mode requires a tag to be present!"); + } + appBase = serverBase(initialUrl) + (baseHref || '/'); + LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url; + } else { + appBase = stripHash(initialUrl); + LocationMode = LocationHashbangUrl; + } + $location = new LocationMode(appBase, '#' + hashPrefix); + $location.$$parseLinkUrl(initialUrl, initialUrl); + + $location.$$state = $browser.state(); + + var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i; + + function setBrowserUrlWithFallback(url, replace, state) { + var oldUrl = $location.url(); + var oldState = $location.$$state; + try { + $browser.url(url, replace, state); + + // Make sure $location.state() returns referentially identical (not just deeply equal) + // state object; this makes possible quick checking if the state changed in the digest + // loop. Checking deep equality would be too expensive. + $location.$$state = $browser.state(); + } catch (e) { + // Restore old values if pushState fails + $location.url(oldUrl); + $location.$$state = oldState; + + throw e; + } + } + + $rootElement.on('click', function(event) { + // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser) + // currently we open nice url link and redirect then + + if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return; + + var elm = jqLite(event.target); + + // traverse the DOM up to find first A tag + while (nodeName_(elm[0]) !== 'a') { + // ignore rewriting if no A tag (reached root element, or no parent - removed from document) + if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return; + } + + var absHref = elm.prop('href'); + // get the actual href attribute - see + // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx + var relHref = elm.attr('href') || elm.attr('xlink:href'); + + if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') { + // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during + // an animation. + absHref = urlResolve(absHref.animVal).href; + } + + // Ignore when url is started with javascript: or mailto: + if (IGNORE_URI_REGEXP.test(absHref)) return; + + if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) { + if ($location.$$parseLinkUrl(absHref, relHref)) { + // We do a preventDefault for all urls that are part of the angular application, + // in html5mode and also without, so that we are able to abort navigation without + // getting double entries in the location history. + event.preventDefault(); + // update location manually + if ($location.absUrl() != $browser.url()) { + $rootScope.$apply(); + // hack to work around FF6 bug 684208 when scenario runner clicks on links + $window.angular['ff-684208-preventDefault'] = true; + } + } + } + }); + + + // rewrite hashbang url <> html5 url + if (trimEmptyHash($location.absUrl()) != trimEmptyHash(initialUrl)) { + $browser.url($location.absUrl(), true); + } + + var initializing = true; + + // update $location when $browser url changes + $browser.onUrlChange(function(newUrl, newState) { + $rootScope.$evalAsync(function() { + var oldUrl = $location.absUrl(); + var oldState = $location.$$state; + var defaultPrevented; + + $location.$$parse(newUrl); + $location.$$state = newState; + + defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl, + newState, oldState).defaultPrevented; + + // if the location was changed by a `$locationChangeStart` handler then stop + // processing this location change + if ($location.absUrl() !== newUrl) return; + + if (defaultPrevented) { + $location.$$parse(oldUrl); + $location.$$state = oldState; + setBrowserUrlWithFallback(oldUrl, false, oldState); + } else { + initializing = false; + afterLocationChange(oldUrl, oldState); + } + }); + if (!$rootScope.$$phase) $rootScope.$digest(); + }); + + // update browser + $rootScope.$watch(function $locationWatch() { + var oldUrl = trimEmptyHash($browser.url()); + var newUrl = trimEmptyHash($location.absUrl()); + var oldState = $browser.state(); + var currentReplace = $location.$$replace; + var urlOrStateChanged = oldUrl !== newUrl || + ($location.$$html5 && $sniffer.history && oldState !== $location.$$state); + + if (initializing || urlOrStateChanged) { + initializing = false; + + $rootScope.$evalAsync(function() { + var newUrl = $location.absUrl(); + var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl, + $location.$$state, oldState).defaultPrevented; + + // if the location was changed by a `$locationChangeStart` handler then stop + // processing this location change + if ($location.absUrl() !== newUrl) return; + + if (defaultPrevented) { + $location.$$parse(oldUrl); + $location.$$state = oldState; + } else { + if (urlOrStateChanged) { + setBrowserUrlWithFallback(newUrl, currentReplace, + oldState === $location.$$state ? null : $location.$$state); + } + afterLocationChange(oldUrl, oldState); + } + }); + } + + $location.$$replace = false; + + // we don't need to return anything because $evalAsync will make the digest loop dirty when + // there is a change + }); + + return $location; + + function afterLocationChange(oldUrl, oldState) { + $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl, + $location.$$state, oldState); + } +}]; +} + +/** + * @ngdoc service + * @name $log + * @requires $window + * + * @description + * Simple service for logging. Default implementation safely writes the message + * into the browser's console (if present). + * + * The main purpose of this service is to simplify debugging and troubleshooting. + * + * The default is to log `debug` messages. You can use + * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this. + * + * @example + + + angular.module('logExample', []) + .controller('LogController', ['$scope', '$log', function($scope, $log) { + $scope.$log = $log; + $scope.message = 'Hello World!'; + }]); + + +
    +

    Reload this page with open console, enter text and hit the log button...

    + Message: + + + + + +
    +
    +
    + */ + +/** + * @ngdoc provider + * @name $logProvider + * @description + * Use the `$logProvider` to configure how the application logs messages + */ +function $LogProvider() { + var debug = true, + self = this; + + /** + * @ngdoc method + * @name $logProvider#debugEnabled + * @description + * @param {boolean=} flag enable or disable debug level messages + * @returns {*} current value if used as getter or itself (chaining) if used as setter + */ + this.debugEnabled = function(flag) { + if (isDefined(flag)) { + debug = flag; + return this; + } else { + return debug; + } + }; + + this.$get = ['$window', function($window) { + return { + /** + * @ngdoc method + * @name $log#log + * + * @description + * Write a log message + */ + log: consoleLog('log'), + + /** + * @ngdoc method + * @name $log#info + * + * @description + * Write an information message + */ + info: consoleLog('info'), + + /** + * @ngdoc method + * @name $log#warn + * + * @description + * Write a warning message + */ + warn: consoleLog('warn'), + + /** + * @ngdoc method + * @name $log#error + * + * @description + * Write an error message + */ + error: consoleLog('error'), + + /** + * @ngdoc method + * @name $log#debug + * + * @description + * Write a debug message + */ + debug: (function() { + var fn = consoleLog('debug'); + + return function() { + if (debug) { + fn.apply(self, arguments); + } + }; + }()) + }; + + function formatError(arg) { + if (arg instanceof Error) { + if (arg.stack) { + arg = (arg.message && arg.stack.indexOf(arg.message) === -1) + ? 'Error: ' + arg.message + '\n' + arg.stack + : arg.stack; + } else if (arg.sourceURL) { + arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line; + } + } + return arg; + } + + function consoleLog(type) { + var console = $window.console || {}, + logFn = console[type] || console.log || noop, + hasApply = false; + + // Note: reading logFn.apply throws an error in IE11 in IE8 document mode. + // The reason behind this is that console.log has type "object" in IE8... + try { + hasApply = !!logFn.apply; + } catch (e) {} + + if (hasApply) { + return function() { + var args = []; + forEach(arguments, function(arg) { + args.push(formatError(arg)); + }); + return logFn.apply(console, args); + }; + } + + // we are IE which either doesn't have window.console => this is noop and we do nothing, + // or we are IE where console.log doesn't have apply so we log at least first 2 args + return function(arg1, arg2) { + logFn(arg1, arg2 == null ? '' : arg2); + }; + } + }]; +} + +var $parseMinErr = minErr('$parse'); + +// Sandboxing Angular Expressions +// ------------------------------ +// Angular expressions are generally considered safe because these expressions only have direct +// access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by +// obtaining a reference to native JS functions such as the Function constructor. +// +// As an example, consider the following Angular expression: +// +// {}.toString.constructor('alert("evil JS code")') +// +// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits +// against the expression language, but not to prevent exploits that were enabled by exposing +// sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good +// practice and therefore we are not even trying to protect against interaction with an object +// explicitly exposed in this way. +// +// In general, it is not possible to access a Window object from an angular expression unless a +// window or some DOM object that has a reference to window is published onto a Scope. +// Similarly we prevent invocations of function known to be dangerous, as well as assignments to +// native objects. +// +// See https://docs.angularjs.org/guide/security + + +function ensureSafeMemberName(name, fullExpression) { + if (name === "__defineGetter__" || name === "__defineSetter__" + || name === "__lookupGetter__" || name === "__lookupSetter__" + || name === "__proto__") { + throw $parseMinErr('isecfld', + 'Attempting to access a disallowed field in Angular expressions! ' + + 'Expression: {0}', fullExpression); + } + return name; +} + +function ensureSafeObject(obj, fullExpression) { + // nifty check if obj is Function that is fast and works across iframes and other contexts + if (obj) { + if (obj.constructor === obj) { + throw $parseMinErr('isecfn', + 'Referencing Function in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } else if (// isWindow(obj) + obj.window === obj) { + throw $parseMinErr('isecwindow', + 'Referencing the Window in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } else if (// isElement(obj) + obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) { + throw $parseMinErr('isecdom', + 'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } else if (// block Object so that we can't get hold of dangerous Object.* methods + obj === Object) { + throw $parseMinErr('isecobj', + 'Referencing Object in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } + } + return obj; +} + +var CALL = Function.prototype.call; +var APPLY = Function.prototype.apply; +var BIND = Function.prototype.bind; + +function ensureSafeFunction(obj, fullExpression) { + if (obj) { + if (obj.constructor === obj) { + throw $parseMinErr('isecfn', + 'Referencing Function in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } else if (obj === CALL || obj === APPLY || obj === BIND) { + throw $parseMinErr('isecff', + 'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } + } +} + +//Keyword constants +var CONSTANTS = createMap(); +forEach({ + 'null': function() { return null; }, + 'true': function() { return true; }, + 'false': function() { return false; }, + 'undefined': function() {} +}, function(constantGetter, name) { + constantGetter.constant = constantGetter.literal = constantGetter.sharedGetter = true; + CONSTANTS[name] = constantGetter; +}); + +//Not quite a constant, but can be lex/parsed the same +CONSTANTS['this'] = function(self) { return self; }; +CONSTANTS['this'].sharedGetter = true; + + +//Operators - will be wrapped by binaryFn/unaryFn/assignment/filter +var OPERATORS = extend(createMap(), { + '+':function(self, locals, a, b) { + a=a(self, locals); b=b(self, locals); + if (isDefined(a)) { + if (isDefined(b)) { + return a + b; + } + return a; + } + return isDefined(b) ? b : undefined;}, + '-':function(self, locals, a, b) { + a=a(self, locals); b=b(self, locals); + return (isDefined(a) ? a : 0) - (isDefined(b) ? b : 0); + }, + '*':function(self, locals, a, b) {return a(self, locals) * b(self, locals);}, + '/':function(self, locals, a, b) {return a(self, locals) / b(self, locals);}, + '%':function(self, locals, a, b) {return a(self, locals) % b(self, locals);}, + '===':function(self, locals, a, b) {return a(self, locals) === b(self, locals);}, + '!==':function(self, locals, a, b) {return a(self, locals) !== b(self, locals);}, + '==':function(self, locals, a, b) {return a(self, locals) == b(self, locals);}, + '!=':function(self, locals, a, b) {return a(self, locals) != b(self, locals);}, + '<':function(self, locals, a, b) {return a(self, locals) < b(self, locals);}, + '>':function(self, locals, a, b) {return a(self, locals) > b(self, locals);}, + '<=':function(self, locals, a, b) {return a(self, locals) <= b(self, locals);}, + '>=':function(self, locals, a, b) {return a(self, locals) >= b(self, locals);}, + '&&':function(self, locals, a, b) {return a(self, locals) && b(self, locals);}, + '||':function(self, locals, a, b) {return a(self, locals) || b(self, locals);}, + '!':function(self, locals, a) {return !a(self, locals);}, + + //Tokenized as operators but parsed as assignment/filters + '=':true, + '|':true +}); +var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'}; + + +///////////////////////////////////////// + + +/** + * @constructor + */ +var Lexer = function(options) { + this.options = options; +}; + +Lexer.prototype = { + constructor: Lexer, + + lex: function(text) { + this.text = text; + this.index = 0; + this.tokens = []; + + while (this.index < this.text.length) { + var ch = this.text.charAt(this.index); + if (ch === '"' || ch === "'") { + this.readString(ch); + } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) { + this.readNumber(); + } else if (this.isIdent(ch)) { + this.readIdent(); + } else if (this.is(ch, '(){}[].,;:?')) { + this.tokens.push({index: this.index, text: ch}); + this.index++; + } else if (this.isWhitespace(ch)) { + this.index++; + } else { + var ch2 = ch + this.peek(); + var ch3 = ch2 + this.peek(2); + var op1 = OPERATORS[ch]; + var op2 = OPERATORS[ch2]; + var op3 = OPERATORS[ch3]; + if (op1 || op2 || op3) { + var token = op3 ? ch3 : (op2 ? ch2 : ch); + this.tokens.push({index: this.index, text: token, operator: true}); + this.index += token.length; + } else { + this.throwError('Unexpected next character ', this.index, this.index + 1); + } + } + } + return this.tokens; + }, + + is: function(ch, chars) { + return chars.indexOf(ch) !== -1; + }, + + peek: function(i) { + var num = i || 1; + return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false; + }, + + isNumber: function(ch) { + return ('0' <= ch && ch <= '9') && typeof ch === "string"; + }, + + isWhitespace: function(ch) { + // IE treats non-breaking space as \u00A0 + return (ch === ' ' || ch === '\r' || ch === '\t' || + ch === '\n' || ch === '\v' || ch === '\u00A0'); + }, + + isIdent: function(ch) { + return ('a' <= ch && ch <= 'z' || + 'A' <= ch && ch <= 'Z' || + '_' === ch || ch === '$'); + }, + + isExpOperator: function(ch) { + return (ch === '-' || ch === '+' || this.isNumber(ch)); + }, + + throwError: function(error, start, end) { + end = end || this.index; + var colStr = (isDefined(start) + ? 's ' + start + '-' + this.index + ' [' + this.text.substring(start, end) + ']' + : ' ' + end); + throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].', + error, colStr, this.text); + }, + + readNumber: function() { + var number = ''; + var start = this.index; + while (this.index < this.text.length) { + var ch = lowercase(this.text.charAt(this.index)); + if (ch == '.' || this.isNumber(ch)) { + number += ch; + } else { + var peekCh = this.peek(); + if (ch == 'e' && this.isExpOperator(peekCh)) { + number += ch; + } else if (this.isExpOperator(ch) && + peekCh && this.isNumber(peekCh) && + number.charAt(number.length - 1) == 'e') { + number += ch; + } else if (this.isExpOperator(ch) && + (!peekCh || !this.isNumber(peekCh)) && + number.charAt(number.length - 1) == 'e') { + this.throwError('Invalid exponent'); + } else { + break; + } + } + this.index++; + } + this.tokens.push({ + index: start, + text: number, + constant: true, + value: Number(number) + }); + }, + + readIdent: function() { + var start = this.index; + while (this.index < this.text.length) { + var ch = this.text.charAt(this.index); + if (!(this.isIdent(ch) || this.isNumber(ch))) { + break; + } + this.index++; + } + this.tokens.push({ + index: start, + text: this.text.slice(start, this.index), + identifier: true + }); + }, + + readString: function(quote) { + var start = this.index; + this.index++; + var string = ''; + var rawString = quote; + var escape = false; + while (this.index < this.text.length) { + var ch = this.text.charAt(this.index); + rawString += ch; + if (escape) { + if (ch === 'u') { + var hex = this.text.substring(this.index + 1, this.index + 5); + if (!hex.match(/[\da-f]{4}/i)) + this.throwError('Invalid unicode escape [\\u' + hex + ']'); + this.index += 4; + string += String.fromCharCode(parseInt(hex, 16)); + } else { + var rep = ESCAPE[ch]; + string = string + (rep || ch); + } + escape = false; + } else if (ch === '\\') { + escape = true; + } else if (ch === quote) { + this.index++; + this.tokens.push({ + index: start, + text: rawString, + constant: true, + value: string + }); + return; + } else { + string += ch; + } + this.index++; + } + this.throwError('Unterminated quote', start); + } +}; + + +function isConstant(exp) { + return exp.constant; +} + +/** + * @constructor + */ +var Parser = function(lexer, $filter, options) { + this.lexer = lexer; + this.$filter = $filter; + this.options = options; +}; + +Parser.ZERO = extend(function() { + return 0; +}, { + sharedGetter: true, + constant: true +}); + +Parser.prototype = { + constructor: Parser, + + parse: function(text) { + this.text = text; + this.tokens = this.lexer.lex(text); + + var value = this.statements(); + + if (this.tokens.length !== 0) { + this.throwError('is an unexpected token', this.tokens[0]); + } + + value.literal = !!value.literal; + value.constant = !!value.constant; + + return value; + }, + + primary: function() { + var primary; + if (this.expect('(')) { + primary = this.filterChain(); + this.consume(')'); + } else if (this.expect('[')) { + primary = this.arrayDeclaration(); + } else if (this.expect('{')) { + primary = this.object(); + } else if (this.peek().identifier && this.peek().text in CONSTANTS) { + primary = CONSTANTS[this.consume().text]; + } else if (this.peek().identifier) { + primary = this.identifier(); + } else if (this.peek().constant) { + primary = this.constant(); + } else { + this.throwError('not a primary expression', this.peek()); + } + + var next, context; + while ((next = this.expect('(', '[', '.'))) { + if (next.text === '(') { + primary = this.functionCall(primary, context); + context = null; + } else if (next.text === '[') { + context = primary; + primary = this.objectIndex(primary); + } else if (next.text === '.') { + context = primary; + primary = this.fieldAccess(primary); + } else { + this.throwError('IMPOSSIBLE'); + } + } + return primary; + }, + + throwError: function(msg, token) { + throw $parseMinErr('syntax', + 'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].', + token.text, msg, (token.index + 1), this.text, this.text.substring(token.index)); + }, + + peekToken: function() { + if (this.tokens.length === 0) + throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text); + return this.tokens[0]; + }, + + peek: function(e1, e2, e3, e4) { + return this.peekAhead(0, e1, e2, e3, e4); + }, + peekAhead: function(i, e1, e2, e3, e4) { + if (this.tokens.length > i) { + var token = this.tokens[i]; + var t = token.text; + if (t === e1 || t === e2 || t === e3 || t === e4 || + (!e1 && !e2 && !e3 && !e4)) { + return token; + } + } + return false; + }, + + expect: function(e1, e2, e3, e4) { + var token = this.peek(e1, e2, e3, e4); + if (token) { + this.tokens.shift(); + return token; + } + return false; + }, + + consume: function(e1) { + if (this.tokens.length === 0) { + throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text); + } + + var token = this.expect(e1); + if (!token) { + this.throwError('is unexpected, expecting [' + e1 + ']', this.peek()); + } + return token; + }, + + unaryFn: function(op, right) { + var fn = OPERATORS[op]; + return extend(function $parseUnaryFn(self, locals) { + return fn(self, locals, right); + }, { + constant:right.constant, + inputs: [right] + }); + }, + + binaryFn: function(left, op, right, isBranching) { + var fn = OPERATORS[op]; + return extend(function $parseBinaryFn(self, locals) { + return fn(self, locals, left, right); + }, { + constant: left.constant && right.constant, + inputs: !isBranching && [left, right] + }); + }, + + identifier: function() { + var id = this.consume().text; + + //Continue reading each `.identifier` unless it is a method invocation + while (this.peek('.') && this.peekAhead(1).identifier && !this.peekAhead(2, '(')) { + id += this.consume().text + this.consume().text; + } + + return getterFn(id, this.options, this.text); + }, + + constant: function() { + var value = this.consume().value; + + return extend(function $parseConstant() { + return value; + }, { + constant: true, + literal: true + }); + }, + + statements: function() { + var statements = []; + while (true) { + if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']')) + statements.push(this.filterChain()); + if (!this.expect(';')) { + // optimize for the common case where there is only one statement. + // TODO(size): maybe we should not support multiple statements? + return (statements.length === 1) + ? statements[0] + : function $parseStatements(self, locals) { + var value; + for (var i = 0, ii = statements.length; i < ii; i++) { + value = statements[i](self, locals); + } + return value; + }; + } + } + }, + + filterChain: function() { + var left = this.expression(); + var token; + while ((token = this.expect('|'))) { + left = this.filter(left); + } + return left; + }, + + filter: function(inputFn) { + var fn = this.$filter(this.consume().text); + var argsFn; + var args; + + if (this.peek(':')) { + argsFn = []; + args = []; // we can safely reuse the array + while (this.expect(':')) { + argsFn.push(this.expression()); + } + } + + var inputs = [inputFn].concat(argsFn || []); + + return extend(function $parseFilter(self, locals) { + var input = inputFn(self, locals); + if (args) { + args[0] = input; + + var i = argsFn.length; + while (i--) { + args[i + 1] = argsFn[i](self, locals); + } + + return fn.apply(undefined, args); + } + + return fn(input); + }, { + constant: !fn.$stateful && inputs.every(isConstant), + inputs: !fn.$stateful && inputs + }); + }, + + expression: function() { + return this.assignment(); + }, + + assignment: function() { + var left = this.ternary(); + var right; + var token; + if ((token = this.expect('='))) { + if (!left.assign) { + this.throwError('implies assignment but [' + + this.text.substring(0, token.index) + '] can not be assigned to', token); + } + right = this.ternary(); + return extend(function $parseAssignment(scope, locals) { + return left.assign(scope, right(scope, locals), locals); + }, { + inputs: [left, right] + }); + } + return left; + }, + + ternary: function() { + var left = this.logicalOR(); + var middle; + var token; + if ((token = this.expect('?'))) { + middle = this.assignment(); + if (this.consume(':')) { + var right = this.assignment(); + + return extend(function $parseTernary(self, locals) { + return left(self, locals) ? middle(self, locals) : right(self, locals); + }, { + constant: left.constant && middle.constant && right.constant + }); + } + } + + return left; + }, + + logicalOR: function() { + var left = this.logicalAND(); + var token; + while ((token = this.expect('||'))) { + left = this.binaryFn(left, token.text, this.logicalAND(), true); + } + return left; + }, + + logicalAND: function() { + var left = this.equality(); + var token; + while ((token = this.expect('&&'))) { + left = this.binaryFn(left, token.text, this.equality(), true); + } + return left; + }, + + equality: function() { + var left = this.relational(); + var token; + while ((token = this.expect('==','!=','===','!=='))) { + left = this.binaryFn(left, token.text, this.relational()); + } + return left; + }, + + relational: function() { + var left = this.additive(); + var token; + while ((token = this.expect('<', '>', '<=', '>='))) { + left = this.binaryFn(left, token.text, this.additive()); + } + return left; + }, + + additive: function() { + var left = this.multiplicative(); + var token; + while ((token = this.expect('+','-'))) { + left = this.binaryFn(left, token.text, this.multiplicative()); + } + return left; + }, + + multiplicative: function() { + var left = this.unary(); + var token; + while ((token = this.expect('*','/','%'))) { + left = this.binaryFn(left, token.text, this.unary()); + } + return left; + }, + + unary: function() { + var token; + if (this.expect('+')) { + return this.primary(); + } else if ((token = this.expect('-'))) { + return this.binaryFn(Parser.ZERO, token.text, this.unary()); + } else if ((token = this.expect('!'))) { + return this.unaryFn(token.text, this.unary()); + } else { + return this.primary(); + } + }, + + fieldAccess: function(object) { + var getter = this.identifier(); + + return extend(function $parseFieldAccess(scope, locals, self) { + var o = self || object(scope, locals); + return (o == null) ? undefined : getter(o); + }, { + assign: function(scope, value, locals) { + var o = object(scope, locals); + if (!o) object.assign(scope, o = {}, locals); + return getter.assign(o, value); + } + }); + }, + + objectIndex: function(obj) { + var expression = this.text; + + var indexFn = this.expression(); + this.consume(']'); + + return extend(function $parseObjectIndex(self, locals) { + var o = obj(self, locals), + i = indexFn(self, locals), + v; + + ensureSafeMemberName(i, expression); + if (!o) return undefined; + v = ensureSafeObject(o[i], expression); + return v; + }, { + assign: function(self, value, locals) { + var key = ensureSafeMemberName(indexFn(self, locals), expression); + // prevent overwriting of Function.constructor which would break ensureSafeObject check + var o = ensureSafeObject(obj(self, locals), expression); + if (!o) obj.assign(self, o = {}, locals); + return o[key] = value; + } + }); + }, + + functionCall: function(fnGetter, contextGetter) { + var argsFn = []; + if (this.peekToken().text !== ')') { + do { + argsFn.push(this.expression()); + } while (this.expect(',')); + } + this.consume(')'); + + var expressionText = this.text; + // we can safely reuse the array across invocations + var args = argsFn.length ? [] : null; + + return function $parseFunctionCall(scope, locals) { + var context = contextGetter ? contextGetter(scope, locals) : isDefined(contextGetter) ? undefined : scope; + var fn = fnGetter(scope, locals, context) || noop; + + if (args) { + var i = argsFn.length; + while (i--) { + args[i] = ensureSafeObject(argsFn[i](scope, locals), expressionText); + } + } + + ensureSafeObject(context, expressionText); + ensureSafeFunction(fn, expressionText); + + // IE doesn't have apply for some native functions + var v = fn.apply + ? fn.apply(context, args) + : fn(args[0], args[1], args[2], args[3], args[4]); + + if (args) { + // Free-up the memory (arguments of the last function call). + args.length = 0; + } + + return ensureSafeObject(v, expressionText); + }; + }, + + // This is used with json array declaration + arrayDeclaration: function() { + var elementFns = []; + if (this.peekToken().text !== ']') { + do { + if (this.peek(']')) { + // Support trailing commas per ES5.1. + break; + } + elementFns.push(this.expression()); + } while (this.expect(',')); + } + this.consume(']'); + + return extend(function $parseArrayLiteral(self, locals) { + var array = []; + for (var i = 0, ii = elementFns.length; i < ii; i++) { + array.push(elementFns[i](self, locals)); + } + return array; + }, { + literal: true, + constant: elementFns.every(isConstant), + inputs: elementFns + }); + }, + + object: function() { + var keys = [], valueFns = []; + if (this.peekToken().text !== '}') { + do { + if (this.peek('}')) { + // Support trailing commas per ES5.1. + break; + } + var token = this.consume(); + if (token.constant) { + keys.push(token.value); + } else if (token.identifier) { + keys.push(token.text); + } else { + this.throwError("invalid key", token); + } + this.consume(':'); + valueFns.push(this.expression()); + } while (this.expect(',')); + } + this.consume('}'); + + return extend(function $parseObjectLiteral(self, locals) { + var object = {}; + for (var i = 0, ii = valueFns.length; i < ii; i++) { + object[keys[i]] = valueFns[i](self, locals); + } + return object; + }, { + literal: true, + constant: valueFns.every(isConstant), + inputs: valueFns + }); + } +}; + + +////////////////////////////////////////////////// +// Parser helper functions +////////////////////////////////////////////////// + +function setter(obj, locals, path, setValue, fullExp) { + ensureSafeObject(obj, fullExp); + ensureSafeObject(locals, fullExp); + + var element = path.split('.'), key; + for (var i = 0; element.length > 1; i++) { + key = ensureSafeMemberName(element.shift(), fullExp); + var propertyObj = (i === 0 && locals && locals[key]) || obj[key]; + if (!propertyObj) { + propertyObj = {}; + obj[key] = propertyObj; + } + obj = ensureSafeObject(propertyObj, fullExp); + } + key = ensureSafeMemberName(element.shift(), fullExp); + ensureSafeObject(obj[key], fullExp); + obj[key] = setValue; + return setValue; +} + +var getterFnCacheDefault = createMap(); +var getterFnCacheExpensive = createMap(); + +function isPossiblyDangerousMemberName(name) { + return name == 'constructor'; +} + +/** + * Implementation of the "Black Hole" variant from: + * - http://jsperf.com/angularjs-parse-getter/4 + * - http://jsperf.com/path-evaluation-simplified/7 + */ +function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, expensiveChecks) { + ensureSafeMemberName(key0, fullExp); + ensureSafeMemberName(key1, fullExp); + ensureSafeMemberName(key2, fullExp); + ensureSafeMemberName(key3, fullExp); + ensureSafeMemberName(key4, fullExp); + var eso = function(o) { + return ensureSafeObject(o, fullExp); + }; + var eso0 = (expensiveChecks || isPossiblyDangerousMemberName(key0)) ? eso : identity; + var eso1 = (expensiveChecks || isPossiblyDangerousMemberName(key1)) ? eso : identity; + var eso2 = (expensiveChecks || isPossiblyDangerousMemberName(key2)) ? eso : identity; + var eso3 = (expensiveChecks || isPossiblyDangerousMemberName(key3)) ? eso : identity; + var eso4 = (expensiveChecks || isPossiblyDangerousMemberName(key4)) ? eso : identity; + + return function cspSafeGetter(scope, locals) { + var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope; + + if (pathVal == null) return pathVal; + pathVal = eso0(pathVal[key0]); + + if (!key1) return pathVal; + if (pathVal == null) return undefined; + pathVal = eso1(pathVal[key1]); + + if (!key2) return pathVal; + if (pathVal == null) return undefined; + pathVal = eso2(pathVal[key2]); + + if (!key3) return pathVal; + if (pathVal == null) return undefined; + pathVal = eso3(pathVal[key3]); + + if (!key4) return pathVal; + if (pathVal == null) return undefined; + pathVal = eso4(pathVal[key4]); + + return pathVal; + }; +} + +function getterFnWithEnsureSafeObject(fn, fullExpression) { + return function(s, l) { + return fn(s, l, ensureSafeObject, fullExpression); + }; +} + +function getterFn(path, options, fullExp) { + var expensiveChecks = options.expensiveChecks; + var getterFnCache = (expensiveChecks ? getterFnCacheExpensive : getterFnCacheDefault); + var fn = getterFnCache[path]; + if (fn) return fn; + + + var pathKeys = path.split('.'), + pathKeysLength = pathKeys.length; + + // http://jsperf.com/angularjs-parse-getter/6 + if (options.csp) { + if (pathKeysLength < 6) { + fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp, expensiveChecks); + } else { + fn = function cspSafeGetter(scope, locals) { + var i = 0, val; + do { + val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], + pathKeys[i++], fullExp, expensiveChecks)(scope, locals); + + locals = undefined; // clear after first iteration + scope = val; + } while (i < pathKeysLength); + return val; + }; + } + } else { + var code = ''; + if (expensiveChecks) { + code += 's = eso(s, fe);\nl = eso(l, fe);\n'; + } + var needsEnsureSafeObject = expensiveChecks; + forEach(pathKeys, function(key, index) { + ensureSafeMemberName(key, fullExp); + var lookupJs = (index + // we simply dereference 's' on any .dot notation + ? 's' + // but if we are first then we check locals first, and if so read it first + : '((l&&l.hasOwnProperty("' + key + '"))?l:s)') + '.' + key; + if (expensiveChecks || isPossiblyDangerousMemberName(key)) { + lookupJs = 'eso(' + lookupJs + ', fe)'; + needsEnsureSafeObject = true; + } + code += 'if(s == null) return undefined;\n' + + 's=' + lookupJs + ';\n'; + }); + code += 'return s;'; + + /* jshint -W054 */ + var evaledFnGetter = new Function('s', 'l', 'eso', 'fe', code); // s=scope, l=locals, eso=ensureSafeObject + /* jshint +W054 */ + evaledFnGetter.toString = valueFn(code); + if (needsEnsureSafeObject) { + evaledFnGetter = getterFnWithEnsureSafeObject(evaledFnGetter, fullExp); + } + fn = evaledFnGetter; + } + + fn.sharedGetter = true; + fn.assign = function(self, value, locals) { + return setter(self, locals, path, value, path); + }; + getterFnCache[path] = fn; + return fn; +} + +var objectValueOf = Object.prototype.valueOf; + +function getValueOf(value) { + return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value); +} + +/////////////////////////////////// + +/** + * @ngdoc service + * @name $parse + * @kind function + * + * @description + * + * Converts Angular {@link guide/expression expression} into a function. + * + * ```js + * var getter = $parse('user.name'); + * var setter = getter.assign; + * var context = {user:{name:'angular'}}; + * var locals = {user:{name:'local'}}; + * + * expect(getter(context)).toEqual('angular'); + * setter(context, 'newValue'); + * expect(context.user.name).toEqual('newValue'); + * expect(getter(context, locals)).toEqual('local'); + * ``` + * + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + * + * The returned function also has the following properties: + * * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript + * literal. + * * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript + * constant literals. + * * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be + * set to a function to change its value on the given context. + * + */ + + +/** + * @ngdoc provider + * @name $parseProvider + * + * @description + * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse} + * service. + */ +function $ParseProvider() { + var cacheDefault = createMap(); + var cacheExpensive = createMap(); + + + + this.$get = ['$filter', '$sniffer', function($filter, $sniffer) { + var $parseOptions = { + csp: $sniffer.csp, + expensiveChecks: false + }, + $parseOptionsExpensive = { + csp: $sniffer.csp, + expensiveChecks: true + }; + + function wrapSharedExpression(exp) { + var wrapped = exp; + + if (exp.sharedGetter) { + wrapped = function $parseWrapper(self, locals) { + return exp(self, locals); + }; + wrapped.literal = exp.literal; + wrapped.constant = exp.constant; + wrapped.assign = exp.assign; + } + + return wrapped; + } + + return function $parse(exp, interceptorFn, expensiveChecks) { + var parsedExpression, oneTime, cacheKey; + + switch (typeof exp) { + case 'string': + cacheKey = exp = exp.trim(); + + var cache = (expensiveChecks ? cacheExpensive : cacheDefault); + parsedExpression = cache[cacheKey]; + + if (!parsedExpression) { + if (exp.charAt(0) === ':' && exp.charAt(1) === ':') { + oneTime = true; + exp = exp.substring(2); + } + + var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions; + var lexer = new Lexer(parseOptions); + var parser = new Parser(lexer, $filter, parseOptions); + parsedExpression = parser.parse(exp); + + if (parsedExpression.constant) { + parsedExpression.$$watchDelegate = constantWatchDelegate; + } else if (oneTime) { + //oneTime is not part of the exp passed to the Parser so we may have to + //wrap the parsedExpression before adding a $$watchDelegate + parsedExpression = wrapSharedExpression(parsedExpression); + parsedExpression.$$watchDelegate = parsedExpression.literal ? + oneTimeLiteralWatchDelegate : oneTimeWatchDelegate; + } else if (parsedExpression.inputs) { + parsedExpression.$$watchDelegate = inputsWatchDelegate; + } + + cache[cacheKey] = parsedExpression; + } + return addInterceptor(parsedExpression, interceptorFn); + + case 'function': + return addInterceptor(exp, interceptorFn); + + default: + return addInterceptor(noop, interceptorFn); + } + }; + + function collectExpressionInputs(inputs, list) { + for (var i = 0, ii = inputs.length; i < ii; i++) { + var input = inputs[i]; + if (!input.constant) { + if (input.inputs) { + collectExpressionInputs(input.inputs, list); + } else if (list.indexOf(input) === -1) { // TODO(perf) can we do better? + list.push(input); + } + } + } + + return list; + } + + function expressionInputDirtyCheck(newValue, oldValueOfValue) { + + if (newValue == null || oldValueOfValue == null) { // null/undefined + return newValue === oldValueOfValue; + } + + if (typeof newValue === 'object') { + + // attempt to convert the value to a primitive type + // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can + // be cheaply dirty-checked + newValue = getValueOf(newValue); + + if (typeof newValue === 'object') { + // objects/arrays are not supported - deep-watching them would be too expensive + return false; + } + + // fall-through to the primitive equality check + } + + //Primitive or NaN + return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue); + } + + function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression) { + var inputExpressions = parsedExpression.$$inputs || + (parsedExpression.$$inputs = collectExpressionInputs(parsedExpression.inputs, [])); + + var lastResult; + + if (inputExpressions.length === 1) { + var oldInputValue = expressionInputDirtyCheck; // init to something unique so that equals check fails + inputExpressions = inputExpressions[0]; + return scope.$watch(function expressionInputWatch(scope) { + var newInputValue = inputExpressions(scope); + if (!expressionInputDirtyCheck(newInputValue, oldInputValue)) { + lastResult = parsedExpression(scope); + oldInputValue = newInputValue && getValueOf(newInputValue); + } + return lastResult; + }, listener, objectEquality); + } + + var oldInputValueOfValues = []; + for (var i = 0, ii = inputExpressions.length; i < ii; i++) { + oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails + } + + return scope.$watch(function expressionInputsWatch(scope) { + var changed = false; + + for (var i = 0, ii = inputExpressions.length; i < ii; i++) { + var newInputValue = inputExpressions[i](scope); + if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) { + oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue); + } + } + + if (changed) { + lastResult = parsedExpression(scope); + } + + return lastResult; + }, listener, objectEquality); + } + + function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) { + var unwatch, lastValue; + return unwatch = scope.$watch(function oneTimeWatch(scope) { + return parsedExpression(scope); + }, function oneTimeListener(value, old, scope) { + lastValue = value; + if (isFunction(listener)) { + listener.apply(this, arguments); + } + if (isDefined(value)) { + scope.$$postDigest(function() { + if (isDefined(lastValue)) { + unwatch(); + } + }); + } + }, objectEquality); + } + + function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) { + var unwatch, lastValue; + return unwatch = scope.$watch(function oneTimeWatch(scope) { + return parsedExpression(scope); + }, function oneTimeListener(value, old, scope) { + lastValue = value; + if (isFunction(listener)) { + listener.call(this, value, old, scope); + } + if (isAllDefined(value)) { + scope.$$postDigest(function() { + if (isAllDefined(lastValue)) unwatch(); + }); + } + }, objectEquality); + + function isAllDefined(value) { + var allDefined = true; + forEach(value, function(val) { + if (!isDefined(val)) allDefined = false; + }); + return allDefined; + } + } + + function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) { + var unwatch; + return unwatch = scope.$watch(function constantWatch(scope) { + return parsedExpression(scope); + }, function constantListener(value, old, scope) { + if (isFunction(listener)) { + listener.apply(this, arguments); + } + unwatch(); + }, objectEquality); + } + + function addInterceptor(parsedExpression, interceptorFn) { + if (!interceptorFn) return parsedExpression; + var watchDelegate = parsedExpression.$$watchDelegate; + + var regularWatch = + watchDelegate !== oneTimeLiteralWatchDelegate && + watchDelegate !== oneTimeWatchDelegate; + + var fn = regularWatch ? function regularInterceptedExpression(scope, locals) { + var value = parsedExpression(scope, locals); + return interceptorFn(value, scope, locals); + } : function oneTimeInterceptedExpression(scope, locals) { + var value = parsedExpression(scope, locals); + var result = interceptorFn(value, scope, locals); + // we only return the interceptor's result if the + // initial value is defined (for bind-once) + return isDefined(value) ? result : value; + }; + + // Propagate $$watchDelegates other then inputsWatchDelegate + if (parsedExpression.$$watchDelegate && + parsedExpression.$$watchDelegate !== inputsWatchDelegate) { + fn.$$watchDelegate = parsedExpression.$$watchDelegate; + } else if (!interceptorFn.$stateful) { + // If there is an interceptor, but no watchDelegate then treat the interceptor like + // we treat filters - it is assumed to be a pure function unless flagged with $stateful + fn.$$watchDelegate = inputsWatchDelegate; + fn.inputs = [parsedExpression]; + } + + return fn; + } + }]; +} + +/** + * @ngdoc service + * @name $q + * @requires $rootScope + * + * @description + * A service that helps you run functions asynchronously, and use their return values (or exceptions) + * when they are done processing. + * + * This is an implementation of promises/deferred objects inspired by + * [Kris Kowal's Q](https://github.com/kriskowal/q). + * + * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred + * implementations, and the other which resembles ES6 promises to some degree. + * + * # $q constructor + * + * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver` + * function as the first argument. This is similar to the native Promise implementation from ES6 Harmony, + * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). + * + * While the constructor-style use is supported, not all of the supporting methods from ES6 Harmony promises are + * available yet. + * + * It can be used like so: + * + * ```js + * // for the purpose of this example let's assume that variables `$q` and `okToGreet` + * // are available in the current lexical scope (they could have been injected or passed in). + * + * function asyncGreet(name) { + * // perform some asynchronous operation, resolve or reject the promise when appropriate. + * return $q(function(resolve, reject) { + * setTimeout(function() { + * if (okToGreet(name)) { + * resolve('Hello, ' + name + '!'); + * } else { + * reject('Greeting ' + name + ' is not allowed.'); + * } + * }, 1000); + * }); + * } + * + * var promise = asyncGreet('Robin Hood'); + * promise.then(function(greeting) { + * alert('Success: ' + greeting); + * }, function(reason) { + * alert('Failed: ' + reason); + * }); + * ``` + * + * Note: progress/notify callbacks are not currently supported via the ES6-style interface. + * + * However, the more traditional CommonJS-style usage is still available, and documented below. + * + * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an + * interface for interacting with an object that represents the result of an action that is + * performed asynchronously, and may or may not be finished at any given point in time. + * + * From the perspective of dealing with error handling, deferred and promise APIs are to + * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming. + * + * ```js + * // for the purpose of this example let's assume that variables `$q` and `okToGreet` + * // are available in the current lexical scope (they could have been injected or passed in). + * + * function asyncGreet(name) { + * var deferred = $q.defer(); + * + * setTimeout(function() { + * deferred.notify('About to greet ' + name + '.'); + * + * if (okToGreet(name)) { + * deferred.resolve('Hello, ' + name + '!'); + * } else { + * deferred.reject('Greeting ' + name + ' is not allowed.'); + * } + * }, 1000); + * + * return deferred.promise; + * } + * + * var promise = asyncGreet('Robin Hood'); + * promise.then(function(greeting) { + * alert('Success: ' + greeting); + * }, function(reason) { + * alert('Failed: ' + reason); + * }, function(update) { + * alert('Got notification: ' + update); + * }); + * ``` + * + * At first it might not be obvious why this extra complexity is worth the trouble. The payoff + * comes in the way of guarantees that promise and deferred APIs make, see + * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md. + * + * Additionally the promise api allows for composition that is very hard to do with the + * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach. + * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the + * section on serial or parallel joining of promises. + * + * # The Deferred API + * + * A new instance of deferred is constructed by calling `$q.defer()`. + * + * The purpose of the deferred object is to expose the associated Promise instance as well as APIs + * that can be used for signaling the successful or unsuccessful completion, as well as the status + * of the task. + * + * **Methods** + * + * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection + * constructed via `$q.reject`, the promise will be rejected instead. + * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to + * resolving it with a rejection constructed via `$q.reject`. + * - `notify(value)` - provides updates on the status of the promise's execution. This may be called + * multiple times before the promise is either resolved or rejected. + * + * **Properties** + * + * - promise – `{Promise}` – promise object associated with this deferred. + * + * + * # The Promise API + * + * A new promise instance is created when a deferred instance is created and can be retrieved by + * calling `deferred.promise`. + * + * The purpose of the promise object is to allow for interested parties to get access to the result + * of the deferred task when it completes. + * + * **Methods** + * + * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or + * will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously + * as soon as the result is available. The callbacks are called with a single argument: the result + * or rejection reason. Additionally, the notify callback may be called zero or more times to + * provide a progress indication, before the promise is resolved or rejected. + * + * This method *returns a new promise* which is resolved or rejected via the return value of the + * `successCallback`, `errorCallback`. It also notifies via the return value of the + * `notifyCallback` method. The promise cannot be resolved or rejected from the notifyCallback + * method. + * + * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)` + * + * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise, + * but to do so without modifying the final value. This is useful to release resources or do some + * clean-up that needs to be done whether the promise was rejected or resolved. See the [full + * specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for + * more information. + * + * # Chaining promises + * + * Because calling the `then` method of a promise returns a new derived promise, it is easily + * possible to create a chain of promises: + * + * ```js + * promiseB = promiseA.then(function(result) { + * return result + 1; + * }); + * + * // promiseB will be resolved immediately after promiseA is resolved and its value + * // will be the result of promiseA incremented by 1 + * ``` + * + * It is possible to create chains of any length and since a promise can be resolved with another + * promise (which will defer its resolution further), it is possible to pause/defer resolution of + * the promises at any point in the chain. This makes it possible to implement powerful APIs like + * $http's response interceptors. + * + * + * # Differences between Kris Kowal's Q and $q + * + * There are two main differences: + * + * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation + * mechanism in angular, which means faster propagation of resolution or rejection into your + * models and avoiding unnecessary browser repaints, which would result in flickering UI. + * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains + * all the important functionality needed for common async tasks. + * + * # Testing + * + * ```js + * it('should simulate promise', inject(function($q, $rootScope) { + * var deferred = $q.defer(); + * var promise = deferred.promise; + * var resolvedValue; + * + * promise.then(function(value) { resolvedValue = value; }); + * expect(resolvedValue).toBeUndefined(); + * + * // Simulate resolving of promise + * deferred.resolve(123); + * // Note that the 'then' function does not get called synchronously. + * // This is because we want the promise API to always be async, whether or not + * // it got called synchronously or asynchronously. + * expect(resolvedValue).toBeUndefined(); + * + * // Propagate promise resolution to 'then' functions using $apply(). + * $rootScope.$apply(); + * expect(resolvedValue).toEqual(123); + * })); + * ``` + * + * @param {function(function, function)} resolver Function which is responsible for resolving or + * rejecting the newly created promise. The first parameter is a function which resolves the + * promise, the second parameter is a function which rejects the promise. + * + * @returns {Promise} The newly created promise. + */ +function $QProvider() { + + this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) { + return qFactory(function(callback) { + $rootScope.$evalAsync(callback); + }, $exceptionHandler); + }]; +} + +function $$QProvider() { + this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) { + return qFactory(function(callback) { + $browser.defer(callback); + }, $exceptionHandler); + }]; +} + +/** + * Constructs a promise manager. + * + * @param {function(function)} nextTick Function for executing functions in the next turn. + * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for + * debugging purposes. + * @returns {object} Promise manager. + */ +function qFactory(nextTick, exceptionHandler) { + var $qMinErr = minErr('$q', TypeError); + function callOnce(self, resolveFn, rejectFn) { + var called = false; + function wrap(fn) { + return function(value) { + if (called) return; + called = true; + fn.call(self, value); + }; + } + + return [wrap(resolveFn), wrap(rejectFn)]; + } + + /** + * @ngdoc method + * @name ng.$q#defer + * @kind function + * + * @description + * Creates a `Deferred` object which represents a task which will finish in the future. + * + * @returns {Deferred} Returns a new instance of deferred. + */ + var defer = function() { + return new Deferred(); + }; + + function Promise() { + this.$$state = { status: 0 }; + } + + Promise.prototype = { + then: function(onFulfilled, onRejected, progressBack) { + var result = new Deferred(); + + this.$$state.pending = this.$$state.pending || []; + this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]); + if (this.$$state.status > 0) scheduleProcessQueue(this.$$state); + + return result.promise; + }, + + "catch": function(callback) { + return this.then(null, callback); + }, + + "finally": function(callback, progressBack) { + return this.then(function(value) { + return handleCallback(value, true, callback); + }, function(error) { + return handleCallback(error, false, callback); + }, progressBack); + } + }; + + //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native + function simpleBind(context, fn) { + return function(value) { + fn.call(context, value); + }; + } + + function processQueue(state) { + var fn, promise, pending; + + pending = state.pending; + state.processScheduled = false; + state.pending = undefined; + for (var i = 0, ii = pending.length; i < ii; ++i) { + promise = pending[i][0]; + fn = pending[i][state.status]; + try { + if (isFunction(fn)) { + promise.resolve(fn(state.value)); + } else if (state.status === 1) { + promise.resolve(state.value); + } else { + promise.reject(state.value); + } + } catch (e) { + promise.reject(e); + exceptionHandler(e); + } + } + } + + function scheduleProcessQueue(state) { + if (state.processScheduled || !state.pending) return; + state.processScheduled = true; + nextTick(function() { processQueue(state); }); + } + + function Deferred() { + this.promise = new Promise(); + //Necessary to support unbound execution :/ + this.resolve = simpleBind(this, this.resolve); + this.reject = simpleBind(this, this.reject); + this.notify = simpleBind(this, this.notify); + } + + Deferred.prototype = { + resolve: function(val) { + if (this.promise.$$state.status) return; + if (val === this.promise) { + this.$$reject($qMinErr( + 'qcycle', + "Expected promise to be resolved with value other than itself '{0}'", + val)); + } else { + this.$$resolve(val); + } + + }, + + $$resolve: function(val) { + var then, fns; + + fns = callOnce(this, this.$$resolve, this.$$reject); + try { + if ((isObject(val) || isFunction(val))) then = val && val.then; + if (isFunction(then)) { + this.promise.$$state.status = -1; + then.call(val, fns[0], fns[1], this.notify); + } else { + this.promise.$$state.value = val; + this.promise.$$state.status = 1; + scheduleProcessQueue(this.promise.$$state); + } + } catch (e) { + fns[1](e); + exceptionHandler(e); + } + }, + + reject: function(reason) { + if (this.promise.$$state.status) return; + this.$$reject(reason); + }, + + $$reject: function(reason) { + this.promise.$$state.value = reason; + this.promise.$$state.status = 2; + scheduleProcessQueue(this.promise.$$state); + }, + + notify: function(progress) { + var callbacks = this.promise.$$state.pending; + + if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) { + nextTick(function() { + var callback, result; + for (var i = 0, ii = callbacks.length; i < ii; i++) { + result = callbacks[i][0]; + callback = callbacks[i][3]; + try { + result.notify(isFunction(callback) ? callback(progress) : progress); + } catch (e) { + exceptionHandler(e); + } + } + }); + } + } + }; + + /** + * @ngdoc method + * @name $q#reject + * @kind function + * + * @description + * Creates a promise that is resolved as rejected with the specified `reason`. This api should be + * used to forward rejection in a chain of promises. If you are dealing with the last promise in + * a promise chain, you don't need to worry about it. + * + * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of + * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via + * a promise error callback and you want to forward the error to the promise derived from the + * current promise, you have to "rethrow" the error by returning a rejection constructed via + * `reject`. + * + * ```js + * promiseB = promiseA.then(function(result) { + * // success: do something and resolve promiseB + * // with the old or a new result + * return result; + * }, function(reason) { + * // error: handle the error if possible and + * // resolve promiseB with newPromiseOrValue, + * // otherwise forward the rejection to promiseB + * if (canHandle(reason)) { + * // handle the error and recover + * return newPromiseOrValue; + * } + * return $q.reject(reason); + * }); + * ``` + * + * @param {*} reason Constant, message, exception or an object representing the rejection reason. + * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`. + */ + var reject = function(reason) { + var result = new Deferred(); + result.reject(reason); + return result.promise; + }; + + var makePromise = function makePromise(value, resolved) { + var result = new Deferred(); + if (resolved) { + result.resolve(value); + } else { + result.reject(value); + } + return result.promise; + }; + + var handleCallback = function handleCallback(value, isResolved, callback) { + var callbackOutput = null; + try { + if (isFunction(callback)) callbackOutput = callback(); + } catch (e) { + return makePromise(e, false); + } + if (isPromiseLike(callbackOutput)) { + return callbackOutput.then(function() { + return makePromise(value, isResolved); + }, function(error) { + return makePromise(error, false); + }); + } else { + return makePromise(value, isResolved); + } + }; + + /** + * @ngdoc method + * @name $q#when + * @kind function + * + * @description + * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. + * This is useful when you are dealing with an object that might or might not be a promise, or if + * the promise comes from a source that can't be trusted. + * + * @param {*} value Value or a promise + * @returns {Promise} Returns a promise of the passed value or promise + */ + + + var when = function(value, callback, errback, progressBack) { + var result = new Deferred(); + result.resolve(value); + return result.promise.then(callback, errback, progressBack); + }; + + /** + * @ngdoc method + * @name $q#all + * @kind function + * + * @description + * Combines multiple promises into a single promise that is resolved when all of the input + * promises are resolved. + * + * @param {Array.|Object.} promises An array or hash of promises. + * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values, + * each value corresponding to the promise at the same index/key in the `promises` array/hash. + * If any of the promises is resolved with a rejection, this resulting promise will be rejected + * with the same rejection value. + */ + + function all(promises) { + var deferred = new Deferred(), + counter = 0, + results = isArray(promises) ? [] : {}; + + forEach(promises, function(promise, key) { + counter++; + when(promise).then(function(value) { + if (results.hasOwnProperty(key)) return; + results[key] = value; + if (!(--counter)) deferred.resolve(results); + }, function(reason) { + if (results.hasOwnProperty(key)) return; + deferred.reject(reason); + }); + }); + + if (counter === 0) { + deferred.resolve(results); + } + + return deferred.promise; + } + + var $Q = function Q(resolver) { + if (!isFunction(resolver)) { + throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver); + } + + if (!(this instanceof Q)) { + // More useful when $Q is the Promise itself. + return new Q(resolver); + } + + var deferred = new Deferred(); + + function resolveFn(value) { + deferred.resolve(value); + } + + function rejectFn(reason) { + deferred.reject(reason); + } + + resolver(resolveFn, rejectFn); + + return deferred.promise; + }; + + $Q.defer = defer; + $Q.reject = reject; + $Q.when = when; + $Q.all = all; + + return $Q; +} + +function $$RAFProvider() { //rAF + this.$get = ['$window', '$timeout', function($window, $timeout) { + var requestAnimationFrame = $window.requestAnimationFrame || + $window.webkitRequestAnimationFrame; + + var cancelAnimationFrame = $window.cancelAnimationFrame || + $window.webkitCancelAnimationFrame || + $window.webkitCancelRequestAnimationFrame; + + var rafSupported = !!requestAnimationFrame; + var raf = rafSupported + ? function(fn) { + var id = requestAnimationFrame(fn); + return function() { + cancelAnimationFrame(id); + }; + } + : function(fn) { + var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666 + return function() { + $timeout.cancel(timer); + }; + }; + + raf.supported = rafSupported; + + return raf; + }]; +} + +/** + * DESIGN NOTES + * + * The design decisions behind the scope are heavily favored for speed and memory consumption. + * + * The typical use of scope is to watch the expressions, which most of the time return the same + * value as last time so we optimize the operation. + * + * Closures construction is expensive in terms of speed as well as memory: + * - No closures, instead use prototypical inheritance for API + * - Internal state needs to be stored on scope directly, which means that private state is + * exposed as $$____ properties + * + * Loop operations are optimized by using while(count--) { ... } + * - this means that in order to keep the same order of execution as addition we have to add + * items to the array at the beginning (unshift) instead of at the end (push) + * + * Child scopes are created and removed often + * - Using an array would be slow since inserts in middle are expensive so we use linked list + * + * There are few watches then a lot of observers. This is why you don't want the observer to be + * implemented in the same way as watch. Watch requires return of initialization function which + * are expensive to construct. + */ + + +/** + * @ngdoc provider + * @name $rootScopeProvider + * @description + * + * Provider for the $rootScope service. + */ + +/** + * @ngdoc method + * @name $rootScopeProvider#digestTtl + * @description + * + * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and + * assuming that the model is unstable. + * + * The current default is 10 iterations. + * + * In complex applications it's possible that the dependencies between `$watch`s will result in + * several digest iterations. However if an application needs more than the default 10 digest + * iterations for its model to stabilize then you should investigate what is causing the model to + * continuously change during the digest. + * + * Increasing the TTL could have performance implications, so you should not change it without + * proper justification. + * + * @param {number} limit The number of digest iterations. + */ + + +/** + * @ngdoc service + * @name $rootScope + * @description + * + * Every application has a single root {@link ng.$rootScope.Scope scope}. + * All other scopes are descendant scopes of the root scope. Scopes provide separation + * between the model and the view, via a mechanism for watching the model for changes. + * They also provide an event emission/broadcast and subscription facility. See the + * {@link guide/scope developer guide on scopes}. + */ +function $RootScopeProvider() { + var TTL = 10; + var $rootScopeMinErr = minErr('$rootScope'); + var lastDirtyWatch = null; + var applyAsyncId = null; + + this.digestTtl = function(value) { + if (arguments.length) { + TTL = value; + } + return TTL; + }; + + this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser', + function($injector, $exceptionHandler, $parse, $browser) { + + /** + * @ngdoc type + * @name $rootScope.Scope + * + * @description + * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the + * {@link auto.$injector $injector}. Child scopes are created using the + * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when + * compiled HTML template is executed.) + * + * Here is a simple scope snippet to show how you can interact with the scope. + * ```html + * + * ``` + * + * # Inheritance + * A scope can inherit from a parent scope, as in this example: + * ```js + var parent = $rootScope; + var child = parent.$new(); + + parent.salutation = "Hello"; + expect(child.salutation).toEqual('Hello'); + + child.salutation = "Welcome"; + expect(child.salutation).toEqual('Welcome'); + expect(parent.salutation).toEqual('Hello'); + * ``` + * + * When interacting with `Scope` in tests, additional helper methods are available on the + * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional + * details. + * + * + * @param {Object.=} providers Map of service factory which need to be + * provided for the current scope. Defaults to {@link ng}. + * @param {Object.=} instanceCache Provides pre-instantiated services which should + * append/override services provided by `providers`. This is handy + * when unit-testing and having the need to override a default + * service. + * @returns {Object} Newly created scope. + * + */ + function Scope() { + this.$id = nextUid(); + this.$$phase = this.$parent = this.$$watchers = + this.$$nextSibling = this.$$prevSibling = + this.$$childHead = this.$$childTail = null; + this.$root = this; + this.$$destroyed = false; + this.$$listeners = {}; + this.$$listenerCount = {}; + this.$$isolateBindings = null; + } + + /** + * @ngdoc property + * @name $rootScope.Scope#$id + * + * @description + * Unique scope ID (monotonically increasing) useful for debugging. + */ + + /** + * @ngdoc property + * @name $rootScope.Scope#$parent + * + * @description + * Reference to the parent scope. + */ + + /** + * @ngdoc property + * @name $rootScope.Scope#$root + * + * @description + * Reference to the root scope. + */ + + Scope.prototype = { + constructor: Scope, + /** + * @ngdoc method + * @name $rootScope.Scope#$new + * @kind function + * + * @description + * Creates a new child {@link ng.$rootScope.Scope scope}. + * + * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event. + * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}. + * + * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is + * desired for the scope and its child scopes to be permanently detached from the parent and + * thus stop participating in model change detection and listener notification by invoking. + * + * @param {boolean} isolate If true, then the scope does not prototypically inherit from the + * parent scope. The scope is isolated, as it can not see parent scope properties. + * When creating widgets, it is useful for the widget to not accidentally read parent + * state. + * + * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent` + * of the newly created scope. Defaults to `this` scope if not provided. + * This is used when creating a transclude scope to correctly place it + * in the scope hierarchy while maintaining the correct prototypical + * inheritance. + * + * @returns {Object} The newly created child scope. + * + */ + $new: function(isolate, parent) { + var child; + + parent = parent || this; + + if (isolate) { + child = new Scope(); + child.$root = this.$root; + } else { + // Only create a child scope class if somebody asks for one, + // but cache it to allow the VM to optimize lookups. + if (!this.$$ChildScope) { + this.$$ChildScope = function ChildScope() { + this.$$watchers = this.$$nextSibling = + this.$$childHead = this.$$childTail = null; + this.$$listeners = {}; + this.$$listenerCount = {}; + this.$id = nextUid(); + this.$$ChildScope = null; + }; + this.$$ChildScope.prototype = this; + } + child = new this.$$ChildScope(); + } + child.$parent = parent; + child.$$prevSibling = parent.$$childTail; + if (parent.$$childHead) { + parent.$$childTail.$$nextSibling = child; + parent.$$childTail = child; + } else { + parent.$$childHead = parent.$$childTail = child; + } + + // When the new scope is not isolated or we inherit from `this`, and + // the parent scope is destroyed, the property `$$destroyed` is inherited + // prototypically. In all other cases, this property needs to be set + // when the parent scope is destroyed. + // The listener needs to be added after the parent is set + if (isolate || parent != this) child.$on('$destroy', destroyChild); + + return child; + + function destroyChild() { + child.$$destroyed = true; + } + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$watch + * @kind function + * + * @description + * Registers a `listener` callback to be executed whenever the `watchExpression` changes. + * + * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest + * $digest()} and should return the value that will be watched. (Since + * {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the + * `watchExpression` can execute multiple times per + * {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.) + * - The `listener` is called only when the value from the current `watchExpression` and the + * previous call to `watchExpression` are not equal (with the exception of the initial run, + * see below). Inequality is determined according to reference inequality, + * [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators) + * via the `!==` Javascript operator, unless `objectEquality == true` + * (see next point) + * - When `objectEquality == true`, inequality of the `watchExpression` is determined + * according to the {@link angular.equals} function. To save the value of the object for + * later comparison, the {@link angular.copy} function is used. This therefore means that + * watching complex objects will have adverse memory and performance implications. + * - The watch `listener` may change the model, which may trigger other `listener`s to fire. + * This is achieved by rerunning the watchers until no changes are detected. The rerun + * iteration limit is 10 to prevent an infinite loop deadlock. + * + * + * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called, + * you can register a `watchExpression` function with no `listener`. (Since `watchExpression` + * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a + * change is detected, be prepared for multiple calls to your listener.) + * + * After a watcher is registered with the scope, the `listener` fn is called asynchronously + * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the + * watcher. In rare cases, this is undesirable because the listener is called when the result + * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you + * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the + * listener was called due to initialization. + * + * + * + * # Example + * ```js + // let's assume that scope was dependency injected as the $rootScope + var scope = $rootScope; + scope.name = 'misko'; + scope.counter = 0; + + expect(scope.counter).toEqual(0); + scope.$watch('name', function(newValue, oldValue) { + scope.counter = scope.counter + 1; + }); + expect(scope.counter).toEqual(0); + + scope.$digest(); + // the listener is always called during the first $digest loop after it was registered + expect(scope.counter).toEqual(1); + + scope.$digest(); + // but now it will not be called unless the value changes + expect(scope.counter).toEqual(1); + + scope.name = 'adam'; + scope.$digest(); + expect(scope.counter).toEqual(2); + + + + // Using a function as a watchExpression + var food; + scope.foodCounter = 0; + expect(scope.foodCounter).toEqual(0); + scope.$watch( + // This function returns the value being watched. It is called for each turn of the $digest loop + function() { return food; }, + // This is the change listener, called when the value returned from the above function changes + function(newValue, oldValue) { + if ( newValue !== oldValue ) { + // Only increment the counter if the value changed + scope.foodCounter = scope.foodCounter + 1; + } + } + ); + // No digest has been run so the counter will be zero + expect(scope.foodCounter).toEqual(0); + + // Run the digest but since food has not changed count will still be zero + scope.$digest(); + expect(scope.foodCounter).toEqual(0); + + // Update food and run digest. Now the counter will increment + food = 'cheeseburger'; + scope.$digest(); + expect(scope.foodCounter).toEqual(1); + + * ``` + * + * + * + * @param {(function()|string)} watchExpression Expression that is evaluated on each + * {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers + * a call to the `listener`. + * + * - `string`: Evaluated as {@link guide/expression expression} + * - `function(scope)`: called with current `scope` as a parameter. + * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value + * of `watchExpression` changes. + * + * - `newVal` contains the current value of the `watchExpression` + * - `oldVal` contains the previous value of the `watchExpression` + * - `scope` refers to the current scope + * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of + * comparing for reference equality. + * @returns {function()} Returns a deregistration function for this listener. + */ + $watch: function(watchExp, listener, objectEquality) { + var get = $parse(watchExp); + + if (get.$$watchDelegate) { + return get.$$watchDelegate(this, listener, objectEquality, get); + } + var scope = this, + array = scope.$$watchers, + watcher = { + fn: listener, + last: initWatchVal, + get: get, + exp: watchExp, + eq: !!objectEquality + }; + + lastDirtyWatch = null; + + if (!isFunction(listener)) { + watcher.fn = noop; + } + + if (!array) { + array = scope.$$watchers = []; + } + // we use unshift since we use a while loop in $digest for speed. + // the while loop reads in reverse order. + array.unshift(watcher); + + return function deregisterWatch() { + arrayRemove(array, watcher); + lastDirtyWatch = null; + }; + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$watchGroup + * @kind function + * + * @description + * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`. + * If any one expression in the collection changes the `listener` is executed. + * + * - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every + * call to $digest() to see if any items changes. + * - The `listener` is called whenever any expression in the `watchExpressions` array changes. + * + * @param {Array.} watchExpressions Array of expressions that will be individually + * watched using {@link ng.$rootScope.Scope#$watch $watch()} + * + * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any + * expression in `watchExpressions` changes + * The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching + * those of `watchExpression` + * and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching + * those of `watchExpression` + * The `scope` refers to the current scope. + * @returns {function()} Returns a de-registration function for all listeners. + */ + $watchGroup: function(watchExpressions, listener) { + var oldValues = new Array(watchExpressions.length); + var newValues = new Array(watchExpressions.length); + var deregisterFns = []; + var self = this; + var changeReactionScheduled = false; + var firstRun = true; + + if (!watchExpressions.length) { + // No expressions means we call the listener ASAP + var shouldCall = true; + self.$evalAsync(function() { + if (shouldCall) listener(newValues, newValues, self); + }); + return function deregisterWatchGroup() { + shouldCall = false; + }; + } + + if (watchExpressions.length === 1) { + // Special case size of one + return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) { + newValues[0] = value; + oldValues[0] = oldValue; + listener(newValues, (value === oldValue) ? newValues : oldValues, scope); + }); + } + + forEach(watchExpressions, function(expr, i) { + var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) { + newValues[i] = value; + oldValues[i] = oldValue; + if (!changeReactionScheduled) { + changeReactionScheduled = true; + self.$evalAsync(watchGroupAction); + } + }); + deregisterFns.push(unwatchFn); + }); + + function watchGroupAction() { + changeReactionScheduled = false; + + if (firstRun) { + firstRun = false; + listener(newValues, newValues, self); + } else { + listener(newValues, oldValues, self); + } + } + + return function deregisterWatchGroup() { + while (deregisterFns.length) { + deregisterFns.shift()(); + } + }; + }, + + + /** + * @ngdoc method + * @name $rootScope.Scope#$watchCollection + * @kind function + * + * @description + * Shallow watches the properties of an object and fires whenever any of the properties change + * (for arrays, this implies watching the array items; for object maps, this implies watching + * the properties). If a change is detected, the `listener` callback is fired. + * + * - The `obj` collection is observed via standard $watch operation and is examined on every + * call to $digest() to see if any items have been added, removed, or moved. + * - The `listener` is called whenever anything within the `obj` has changed. Examples include + * adding, removing, and moving items belonging to an object or array. + * + * + * # Example + * ```js + $scope.names = ['igor', 'matias', 'misko', 'james']; + $scope.dataCount = 4; + + $scope.$watchCollection('names', function(newNames, oldNames) { + $scope.dataCount = newNames.length; + }); + + expect($scope.dataCount).toEqual(4); + $scope.$digest(); + + //still at 4 ... no changes + expect($scope.dataCount).toEqual(4); + + $scope.names.pop(); + $scope.$digest(); + + //now there's been a change + expect($scope.dataCount).toEqual(3); + * ``` + * + * + * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The + * expression value should evaluate to an object or an array which is observed on each + * {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the + * collection will trigger a call to the `listener`. + * + * @param {function(newCollection, oldCollection, scope)} listener a callback function called + * when a change is detected. + * - The `newCollection` object is the newly modified data obtained from the `obj` expression + * - The `oldCollection` object is a copy of the former collection data. + * Due to performance considerations, the`oldCollection` value is computed only if the + * `listener` function declares two or more arguments. + * - The `scope` argument refers to the current scope. + * + * @returns {function()} Returns a de-registration function for this listener. When the + * de-registration function is executed, the internal watch operation is terminated. + */ + $watchCollection: function(obj, listener) { + $watchCollectionInterceptor.$stateful = true; + + var self = this; + // the current value, updated on each dirty-check run + var newValue; + // a shallow copy of the newValue from the last dirty-check run, + // updated to match newValue during dirty-check run + var oldValue; + // a shallow copy of the newValue from when the last change happened + var veryOldValue; + // only track veryOldValue if the listener is asking for it + var trackVeryOldValue = (listener.length > 1); + var changeDetected = 0; + var changeDetector = $parse(obj, $watchCollectionInterceptor); + var internalArray = []; + var internalObject = {}; + var initRun = true; + var oldLength = 0; + + function $watchCollectionInterceptor(_value) { + newValue = _value; + var newLength, key, bothNaN, newItem, oldItem; + + // If the new value is undefined, then return undefined as the watch may be a one-time watch + if (isUndefined(newValue)) return; + + if (!isObject(newValue)) { // if primitive + if (oldValue !== newValue) { + oldValue = newValue; + changeDetected++; + } + } else if (isArrayLike(newValue)) { + if (oldValue !== internalArray) { + // we are transitioning from something which was not an array into array. + oldValue = internalArray; + oldLength = oldValue.length = 0; + changeDetected++; + } + + newLength = newValue.length; + + if (oldLength !== newLength) { + // if lengths do not match we need to trigger change notification + changeDetected++; + oldValue.length = oldLength = newLength; + } + // copy the items to oldValue and look for changes. + for (var i = 0; i < newLength; i++) { + oldItem = oldValue[i]; + newItem = newValue[i]; + + bothNaN = (oldItem !== oldItem) && (newItem !== newItem); + if (!bothNaN && (oldItem !== newItem)) { + changeDetected++; + oldValue[i] = newItem; + } + } + } else { + if (oldValue !== internalObject) { + // we are transitioning from something which was not an object into object. + oldValue = internalObject = {}; + oldLength = 0; + changeDetected++; + } + // copy the items to oldValue and look for changes. + newLength = 0; + for (key in newValue) { + if (newValue.hasOwnProperty(key)) { + newLength++; + newItem = newValue[key]; + oldItem = oldValue[key]; + + if (key in oldValue) { + bothNaN = (oldItem !== oldItem) && (newItem !== newItem); + if (!bothNaN && (oldItem !== newItem)) { + changeDetected++; + oldValue[key] = newItem; + } + } else { + oldLength++; + oldValue[key] = newItem; + changeDetected++; + } + } + } + if (oldLength > newLength) { + // we used to have more keys, need to find them and destroy them. + changeDetected++; + for (key in oldValue) { + if (!newValue.hasOwnProperty(key)) { + oldLength--; + delete oldValue[key]; + } + } + } + } + return changeDetected; + } + + function $watchCollectionAction() { + if (initRun) { + initRun = false; + listener(newValue, newValue, self); + } else { + listener(newValue, veryOldValue, self); + } + + // make a copy for the next time a collection is changed + if (trackVeryOldValue) { + if (!isObject(newValue)) { + //primitive + veryOldValue = newValue; + } else if (isArrayLike(newValue)) { + veryOldValue = new Array(newValue.length); + for (var i = 0; i < newValue.length; i++) { + veryOldValue[i] = newValue[i]; + } + } else { // if object + veryOldValue = {}; + for (var key in newValue) { + if (hasOwnProperty.call(newValue, key)) { + veryOldValue[key] = newValue[key]; + } + } + } + } + } + + return this.$watch(changeDetector, $watchCollectionAction); + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$digest + * @kind function + * + * @description + * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and + * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change + * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers} + * until no more listeners are firing. This means that it is possible to get into an infinite + * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of + * iterations exceeds 10. + * + * Usually, you don't call `$digest()` directly in + * {@link ng.directive:ngController controllers} or in + * {@link ng.$compileProvider#directive directives}. + * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within + * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`. + * + * If you want to be notified whenever `$digest()` is called, + * you can register a `watchExpression` function with + * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`. + * + * In unit tests, you may need to call `$digest()` to simulate the scope life cycle. + * + * # Example + * ```js + var scope = ...; + scope.name = 'misko'; + scope.counter = 0; + + expect(scope.counter).toEqual(0); + scope.$watch('name', function(newValue, oldValue) { + scope.counter = scope.counter + 1; + }); + expect(scope.counter).toEqual(0); + + scope.$digest(); + // the listener is always called during the first $digest loop after it was registered + expect(scope.counter).toEqual(1); + + scope.$digest(); + // but now it will not be called unless the value changes + expect(scope.counter).toEqual(1); + + scope.name = 'adam'; + scope.$digest(); + expect(scope.counter).toEqual(2); + * ``` + * + */ + $digest: function() { + var watch, value, last, + watchers, + length, + dirty, ttl = TTL, + next, current, target = this, + watchLog = [], + logIdx, logMsg, asyncTask; + + beginPhase('$digest'); + // Check for changes to browser url that happened in sync before the call to $digest + $browser.$$checkUrlChange(); + + if (this === $rootScope && applyAsyncId !== null) { + // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then + // cancel the scheduled $apply and flush the queue of expressions to be evaluated. + $browser.defer.cancel(applyAsyncId); + flushApplyAsync(); + } + + lastDirtyWatch = null; + + do { // "while dirty" loop + dirty = false; + current = target; + + while (asyncQueue.length) { + try { + asyncTask = asyncQueue.shift(); + asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals); + } catch (e) { + $exceptionHandler(e); + } + lastDirtyWatch = null; + } + + traverseScopesLoop: + do { // "traverse the scopes" loop + if ((watchers = current.$$watchers)) { + // process our watches + length = watchers.length; + while (length--) { + try { + watch = watchers[length]; + // Most common watches are on primitives, in which case we can short + // circuit it with === operator, only when === fails do we use .equals + if (watch) { + if ((value = watch.get(current)) !== (last = watch.last) && + !(watch.eq + ? equals(value, last) + : (typeof value === 'number' && typeof last === 'number' + && isNaN(value) && isNaN(last)))) { + dirty = true; + lastDirtyWatch = watch; + watch.last = watch.eq ? copy(value, null) : value; + watch.fn(value, ((last === initWatchVal) ? value : last), current); + if (ttl < 5) { + logIdx = 4 - ttl; + if (!watchLog[logIdx]) watchLog[logIdx] = []; + watchLog[logIdx].push({ + msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp, + newVal: value, + oldVal: last + }); + } + } else if (watch === lastDirtyWatch) { + // If the most recently dirty watcher is now clean, short circuit since the remaining watchers + // have already been tested. + dirty = false; + break traverseScopesLoop; + } + } + } catch (e) { + $exceptionHandler(e); + } + } + } + + // Insanity Warning: scope depth-first traversal + // yes, this code is a bit crazy, but it works and we have tests to prove it! + // this piece should be kept in sync with the traversal in $broadcast + if (!(next = (current.$$childHead || + (current !== target && current.$$nextSibling)))) { + while (current !== target && !(next = current.$$nextSibling)) { + current = current.$parent; + } + } + } while ((current = next)); + + // `break traverseScopesLoop;` takes us to here + + if ((dirty || asyncQueue.length) && !(ttl--)) { + clearPhase(); + throw $rootScopeMinErr('infdig', + '{0} $digest() iterations reached. Aborting!\n' + + 'Watchers fired in the last 5 iterations: {1}', + TTL, watchLog); + } + + } while (dirty || asyncQueue.length); + + clearPhase(); + + while (postDigestQueue.length) { + try { + postDigestQueue.shift()(); + } catch (e) { + $exceptionHandler(e); + } + } + }, + + + /** + * @ngdoc event + * @name $rootScope.Scope#$destroy + * @eventType broadcast on scope being destroyed + * + * @description + * Broadcasted when a scope and its children are being destroyed. + * + * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to + * clean up DOM bindings before an element is removed from the DOM. + */ + + /** + * @ngdoc method + * @name $rootScope.Scope#$destroy + * @kind function + * + * @description + * Removes the current scope (and all of its children) from the parent scope. Removal implies + * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer + * propagate to the current scope and its children. Removal also implies that the current + * scope is eligible for garbage collection. + * + * The `$destroy()` is usually used by directives such as + * {@link ng.directive:ngRepeat ngRepeat} for managing the + * unrolling of the loop. + * + * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope. + * Application code can register a `$destroy` event handler that will give it a chance to + * perform any necessary cleanup. + * + * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to + * clean up DOM bindings before an element is removed from the DOM. + */ + $destroy: function() { + // we can't destroy the root scope or a scope that has been already destroyed + if (this.$$destroyed) return; + var parent = this.$parent; + + this.$broadcast('$destroy'); + this.$$destroyed = true; + if (this === $rootScope) return; + + for (var eventName in this.$$listenerCount) { + decrementListenerCount(this, this.$$listenerCount[eventName], eventName); + } + + // sever all the references to parent scopes (after this cleanup, the current scope should + // not be retained by any of our references and should be eligible for garbage collection) + if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling; + if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling; + if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling; + if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling; + + // Disable listeners, watchers and apply/digest methods + this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop; + this.$on = this.$watch = this.$watchGroup = function() { return noop; }; + this.$$listeners = {}; + + // All of the code below is bogus code that works around V8's memory leak via optimized code + // and inline caches. + // + // see: + // - https://code.google.com/p/v8/issues/detail?id=2073#c26 + // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909 + // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451 + + this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead = + this.$$childTail = this.$root = this.$$watchers = null; + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$eval + * @kind function + * + * @description + * Executes the `expression` on the current scope and returns the result. Any exceptions in + * the expression are propagated (uncaught). This is useful when evaluating Angular + * expressions. + * + * # Example + * ```js + var scope = ng.$rootScope.Scope(); + scope.a = 1; + scope.b = 2; + + expect(scope.$eval('a+b')).toEqual(3); + expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3); + * ``` + * + * @param {(string|function())=} expression An angular expression to be executed. + * + * - `string`: execute using the rules as defined in {@link guide/expression expression}. + * - `function(scope)`: execute the function with the current `scope` parameter. + * + * @param {(object)=} locals Local variables object, useful for overriding values in scope. + * @returns {*} The result of evaluating the expression. + */ + $eval: function(expr, locals) { + return $parse(expr)(this, locals); + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$evalAsync + * @kind function + * + * @description + * Executes the expression on the current scope at a later point in time. + * + * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only + * that: + * + * - it will execute after the function that scheduled the evaluation (preferably before DOM + * rendering). + * - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after + * `expression` execution. + * + * Any exceptions from the execution of the expression are forwarded to the + * {@link ng.$exceptionHandler $exceptionHandler} service. + * + * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle + * will be scheduled. However, it is encouraged to always call code that changes the model + * from within an `$apply` call. That includes code evaluated via `$evalAsync`. + * + * @param {(string|function())=} expression An angular expression to be executed. + * + * - `string`: execute using the rules as defined in {@link guide/expression expression}. + * - `function(scope)`: execute the function with the current `scope` parameter. + * + * @param {(object)=} locals Local variables object, useful for overriding values in scope. + */ + $evalAsync: function(expr, locals) { + // if we are outside of an $digest loop and this is the first time we are scheduling async + // task also schedule async auto-flush + if (!$rootScope.$$phase && !asyncQueue.length) { + $browser.defer(function() { + if (asyncQueue.length) { + $rootScope.$digest(); + } + }); + } + + asyncQueue.push({scope: this, expression: expr, locals: locals}); + }, + + $$postDigest: function(fn) { + postDigestQueue.push(fn); + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$apply + * @kind function + * + * @description + * `$apply()` is used to execute an expression in angular from outside of the angular + * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries). + * Because we are calling into the angular framework we need to perform proper scope life + * cycle of {@link ng.$exceptionHandler exception handling}, + * {@link ng.$rootScope.Scope#$digest executing watches}. + * + * ## Life cycle + * + * # Pseudo-Code of `$apply()` + * ```js + function $apply(expr) { + try { + return $eval(expr); + } catch (e) { + $exceptionHandler(e); + } finally { + $root.$digest(); + } + } + * ``` + * + * + * Scope's `$apply()` method transitions through the following stages: + * + * 1. The {@link guide/expression expression} is executed using the + * {@link ng.$rootScope.Scope#$eval $eval()} method. + * 2. Any exceptions from the execution of the expression are forwarded to the + * {@link ng.$exceptionHandler $exceptionHandler} service. + * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the + * expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method. + * + * + * @param {(string|function())=} exp An angular expression to be executed. + * + * - `string`: execute using the rules as defined in {@link guide/expression expression}. + * - `function(scope)`: execute the function with current `scope` parameter. + * + * @returns {*} The result of evaluating the expression. + */ + $apply: function(expr) { + try { + beginPhase('$apply'); + return this.$eval(expr); + } catch (e) { + $exceptionHandler(e); + } finally { + clearPhase(); + try { + $rootScope.$digest(); + } catch (e) { + $exceptionHandler(e); + throw e; + } + } + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$applyAsync + * @kind function + * + * @description + * Schedule the invocation of $apply to occur at a later time. The actual time difference + * varies across browsers, but is typically around ~10 milliseconds. + * + * This can be used to queue up multiple expressions which need to be evaluated in the same + * digest. + * + * @param {(string|function())=} exp An angular expression to be executed. + * + * - `string`: execute using the rules as defined in {@link guide/expression expression}. + * - `function(scope)`: execute the function with current `scope` parameter. + */ + $applyAsync: function(expr) { + var scope = this; + expr && applyAsyncQueue.push($applyAsyncExpression); + scheduleApplyAsync(); + + function $applyAsyncExpression() { + scope.$eval(expr); + } + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$on + * @kind function + * + * @description + * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for + * discussion of event life cycle. + * + * The event listener function format is: `function(event, args...)`. The `event` object + * passed into the listener has the following attributes: + * + * - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or + * `$broadcast`-ed. + * - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the + * event propagates through the scope hierarchy, this property is set to null. + * - `name` - `{string}`: name of the event. + * - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel + * further event propagation (available only for events that were `$emit`-ed). + * - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag + * to true. + * - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called. + * + * @param {string} name Event name to listen on. + * @param {function(event, ...args)} listener Function to call when the event is emitted. + * @returns {function()} Returns a deregistration function for this listener. + */ + $on: function(name, listener) { + var namedListeners = this.$$listeners[name]; + if (!namedListeners) { + this.$$listeners[name] = namedListeners = []; + } + namedListeners.push(listener); + + var current = this; + do { + if (!current.$$listenerCount[name]) { + current.$$listenerCount[name] = 0; + } + current.$$listenerCount[name]++; + } while ((current = current.$parent)); + + var self = this; + return function() { + var indexOfListener = namedListeners.indexOf(listener); + if (indexOfListener !== -1) { + namedListeners[indexOfListener] = null; + decrementListenerCount(self, 1, name); + } + }; + }, + + + /** + * @ngdoc method + * @name $rootScope.Scope#$emit + * @kind function + * + * @description + * Dispatches an event `name` upwards through the scope hierarchy notifying the + * registered {@link ng.$rootScope.Scope#$on} listeners. + * + * The event life cycle starts at the scope on which `$emit` was called. All + * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get + * notified. Afterwards, the event traverses upwards toward the root scope and calls all + * registered listeners along the way. The event will stop propagating if one of the listeners + * cancels it. + * + * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed + * onto the {@link ng.$exceptionHandler $exceptionHandler} service. + * + * @param {string} name Event name to emit. + * @param {...*} args Optional one or more arguments which will be passed onto the event listeners. + * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}). + */ + $emit: function(name, args) { + var empty = [], + namedListeners, + scope = this, + stopPropagation = false, + event = { + name: name, + targetScope: scope, + stopPropagation: function() {stopPropagation = true;}, + preventDefault: function() { + event.defaultPrevented = true; + }, + defaultPrevented: false + }, + listenerArgs = concat([event], arguments, 1), + i, length; + + do { + namedListeners = scope.$$listeners[name] || empty; + event.currentScope = scope; + for (i = 0, length = namedListeners.length; i < length; i++) { + + // if listeners were deregistered, defragment the array + if (!namedListeners[i]) { + namedListeners.splice(i, 1); + i--; + length--; + continue; + } + try { + //allow all listeners attached to the current scope to run + namedListeners[i].apply(null, listenerArgs); + } catch (e) { + $exceptionHandler(e); + } + } + //if any listener on the current scope stops propagation, prevent bubbling + if (stopPropagation) { + event.currentScope = null; + return event; + } + //traverse upwards + scope = scope.$parent; + } while (scope); + + event.currentScope = null; + + return event; + }, + + + /** + * @ngdoc method + * @name $rootScope.Scope#$broadcast + * @kind function + * + * @description + * Dispatches an event `name` downwards to all child scopes (and their children) notifying the + * registered {@link ng.$rootScope.Scope#$on} listeners. + * + * The event life cycle starts at the scope on which `$broadcast` was called. All + * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get + * notified. Afterwards, the event propagates to all direct and indirect scopes of the current + * scope and calls all registered listeners along the way. The event cannot be canceled. + * + * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed + * onto the {@link ng.$exceptionHandler $exceptionHandler} service. + * + * @param {string} name Event name to broadcast. + * @param {...*} args Optional one or more arguments which will be passed onto the event listeners. + * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on} + */ + $broadcast: function(name, args) { + var target = this, + current = target, + next = target, + event = { + name: name, + targetScope: target, + preventDefault: function() { + event.defaultPrevented = true; + }, + defaultPrevented: false + }; + + if (!target.$$listenerCount[name]) return event; + + var listenerArgs = concat([event], arguments, 1), + listeners, i, length; + + //down while you can, then up and next sibling or up and next sibling until back at root + while ((current = next)) { + event.currentScope = current; + listeners = current.$$listeners[name] || []; + for (i = 0, length = listeners.length; i < length; i++) { + // if listeners were deregistered, defragment the array + if (!listeners[i]) { + listeners.splice(i, 1); + i--; + length--; + continue; + } + + try { + listeners[i].apply(null, listenerArgs); + } catch (e) { + $exceptionHandler(e); + } + } + + // Insanity Warning: scope depth-first traversal + // yes, this code is a bit crazy, but it works and we have tests to prove it! + // this piece should be kept in sync with the traversal in $digest + // (though it differs due to having the extra check for $$listenerCount) + if (!(next = ((current.$$listenerCount[name] && current.$$childHead) || + (current !== target && current.$$nextSibling)))) { + while (current !== target && !(next = current.$$nextSibling)) { + current = current.$parent; + } + } + } + + event.currentScope = null; + return event; + } + }; + + var $rootScope = new Scope(); + + //The internal queues. Expose them on the $rootScope for debugging/testing purposes. + var asyncQueue = $rootScope.$$asyncQueue = []; + var postDigestQueue = $rootScope.$$postDigestQueue = []; + var applyAsyncQueue = $rootScope.$$applyAsyncQueue = []; + + return $rootScope; + + + function beginPhase(phase) { + if ($rootScope.$$phase) { + throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase); + } + + $rootScope.$$phase = phase; + } + + function clearPhase() { + $rootScope.$$phase = null; + } + + + function decrementListenerCount(current, count, name) { + do { + current.$$listenerCount[name] -= count; + + if (current.$$listenerCount[name] === 0) { + delete current.$$listenerCount[name]; + } + } while ((current = current.$parent)); + } + + /** + * function used as an initial value for watchers. + * because it's unique we can easily tell it apart from other values + */ + function initWatchVal() {} + + function flushApplyAsync() { + while (applyAsyncQueue.length) { + try { + applyAsyncQueue.shift()(); + } catch (e) { + $exceptionHandler(e); + } + } + applyAsyncId = null; + } + + function scheduleApplyAsync() { + if (applyAsyncId === null) { + applyAsyncId = $browser.defer(function() { + $rootScope.$apply(flushApplyAsync); + }); + } + } + }]; +} + +/** + * @description + * Private service to sanitize uris for links and images. Used by $compile and $sanitize. + */ +function $$SanitizeUriProvider() { + var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/, + imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/; + + /** + * @description + * Retrieves or overrides the default regular expression that is used for whitelisting of safe + * urls during a[href] sanitization. + * + * The sanitization is a security measure aimed at prevent XSS attacks via html links. + * + * Any url about to be assigned to a[href] via data-binding is first normalized and turned into + * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist` + * regular expression. If a match is found, the original url is written into the dom. Otherwise, + * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM. + * + * @param {RegExp=} regexp New regexp to whitelist urls with. + * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for + * chaining otherwise. + */ + this.aHrefSanitizationWhitelist = function(regexp) { + if (isDefined(regexp)) { + aHrefSanitizationWhitelist = regexp; + return this; + } + return aHrefSanitizationWhitelist; + }; + + + /** + * @description + * Retrieves or overrides the default regular expression that is used for whitelisting of safe + * urls during img[src] sanitization. + * + * The sanitization is a security measure aimed at prevent XSS attacks via html links. + * + * Any url about to be assigned to img[src] via data-binding is first normalized and turned into + * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist` + * regular expression. If a match is found, the original url is written into the dom. Otherwise, + * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM. + * + * @param {RegExp=} regexp New regexp to whitelist urls with. + * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for + * chaining otherwise. + */ + this.imgSrcSanitizationWhitelist = function(regexp) { + if (isDefined(regexp)) { + imgSrcSanitizationWhitelist = regexp; + return this; + } + return imgSrcSanitizationWhitelist; + }; + + this.$get = function() { + return function sanitizeUri(uri, isImage) { + var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist; + var normalizedVal; + normalizedVal = urlResolve(uri).href; + if (normalizedVal !== '' && !normalizedVal.match(regex)) { + return 'unsafe:' + normalizedVal; + } + return uri; + }; + }; +} + +var $sceMinErr = minErr('$sce'); + +var SCE_CONTEXTS = { + HTML: 'html', + CSS: 'css', + URL: 'url', + // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a + // url. (e.g. ng-include, script src, templateUrl) + RESOURCE_URL: 'resourceUrl', + JS: 'js' +}; + +// Helper functions follow. + +function adjustMatcher(matcher) { + if (matcher === 'self') { + return matcher; + } else if (isString(matcher)) { + // Strings match exactly except for 2 wildcards - '*' and '**'. + // '*' matches any character except those from the set ':/.?&'. + // '**' matches any character (like .* in a RegExp). + // More than 2 *'s raises an error as it's ill defined. + if (matcher.indexOf('***') > -1) { + throw $sceMinErr('iwcard', + 'Illegal sequence *** in string matcher. String: {0}', matcher); + } + matcher = escapeForRegexp(matcher). + replace('\\*\\*', '.*'). + replace('\\*', '[^:/.?&;]*'); + return new RegExp('^' + matcher + '$'); + } else if (isRegExp(matcher)) { + // The only other type of matcher allowed is a Regexp. + // Match entire URL / disallow partial matches. + // Flags are reset (i.e. no global, ignoreCase or multiline) + return new RegExp('^' + matcher.source + '$'); + } else { + throw $sceMinErr('imatcher', + 'Matchers may only be "self", string patterns or RegExp objects'); + } +} + + +function adjustMatchers(matchers) { + var adjustedMatchers = []; + if (isDefined(matchers)) { + forEach(matchers, function(matcher) { + adjustedMatchers.push(adjustMatcher(matcher)); + }); + } + return adjustedMatchers; +} + + +/** + * @ngdoc service + * @name $sceDelegate + * @kind function + * + * @description + * + * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict + * Contextual Escaping (SCE)} services to AngularJS. + * + * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of + * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS. This is + * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to + * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things + * work because `$sce` delegates to `$sceDelegate` for these operations. + * + * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service. + * + * The default instance of `$sceDelegate` should work out of the box with little pain. While you + * can override it completely to change the behavior of `$sce`, the common case would + * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting + * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as + * templates. Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist + * $sceDelegateProvider.resourceUrlWhitelist} and {@link + * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} + */ + +/** + * @ngdoc provider + * @name $sceDelegateProvider + * @description + * + * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate + * $sceDelegate} service. This allows one to get/set the whitelists and blacklists used to ensure + * that the URLs used for sourcing Angular templates are safe. Refer {@link + * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and + * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} + * + * For the general details about this service in Angular, read the main page for {@link ng.$sce + * Strict Contextual Escaping (SCE)}. + * + * **Example**: Consider the following case. + * + * - your app is hosted at url `http://myapp.example.com/` + * - but some of your templates are hosted on other domains you control such as + * `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc. + * - and you have an open redirect at `http://myapp.example.com/clickThru?...`. + * + * Here is what a secure configuration for this scenario might look like: + * + * ``` + * angular.module('myApp', []).config(function($sceDelegateProvider) { + * $sceDelegateProvider.resourceUrlWhitelist([ + * // Allow same origin resource loads. + * 'self', + * // Allow loading from our assets domain. Notice the difference between * and **. + * 'http://srv*.assets.example.com/**' + * ]); + * + * // The blacklist overrides the whitelist so the open redirect here is blocked. + * $sceDelegateProvider.resourceUrlBlacklist([ + * 'http://myapp.example.com/clickThru**' + * ]); + * }); + * ``` + */ + +function $SceDelegateProvider() { + this.SCE_CONTEXTS = SCE_CONTEXTS; + + // Resource URLs can also be trusted by policy. + var resourceUrlWhitelist = ['self'], + resourceUrlBlacklist = []; + + /** + * @ngdoc method + * @name $sceDelegateProvider#resourceUrlWhitelist + * @kind function + * + * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value + * provided. This must be an array or null. A snapshot of this array is used so further + * changes to the array are ignored. + * + * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items + * allowed in this array. + * + * Note: **an empty whitelist array will block all URLs**! + * + * @return {Array} the currently set whitelist array. + * + * The **default value** when no whitelist has been explicitly set is `['self']` allowing only + * same origin resource requests. + * + * @description + * Sets/Gets the whitelist of trusted resource URLs. + */ + this.resourceUrlWhitelist = function(value) { + if (arguments.length) { + resourceUrlWhitelist = adjustMatchers(value); + } + return resourceUrlWhitelist; + }; + + /** + * @ngdoc method + * @name $sceDelegateProvider#resourceUrlBlacklist + * @kind function + * + * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value + * provided. This must be an array or null. A snapshot of this array is used so further + * changes to the array are ignored. + * + * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items + * allowed in this array. + * + * The typical usage for the blacklist is to **block + * [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as + * these would otherwise be trusted but actually return content from the redirected domain. + * + * Finally, **the blacklist overrides the whitelist** and has the final say. + * + * @return {Array} the currently set blacklist array. + * + * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there + * is no blacklist.) + * + * @description + * Sets/Gets the blacklist of trusted resource URLs. + */ + + this.resourceUrlBlacklist = function(value) { + if (arguments.length) { + resourceUrlBlacklist = adjustMatchers(value); + } + return resourceUrlBlacklist; + }; + + this.$get = ['$injector', function($injector) { + + var htmlSanitizer = function htmlSanitizer(html) { + throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.'); + }; + + if ($injector.has('$sanitize')) { + htmlSanitizer = $injector.get('$sanitize'); + } + + + function matchUrl(matcher, parsedUrl) { + if (matcher === 'self') { + return urlIsSameOrigin(parsedUrl); + } else { + // definitely a regex. See adjustMatchers() + return !!matcher.exec(parsedUrl.href); + } + } + + function isResourceUrlAllowedByPolicy(url) { + var parsedUrl = urlResolve(url.toString()); + var i, n, allowed = false; + // Ensure that at least one item from the whitelist allows this url. + for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) { + if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) { + allowed = true; + break; + } + } + if (allowed) { + // Ensure that no item from the blacklist blocked this url. + for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) { + if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) { + allowed = false; + break; + } + } + } + return allowed; + } + + function generateHolderType(Base) { + var holderType = function TrustedValueHolderType(trustedValue) { + this.$$unwrapTrustedValue = function() { + return trustedValue; + }; + }; + if (Base) { + holderType.prototype = new Base(); + } + holderType.prototype.valueOf = function sceValueOf() { + return this.$$unwrapTrustedValue(); + }; + holderType.prototype.toString = function sceToString() { + return this.$$unwrapTrustedValue().toString(); + }; + return holderType; + } + + var trustedValueHolderBase = generateHolderType(), + byType = {}; + + byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase); + byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase); + byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase); + byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase); + byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]); + + /** + * @ngdoc method + * @name $sceDelegate#trustAs + * + * @description + * Returns an object that is trusted by angular for use in specified strict + * contextual escaping contexts (such as ng-bind-html, ng-include, any src + * attribute interpolation, any dom event binding attribute interpolation + * such as for onclick, etc.) that uses the provided value. + * See {@link ng.$sce $sce} for enabling strict contextual escaping. + * + * @param {string} type The kind of context in which this value is safe for use. e.g. url, + * resourceUrl, html, js and css. + * @param {*} value The value that that should be considered trusted/safe. + * @returns {*} A value that can be used to stand in for the provided `value` in places + * where Angular expects a $sce.trustAs() return value. + */ + function trustAs(type, trustedValue) { + var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null); + if (!Constructor) { + throw $sceMinErr('icontext', + 'Attempted to trust a value in invalid context. Context: {0}; Value: {1}', + type, trustedValue); + } + if (trustedValue === null || trustedValue === undefined || trustedValue === '') { + return trustedValue; + } + // All the current contexts in SCE_CONTEXTS happen to be strings. In order to avoid trusting + // mutable objects, we ensure here that the value passed in is actually a string. + if (typeof trustedValue !== 'string') { + throw $sceMinErr('itype', + 'Attempted to trust a non-string value in a content requiring a string: Context: {0}', + type); + } + return new Constructor(trustedValue); + } + + /** + * @ngdoc method + * @name $sceDelegate#valueOf + * + * @description + * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs + * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link + * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}. + * + * If the passed parameter is not a value that had been returned by {@link + * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is. + * + * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} + * call or anything else. + * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs + * `$sceDelegate.trustAs`} if `value` is the result of such a call. Otherwise, returns + * `value` unchanged. + */ + function valueOf(maybeTrusted) { + if (maybeTrusted instanceof trustedValueHolderBase) { + return maybeTrusted.$$unwrapTrustedValue(); + } else { + return maybeTrusted; + } + } + + /** + * @ngdoc method + * @name $sceDelegate#getTrusted + * + * @description + * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and + * returns the originally supplied value if the queried context type is a supertype of the + * created type. If this condition isn't satisfied, throws an exception. + * + * @param {string} type The kind of context in which this value is to be used. + * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs + * `$sceDelegate.trustAs`} call. + * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs + * `$sceDelegate.trustAs`} if valid in this context. Otherwise, throws an exception. + */ + function getTrusted(type, maybeTrusted) { + if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') { + return maybeTrusted; + } + var constructor = (byType.hasOwnProperty(type) ? byType[type] : null); + if (constructor && maybeTrusted instanceof constructor) { + return maybeTrusted.$$unwrapTrustedValue(); + } + // If we get here, then we may only take one of two actions. + // 1. sanitize the value for the requested type, or + // 2. throw an exception. + if (type === SCE_CONTEXTS.RESOURCE_URL) { + if (isResourceUrlAllowedByPolicy(maybeTrusted)) { + return maybeTrusted; + } else { + throw $sceMinErr('insecurl', + 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: {0}', + maybeTrusted.toString()); + } + } else if (type === SCE_CONTEXTS.HTML) { + return htmlSanitizer(maybeTrusted); + } + throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.'); + } + + return { trustAs: trustAs, + getTrusted: getTrusted, + valueOf: valueOf }; + }]; +} + + +/** + * @ngdoc provider + * @name $sceProvider + * @description + * + * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service. + * - enable/disable Strict Contextual Escaping (SCE) in a module + * - override the default implementation with a custom delegate + * + * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}. + */ + +/* jshint maxlen: false*/ + +/** + * @ngdoc service + * @name $sce + * @kind function + * + * @description + * + * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS. + * + * # Strict Contextual Escaping + * + * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain + * contexts to result in a value that is marked as safe to use for that context. One example of + * such a context is binding arbitrary html controlled by the user via `ng-bind-html`. We refer + * to these contexts as privileged or SCE contexts. + * + * As of version 1.2, Angular ships with SCE enabled by default. + * + * Note: When enabled (the default), IE<11 in quirks mode is not supported. In this mode, IE<11 allow + * one to execute arbitrary javascript by the use of the expression() syntax. Refer + * to learn more about them. + * You can ensure your document is in standards mode and not quirks mode by adding `` + * to the top of your HTML document. + * + * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for + * security vulnerabilities such as XSS, clickjacking, etc. a lot easier. + * + * Here's an example of a binding in a privileged context: + * + * ``` + * + *
    + * ``` + * + * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user. With SCE + * disabled, this application allows the user to render arbitrary HTML into the DIV. + * In a more realistic example, one may be rendering user comments, blog articles, etc. via + * bindings. (HTML is just one example of a context where rendering user controlled input creates + * security vulnerabilities.) + * + * For the case of HTML, you might use a library, either on the client side, or on the server side, + * to sanitize unsafe HTML before binding to the value and rendering it in the document. + * + * How would you ensure that every place that used these types of bindings was bound to a value that + * was sanitized by your library (or returned as safe for rendering by your server?) How can you + * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some + * properties/fields and forgot to update the binding to the sanitized value? + * + * To be secure by default, you want to ensure that any such bindings are disallowed unless you can + * determine that something explicitly says it's safe to use a value for binding in that + * context. You can then audit your code (a simple grep would do) to ensure that this is only done + * for those values that you can easily tell are safe - because they were received from your server, + * sanitized by your library, etc. You can organize your codebase to help with this - perhaps + * allowing only the files in a specific directory to do this. Ensuring that the internal API + * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task. + * + * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs} + * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to + * obtain values that will be accepted by SCE / privileged contexts. + * + * + * ## How does it work? + * + * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted + * $sce.getTrusted(context, value)} rather than to the value directly. Directives use {@link + * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the + * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals. + * + * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link + * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}. Here's the actual code (slightly + * simplified): + * + * ``` + * var ngBindHtmlDirective = ['$sce', function($sce) { + * return function(scope, element, attr) { + * scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) { + * element.html(value || ''); + * }); + * }; + * }]; + * ``` + * + * ## Impact on loading templates + * + * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as + * `templateUrl`'s specified by {@link guide/directive directives}. + * + * By default, Angular only loads templates from the same domain and protocol as the application + * document. This is done by calling {@link ng.$sce#getTrustedResourceUrl + * $sce.getTrustedResourceUrl} on the template URL. To load templates from other domains and/or + * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist + * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value. + * + * *Please note*: + * The browser's + * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest) + * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/) + * policy apply in addition to this and may further restrict whether the template is successfully + * loaded. This means that without the right CORS policy, loading templates from a different domain + * won't work on all browsers. Also, loading templates from `file://` URL does not work on some + * browsers. + * + * ## This feels like too much overhead + * + * It's important to remember that SCE only applies to interpolation expressions. + * + * If your expressions are constant literals, they're automatically trusted and you don't need to + * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g. + * `
    `) just works. + * + * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them + * through {@link ng.$sce#getTrusted $sce.getTrusted}. SCE doesn't play a role here. + * + * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load + * templates in `ng-include` from your application's domain without having to even know about SCE. + * It blocks loading templates from other domains or loading templates over http from an https + * served document. You can change these by setting your own custom {@link + * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link + * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs. + * + * This significantly reduces the overhead. It is far easier to pay the small overhead and have an + * application that's secure and can be audited to verify that with much more ease than bolting + * security onto an application later. + * + * + * ## What trusted context types are supported? + * + * | Context | Notes | + * |---------------------|----------------| + * | `$sce.HTML` | For HTML that's safe to source into the application. The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. If an unsafe value is encountered and the {@link ngSanitize $sanitize} module is present this will sanitize the value instead of throwing an error. | + * | `$sce.CSS` | For CSS that's safe to source into the application. Currently unused. Feel free to use it in your own directives. | + * | `$sce.URL` | For URLs that are safe to follow as links. Currently unused (`
    Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. | + * | `$sce.JS` | For JavaScript that is safe to execute in your application's context. Currently unused. Feel free to use it in your own directives. | + * + * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist}
    + * + * Each element in these arrays must be one of the following: + * + * - **'self'** + * - The special **string**, `'self'`, can be used to match against all URLs of the **same + * domain** as the application document using the **same protocol**. + * - **String** (except the special value `'self'`) + * - The string is matched against the full *normalized / absolute URL* of the resource + * being tested (substring matches are not good enough.) + * - There are exactly **two wildcard sequences** - `*` and `**`. All other characters + * match themselves. + * - `*`: matches zero or more occurrences of any character other than one of the following 6 + * characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'. It's a useful wildcard for use + * in a whitelist. + * - `**`: matches zero or more occurrences of *any* character. As such, it's not + * not appropriate to use in for a scheme, domain, etc. as it would match too much. (e.g. + * http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might + * not have been the intention.) Its usage at the very end of the path is ok. (e.g. + * http://foo.example.com/templates/**). + * - **RegExp** (*see caveat below*) + * - *Caveat*: While regular expressions are powerful and offer great flexibility, their syntax + * (and all the inevitable escaping) makes them *harder to maintain*. It's easy to + * accidentally introduce a bug when one updates a complex expression (imho, all regexes should + * have good test coverage.). For instance, the use of `.` in the regex is correct only in a + * small number of cases. A `.` character in the regex used when matching the scheme or a + * subdomain could be matched against a `:` or literal `.` that was likely not intended. It + * is highly recommended to use the string patterns and only fall back to regular expressions + * if they as a last resort. + * - The regular expression must be an instance of RegExp (i.e. not a string.) It is + * matched against the **entire** *normalized / absolute URL* of the resource being tested + * (even when the RegExp did not have the `^` and `$` codes.) In addition, any flags + * present on the RegExp (such as multiline, global, ignoreCase) are ignored. + * - If you are generating your JavaScript from some other templating engine (not + * recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)), + * remember to escape your regular expression (and be aware that you might need more than + * one level of escaping depending on your templating engine and the way you interpolated + * the value.) Do make use of your platform's escaping mechanism as it might be good + * enough before coding your own. e.g. Ruby has + * [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape) + * and Python has [re.escape](http://docs.python.org/library/re.html#re.escape). + * Javascript lacks a similar built in function for escaping. Take a look at Google + * Closure library's [goog.string.regExpEscape(s)]( + * http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962). + * + * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example. + * + * ## Show me an example using SCE. + * + * + * + *
    + *

    + * User comments
    + * By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when + * $sanitize is available. If $sanitize isn't available, this results in an error instead of an + * exploit. + *
    + *
    + * {{userComment.name}}: + * + *
    + *
    + *
    + *
    + *
    + * + * + * angular.module('mySceApp', ['ngSanitize']) + * .controller('AppController', ['$http', '$templateCache', '$sce', + * function($http, $templateCache, $sce) { + * var self = this; + * $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) { + * self.userComments = userComments; + * }); + * self.explicitlyTrustedHtml = $sce.trustAsHtml( + * 'Hover over this text.'); + * }]); + * + * + * + * [ + * { "name": "Alice", + * "htmlComment": + * "Is anyone reading this?" + * }, + * { "name": "Bob", + * "htmlComment": "Yes! Am I the only other one?" + * } + * ] + * + * + * + * describe('SCE doc demo', function() { + * it('should sanitize untrusted values', function() { + * expect(element.all(by.css('.htmlComment')).first().getInnerHtml()) + * .toBe('Is anyone reading this?'); + * }); + * + * it('should NOT sanitize explicitly trusted values', function() { + * expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe( + * 'Hover over this text.'); + * }); + * }); + * + *
    + * + * + * + * ## Can I disable SCE completely? + * + * Yes, you can. However, this is strongly discouraged. SCE gives you a lot of security benefits + * for little coding overhead. It will be much harder to take an SCE disabled application and + * either secure it on your own or enable SCE at a later stage. It might make sense to disable SCE + * for cases where you have a lot of existing code that was written before SCE was introduced and + * you're migrating them a module at a time. + * + * That said, here's how you can completely disable SCE: + * + * ``` + * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) { + * // Completely disable SCE. For demonstration purposes only! + * // Do not use in new projects. + * $sceProvider.enabled(false); + * }); + * ``` + * + */ +/* jshint maxlen: 100 */ + +function $SceProvider() { + var enabled = true; + + /** + * @ngdoc method + * @name $sceProvider#enabled + * @kind function + * + * @param {boolean=} value If provided, then enables/disables SCE. + * @return {boolean} true if SCE is enabled, false otherwise. + * + * @description + * Enables/disables SCE and returns the current value. + */ + this.enabled = function(value) { + if (arguments.length) { + enabled = !!value; + } + return enabled; + }; + + + /* Design notes on the default implementation for SCE. + * + * The API contract for the SCE delegate + * ------------------------------------- + * The SCE delegate object must provide the following 3 methods: + * + * - trustAs(contextEnum, value) + * This method is used to tell the SCE service that the provided value is OK to use in the + * contexts specified by contextEnum. It must return an object that will be accepted by + * getTrusted() for a compatible contextEnum and return this value. + * + * - valueOf(value) + * For values that were not produced by trustAs(), return them as is. For values that were + * produced by trustAs(), return the corresponding input value to trustAs. Basically, if + * trustAs is wrapping the given values into some type, this operation unwraps it when given + * such a value. + * + * - getTrusted(contextEnum, value) + * This function should return the a value that is safe to use in the context specified by + * contextEnum or throw and exception otherwise. + * + * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be + * opaque or wrapped in some holder object. That happens to be an implementation detail. For + * instance, an implementation could maintain a registry of all trusted objects by context. In + * such a case, trustAs() would return the same object that was passed in. getTrusted() would + * return the same object passed in if it was found in the registry under a compatible context or + * throw an exception otherwise. An implementation might only wrap values some of the time based + * on some criteria. getTrusted() might return a value and not throw an exception for special + * constants or objects even if not wrapped. All such implementations fulfill this contract. + * + * + * A note on the inheritance model for SCE contexts + * ------------------------------------------------ + * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types. This + * is purely an implementation details. + * + * The contract is simply this: + * + * getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value) + * will also succeed. + * + * Inheritance happens to capture this in a natural way. In some future, we + * may not use inheritance anymore. That is OK because no code outside of + * sce.js and sceSpecs.js would need to be aware of this detail. + */ + + this.$get = ['$parse', '$sceDelegate', function( + $parse, $sceDelegate) { + // Prereq: Ensure that we're not running in IE<11 quirks mode. In that mode, IE < 11 allow + // the "expression(javascript expression)" syntax which is insecure. + if (enabled && msie < 8) { + throw $sceMinErr('iequirks', + 'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' + + 'mode. You can fix this by adding the text to the top of your HTML ' + + 'document. See http://docs.angularjs.org/api/ng.$sce for more information.'); + } + + var sce = shallowCopy(SCE_CONTEXTS); + + /** + * @ngdoc method + * @name $sce#isEnabled + * @kind function + * + * @return {Boolean} true if SCE is enabled, false otherwise. If you want to set the value, you + * have to do it at module config time on {@link ng.$sceProvider $sceProvider}. + * + * @description + * Returns a boolean indicating if SCE is enabled. + */ + sce.isEnabled = function() { + return enabled; + }; + sce.trustAs = $sceDelegate.trustAs; + sce.getTrusted = $sceDelegate.getTrusted; + sce.valueOf = $sceDelegate.valueOf; + + if (!enabled) { + sce.trustAs = sce.getTrusted = function(type, value) { return value; }; + sce.valueOf = identity; + } + + /** + * @ngdoc method + * @name $sce#parseAs + * + * @description + * Converts Angular {@link guide/expression expression} into a function. This is like {@link + * ng.$parse $parse} and is identical when the expression is a literal constant. Otherwise, it + * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*, + * *result*)} + * + * @param {string} type The kind of SCE context in which this result will be used. + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + */ + sce.parseAs = function sceParseAs(type, expr) { + var parsed = $parse(expr); + if (parsed.literal && parsed.constant) { + return parsed; + } else { + return $parse(expr, function(value) { + return sce.getTrusted(type, value); + }); + } + }; + + /** + * @ngdoc method + * @name $sce#trustAs + * + * @description + * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}. As such, + * returns an object that is trusted by angular for use in specified strict contextual + * escaping contexts (such as ng-bind-html, ng-include, any src attribute + * interpolation, any dom event binding attribute interpolation such as for onclick, etc.) + * that uses the provided value. See * {@link ng.$sce $sce} for enabling strict contextual + * escaping. + * + * @param {string} type The kind of context in which this value is safe for use. e.g. url, + * resource_url, html, js and css. + * @param {*} value The value that that should be considered trusted/safe. + * @returns {*} A value that can be used to stand in for the provided `value` in places + * where Angular expects a $sce.trustAs() return value. + */ + + /** + * @ngdoc method + * @name $sce#trustAsHtml + * + * @description + * Shorthand method. `$sce.trustAsHtml(value)` → + * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`} + * + * @param {*} value The value to trustAs. + * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml + * $sce.getTrustedHtml(value)} to obtain the original value. (privileged directives + * only accept expressions that are either literal constants or are the + * return value of {@link ng.$sce#trustAs $sce.trustAs}.) + */ + + /** + * @ngdoc method + * @name $sce#trustAsUrl + * + * @description + * Shorthand method. `$sce.trustAsUrl(value)` → + * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`} + * + * @param {*} value The value to trustAs. + * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl + * $sce.getTrustedUrl(value)} to obtain the original value. (privileged directives + * only accept expressions that are either literal constants or are the + * return value of {@link ng.$sce#trustAs $sce.trustAs}.) + */ + + /** + * @ngdoc method + * @name $sce#trustAsResourceUrl + * + * @description + * Shorthand method. `$sce.trustAsResourceUrl(value)` → + * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`} + * + * @param {*} value The value to trustAs. + * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl + * $sce.getTrustedResourceUrl(value)} to obtain the original value. (privileged directives + * only accept expressions that are either literal constants or are the return + * value of {@link ng.$sce#trustAs $sce.trustAs}.) + */ + + /** + * @ngdoc method + * @name $sce#trustAsJs + * + * @description + * Shorthand method. `$sce.trustAsJs(value)` → + * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`} + * + * @param {*} value The value to trustAs. + * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs + * $sce.getTrustedJs(value)} to obtain the original value. (privileged directives + * only accept expressions that are either literal constants or are the + * return value of {@link ng.$sce#trustAs $sce.trustAs}.) + */ + + /** + * @ngdoc method + * @name $sce#getTrusted + * + * @description + * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}. As such, + * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the + * originally supplied value if the queried context type is a supertype of the created type. + * If this condition isn't satisfied, throws an exception. + * + * @param {string} type The kind of context in which this value is to be used. + * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`} + * call. + * @returns {*} The value the was originally provided to + * {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context. + * Otherwise, throws an exception. + */ + + /** + * @ngdoc method + * @name $sce#getTrustedHtml + * + * @description + * Shorthand method. `$sce.getTrustedHtml(value)` → + * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`} + * + * @param {*} value The value to pass to `$sce.getTrusted`. + * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)` + */ + + /** + * @ngdoc method + * @name $sce#getTrustedCss + * + * @description + * Shorthand method. `$sce.getTrustedCss(value)` → + * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`} + * + * @param {*} value The value to pass to `$sce.getTrusted`. + * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)` + */ + + /** + * @ngdoc method + * @name $sce#getTrustedUrl + * + * @description + * Shorthand method. `$sce.getTrustedUrl(value)` → + * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`} + * + * @param {*} value The value to pass to `$sce.getTrusted`. + * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)` + */ + + /** + * @ngdoc method + * @name $sce#getTrustedResourceUrl + * + * @description + * Shorthand method. `$sce.getTrustedResourceUrl(value)` → + * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`} + * + * @param {*} value The value to pass to `$sceDelegate.getTrusted`. + * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)` + */ + + /** + * @ngdoc method + * @name $sce#getTrustedJs + * + * @description + * Shorthand method. `$sce.getTrustedJs(value)` → + * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`} + * + * @param {*} value The value to pass to `$sce.getTrusted`. + * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)` + */ + + /** + * @ngdoc method + * @name $sce#parseAsHtml + * + * @description + * Shorthand method. `$sce.parseAsHtml(expression string)` → + * {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`} + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + */ + + /** + * @ngdoc method + * @name $sce#parseAsCss + * + * @description + * Shorthand method. `$sce.parseAsCss(value)` → + * {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`} + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + */ + + /** + * @ngdoc method + * @name $sce#parseAsUrl + * + * @description + * Shorthand method. `$sce.parseAsUrl(value)` → + * {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`} + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + */ + + /** + * @ngdoc method + * @name $sce#parseAsResourceUrl + * + * @description + * Shorthand method. `$sce.parseAsResourceUrl(value)` → + * {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`} + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + */ + + /** + * @ngdoc method + * @name $sce#parseAsJs + * + * @description + * Shorthand method. `$sce.parseAsJs(value)` → + * {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`} + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + */ + + // Shorthand delegations. + var parse = sce.parseAs, + getTrusted = sce.getTrusted, + trustAs = sce.trustAs; + + forEach(SCE_CONTEXTS, function(enumValue, name) { + var lName = lowercase(name); + sce[camelCase("parse_as_" + lName)] = function(expr) { + return parse(enumValue, expr); + }; + sce[camelCase("get_trusted_" + lName)] = function(value) { + return getTrusted(enumValue, value); + }; + sce[camelCase("trust_as_" + lName)] = function(value) { + return trustAs(enumValue, value); + }; + }); + + return sce; + }]; +} + +/** + * !!! This is an undocumented "private" service !!! + * + * @name $sniffer + * @requires $window + * @requires $document + * + * @property {boolean} history Does the browser support html5 history api ? + * @property {boolean} transitions Does the browser support CSS transition events ? + * @property {boolean} animations Does the browser support CSS animation events ? + * + * @description + * This is very simple implementation of testing browser's features. + */ +function $SnifferProvider() { + this.$get = ['$window', '$document', function($window, $document) { + var eventSupport = {}, + android = + int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]), + boxee = /Boxee/i.test(($window.navigator || {}).userAgent), + document = $document[0] || {}, + vendorPrefix, + vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/, + bodyStyle = document.body && document.body.style, + transitions = false, + animations = false, + match; + + if (bodyStyle) { + for (var prop in bodyStyle) { + if (match = vendorRegex.exec(prop)) { + vendorPrefix = match[0]; + vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1); + break; + } + } + + if (!vendorPrefix) { + vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit'; + } + + transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle)); + animations = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle)); + + if (android && (!transitions || !animations)) { + transitions = isString(document.body.style.webkitTransition); + animations = isString(document.body.style.webkitAnimation); + } + } + + + return { + // Android has history.pushState, but it does not update location correctly + // so let's not use the history API at all. + // http://code.google.com/p/android/issues/detail?id=17471 + // https://github.com/angular/angular.js/issues/904 + + // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has + // so let's not use the history API also + // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined + // jshint -W018 + history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee), + // jshint +W018 + hasEvent: function(event) { + // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have + // it. In particular the event is not fired when backspace or delete key are pressed or + // when cut operation is performed. + // IE10+ implements 'input' event but it erroneously fires under various situations, + // e.g. when placeholder changes, or a form is focused. + if (event === 'input' && msie <= 11) return false; + + if (isUndefined(eventSupport[event])) { + var divElm = document.createElement('div'); + eventSupport[event] = 'on' + event in divElm; + } + + return eventSupport[event]; + }, + csp: csp(), + vendorPrefix: vendorPrefix, + transitions: transitions, + animations: animations, + android: android + }; + }]; +} + +var $compileMinErr = minErr('$compile'); + +/** + * @ngdoc service + * @name $templateRequest + * + * @description + * The `$templateRequest` service downloads the provided template using `$http` and, upon success, + * stores the contents inside of `$templateCache`. If the HTTP request fails or the response data + * of the HTTP request is empty, a `$compile` error will be thrown (the exception can be thwarted + * by setting the 2nd parameter of the function to true). + * + * @param {string} tpl The HTTP request template URL + * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty + * + * @return {Promise} the HTTP Promise for the given. + * + * @property {number} totalPendingRequests total amount of pending template requests being downloaded. + */ +function $TemplateRequestProvider() { + this.$get = ['$templateCache', '$http', '$q', function($templateCache, $http, $q) { + function handleRequestFn(tpl, ignoreRequestError) { + handleRequestFn.totalPendingRequests++; + + var transformResponse = $http.defaults && $http.defaults.transformResponse; + + if (isArray(transformResponse)) { + transformResponse = transformResponse.filter(function(transformer) { + return transformer !== defaultHttpResponseTransform; + }); + } else if (transformResponse === defaultHttpResponseTransform) { + transformResponse = null; + } + + var httpOptions = { + cache: $templateCache, + transformResponse: transformResponse + }; + + return $http.get(tpl, httpOptions) + .finally(function() { + handleRequestFn.totalPendingRequests--; + }) + .then(function(response) { + return response.data; + }, handleError); + + function handleError(resp) { + if (!ignoreRequestError) { + throw $compileMinErr('tpload', 'Failed to load template: {0}', tpl); + } + return $q.reject(resp); + } + } + + handleRequestFn.totalPendingRequests = 0; + + return handleRequestFn; + }]; +} + +function $$TestabilityProvider() { + this.$get = ['$rootScope', '$browser', '$location', + function($rootScope, $browser, $location) { + + /** + * @name $testability + * + * @description + * The private $$testability service provides a collection of methods for use when debugging + * or by automated test and debugging tools. + */ + var testability = {}; + + /** + * @name $$testability#findBindings + * + * @description + * Returns an array of elements that are bound (via ng-bind or {{}}) + * to expressions matching the input. + * + * @param {Element} element The element root to search from. + * @param {string} expression The binding expression to match. + * @param {boolean} opt_exactMatch If true, only returns exact matches + * for the expression. Filters and whitespace are ignored. + */ + testability.findBindings = function(element, expression, opt_exactMatch) { + var bindings = element.getElementsByClassName('ng-binding'); + var matches = []; + forEach(bindings, function(binding) { + var dataBinding = angular.element(binding).data('$binding'); + if (dataBinding) { + forEach(dataBinding, function(bindingName) { + if (opt_exactMatch) { + var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)'); + if (matcher.test(bindingName)) { + matches.push(binding); + } + } else { + if (bindingName.indexOf(expression) != -1) { + matches.push(binding); + } + } + }); + } + }); + return matches; + }; + + /** + * @name $$testability#findModels + * + * @description + * Returns an array of elements that are two-way found via ng-model to + * expressions matching the input. + * + * @param {Element} element The element root to search from. + * @param {string} expression The model expression to match. + * @param {boolean} opt_exactMatch If true, only returns exact matches + * for the expression. + */ + testability.findModels = function(element, expression, opt_exactMatch) { + var prefixes = ['ng-', 'data-ng-', 'ng\\:']; + for (var p = 0; p < prefixes.length; ++p) { + var attributeEquals = opt_exactMatch ? '=' : '*='; + var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]'; + var elements = element.querySelectorAll(selector); + if (elements.length) { + return elements; + } + } + }; + + /** + * @name $$testability#getLocation + * + * @description + * Shortcut for getting the location in a browser agnostic way. Returns + * the path, search, and hash. (e.g. /path?a=b#hash) + */ + testability.getLocation = function() { + return $location.url(); + }; + + /** + * @name $$testability#setLocation + * + * @description + * Shortcut for navigating to a location without doing a full page reload. + * + * @param {string} url The location url (path, search and hash, + * e.g. /path?a=b#hash) to go to. + */ + testability.setLocation = function(url) { + if (url !== $location.url()) { + $location.url(url); + $rootScope.$digest(); + } + }; + + /** + * @name $$testability#whenStable + * + * @description + * Calls the callback when $timeout and $http requests are completed. + * + * @param {function} callback + */ + testability.whenStable = function(callback) { + $browser.notifyWhenNoOutstandingRequests(callback); + }; + + return testability; + }]; +} + +function $TimeoutProvider() { + this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler', + function($rootScope, $browser, $q, $$q, $exceptionHandler) { + var deferreds = {}; + + + /** + * @ngdoc service + * @name $timeout + * + * @description + * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch + * block and delegates any exceptions to + * {@link ng.$exceptionHandler $exceptionHandler} service. + * + * The return value of registering a timeout function is a promise, which will be resolved when + * the timeout is reached and the timeout function is executed. + * + * To cancel a timeout request, call `$timeout.cancel(promise)`. + * + * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to + * synchronously flush the queue of deferred functions. + * + * @param {function()} fn A function, whose execution should be delayed. + * @param {number=} [delay=0] Delay in milliseconds. + * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise + * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. + * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this + * promise will be resolved with is the return value of the `fn` function. + * + */ + function timeout(fn, delay, invokeApply) { + var skipApply = (isDefined(invokeApply) && !invokeApply), + deferred = (skipApply ? $$q : $q).defer(), + promise = deferred.promise, + timeoutId; + + timeoutId = $browser.defer(function() { + try { + deferred.resolve(fn()); + } catch (e) { + deferred.reject(e); + $exceptionHandler(e); + } + finally { + delete deferreds[promise.$$timeoutId]; + } + + if (!skipApply) $rootScope.$apply(); + }, delay); + + promise.$$timeoutId = timeoutId; + deferreds[timeoutId] = deferred; + + return promise; + } + + + /** + * @ngdoc method + * @name $timeout#cancel + * + * @description + * Cancels a task associated with the `promise`. As a result of this, the promise will be + * resolved with a rejection. + * + * @param {Promise=} promise Promise returned by the `$timeout` function. + * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully + * canceled. + */ + timeout.cancel = function(promise) { + if (promise && promise.$$timeoutId in deferreds) { + deferreds[promise.$$timeoutId].reject('canceled'); + delete deferreds[promise.$$timeoutId]; + return $browser.defer.cancel(promise.$$timeoutId); + } + return false; + }; + + return timeout; + }]; +} + +// NOTE: The usage of window and document instead of $window and $document here is +// deliberate. This service depends on the specific behavior of anchor nodes created by the +// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and +// cause us to break tests. In addition, when the browser resolves a URL for XHR, it +// doesn't know about mocked locations and resolves URLs to the real document - which is +// exactly the behavior needed here. There is little value is mocking these out for this +// service. +var urlParsingNode = document.createElement("a"); +var originUrl = urlResolve(window.location.href); + + +/** + * + * Implementation Notes for non-IE browsers + * ---------------------------------------- + * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM, + * results both in the normalizing and parsing of the URL. Normalizing means that a relative + * URL will be resolved into an absolute URL in the context of the application document. + * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related + * properties are all populated to reflect the normalized URL. This approach has wide + * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc. See + * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html + * + * Implementation Notes for IE + * --------------------------- + * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other + * browsers. However, the parsed components will not be set if the URL assigned did not specify + * them. (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.) We + * work around that by performing the parsing in a 2nd step by taking a previously normalized + * URL (e.g. by assigning to a.href) and assigning it a.href again. This correctly populates the + * properties such as protocol, hostname, port, etc. + * + * IE7 does not normalize the URL when assigned to an anchor node. (Apparently, it does, if one + * uses the inner HTML approach to assign the URL as part of an HTML snippet - + * http://stackoverflow.com/a/472729) However, setting img[src] does normalize the URL. + * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception. + * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that + * method and IE < 8 is unsupported. + * + * References: + * http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement + * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html + * http://url.spec.whatwg.org/#urlutils + * https://github.com/angular/angular.js/pull/2902 + * http://james.padolsey.com/javascript/parsing-urls-with-the-dom/ + * + * @kind function + * @param {string} url The URL to be parsed. + * @description Normalizes and parses a URL. + * @returns {object} Returns the normalized URL as a dictionary. + * + * | member name | Description | + * |---------------|----------------| + * | href | A normalized version of the provided URL if it was not an absolute URL | + * | protocol | The protocol including the trailing colon | + * | host | The host and port (if the port is non-default) of the normalizedUrl | + * | search | The search params, minus the question mark | + * | hash | The hash string, minus the hash symbol + * | hostname | The hostname + * | port | The port, without ":" + * | pathname | The pathname, beginning with "/" + * + */ +function urlResolve(url) { + var href = url; + + if (msie) { + // Normalize before parse. Refer Implementation Notes on why this is + // done in two steps on IE. + urlParsingNode.setAttribute("href", href); + href = urlParsingNode.href; + } + + urlParsingNode.setAttribute('href', href); + + // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils + return { + href: urlParsingNode.href, + protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '', + host: urlParsingNode.host, + search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '', + hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '', + hostname: urlParsingNode.hostname, + port: urlParsingNode.port, + pathname: (urlParsingNode.pathname.charAt(0) === '/') + ? urlParsingNode.pathname + : '/' + urlParsingNode.pathname + }; +} + +/** + * Parse a request URL and determine whether this is a same-origin request as the application document. + * + * @param {string|object} requestUrl The url of the request as a string that will be resolved + * or a parsed URL object. + * @returns {boolean} Whether the request is for the same origin as the application document. + */ +function urlIsSameOrigin(requestUrl) { + var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl; + return (parsed.protocol === originUrl.protocol && + parsed.host === originUrl.host); +} + +/** + * @ngdoc service + * @name $window + * + * @description + * A reference to the browser's `window` object. While `window` + * is globally available in JavaScript, it causes testability problems, because + * it is a global variable. In angular we always refer to it through the + * `$window` service, so it may be overridden, removed or mocked for testing. + * + * Expressions, like the one defined for the `ngClick` directive in the example + * below, are evaluated with respect to the current scope. Therefore, there is + * no risk of inadvertently coding in a dependency on a global value in such an + * expression. + * + * @example + + + +
    + + +
    +
    + + it('should display the greeting in the input box', function() { + element(by.model('greeting')).sendKeys('Hello, E2E Tests'); + // If we click the button it will block the test runner + // element(':button').click(); + }); + +
    + */ +function $WindowProvider() { + this.$get = valueFn(window); +} + +/* global currencyFilter: true, + dateFilter: true, + filterFilter: true, + jsonFilter: true, + limitToFilter: true, + lowercaseFilter: true, + numberFilter: true, + orderByFilter: true, + uppercaseFilter: true, + */ + +/** + * @ngdoc provider + * @name $filterProvider + * @description + * + * Filters are just functions which transform input to an output. However filters need to be + * Dependency Injected. To achieve this a filter definition consists of a factory function which is + * annotated with dependencies and is responsible for creating a filter function. + * + * ```js + * // Filter registration + * function MyModule($provide, $filterProvider) { + * // create a service to demonstrate injection (not always needed) + * $provide.value('greet', function(name){ + * return 'Hello ' + name + '!'; + * }); + * + * // register a filter factory which uses the + * // greet service to demonstrate DI. + * $filterProvider.register('greet', function(greet){ + * // return the filter function which uses the greet service + * // to generate salutation + * return function(text) { + * // filters need to be forgiving so check input validity + * return text && greet(text) || text; + * }; + * }); + * } + * ``` + * + * The filter function is registered with the `$injector` under the filter name suffix with + * `Filter`. + * + * ```js + * it('should be the same instance', inject( + * function($filterProvider) { + * $filterProvider.register('reverse', function(){ + * return ...; + * }); + * }, + * function($filter, reverseFilter) { + * expect($filter('reverse')).toBe(reverseFilter); + * }); + * ``` + * + * + * For more information about how angular filters work, and how to create your own filters, see + * {@link guide/filter Filters} in the Angular Developer Guide. + */ + +/** + * @ngdoc service + * @name $filter + * @kind function + * @description + * Filters are used for formatting data displayed to the user. + * + * The general syntax in templates is as follows: + * + * {{ expression [| filter_name[:parameter_value] ... ] }} + * + * @param {String} name Name of the filter function to retrieve + * @return {Function} the filter function + * @example + + +
    +

    {{ originalText }}

    +

    {{ filteredText }}

    +
    +
    + + + angular.module('filterExample', []) + .controller('MainCtrl', function($scope, $filter) { + $scope.originalText = 'hello'; + $scope.filteredText = $filter('uppercase')($scope.originalText); + }); + +
    + */ +$FilterProvider.$inject = ['$provide']; +function $FilterProvider($provide) { + var suffix = 'Filter'; + + /** + * @ngdoc method + * @name $filterProvider#register + * @param {string|Object} name Name of the filter function, or an object map of filters where + * the keys are the filter names and the values are the filter factories. + * @returns {Object} Registered filter instance, or if a map of filters was provided then a map + * of the registered filter instances. + */ + function register(name, factory) { + if (isObject(name)) { + var filters = {}; + forEach(name, function(filter, key) { + filters[key] = register(key, filter); + }); + return filters; + } else { + return $provide.factory(name + suffix, factory); + } + } + this.register = register; + + this.$get = ['$injector', function($injector) { + return function(name) { + return $injector.get(name + suffix); + }; + }]; + + //////////////////////////////////////// + + /* global + currencyFilter: false, + dateFilter: false, + filterFilter: false, + jsonFilter: false, + limitToFilter: false, + lowercaseFilter: false, + numberFilter: false, + orderByFilter: false, + uppercaseFilter: false, + */ + + register('currency', currencyFilter); + register('date', dateFilter); + register('filter', filterFilter); + register('json', jsonFilter); + register('limitTo', limitToFilter); + register('lowercase', lowercaseFilter); + register('number', numberFilter); + register('orderBy', orderByFilter); + register('uppercase', uppercaseFilter); +} + +/** + * @ngdoc filter + * @name filter + * @kind function + * + * @description + * Selects a subset of items from `array` and returns it as a new array. + * + * @param {Array} array The source array. + * @param {string|Object|function()} expression The predicate to be used for selecting items from + * `array`. + * + * Can be one of: + * + * - `string`: The string is used for matching against the contents of the `array`. All strings or + * objects with string properties in `array` that match this string will be returned. This also + * applies to nested object properties. + * The predicate can be negated by prefixing the string with `!`. + * + * - `Object`: A pattern object can be used to filter specific properties on objects contained + * by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items + * which have property `name` containing "M" and property `phone` containing "1". A special + * property name `$` can be used (as in `{$:"text"}`) to accept a match against any + * property of the object or its nested object properties. That's equivalent to the simple + * substring match with a `string` as described above. The predicate can be negated by prefixing + * the string with `!`. + * For example `{name: "!M"}` predicate will return an array of items which have property `name` + * not containing "M". + * + * Note that a named property will match properties on the same level only, while the special + * `$` property will match properties on the same level or deeper. E.g. an array item like + * `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but + * **will** be matched by `{$: 'John'}`. + * + * - `function(value, index)`: A predicate function can be used to write arbitrary filters. The + * function is called for each element of `array`. The final result is an array of those + * elements that the predicate returned true for. + * + * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in + * determining if the expected value (from the filter expression) and actual value (from + * the object in the array) should be considered a match. + * + * Can be one of: + * + * - `function(actual, expected)`: + * The function will be given the object value and the predicate value to compare and + * should return true if both values should be considered equal. + * + * - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`. + * This is essentially strict comparison of expected and actual. + * + * - `false|undefined`: A short hand for a function which will look for a substring match in case + * insensitive way. + * + * @example + + +
    + + Search: + + + + + + +
    NamePhone
    {{friend.name}}{{friend.phone}}
    +
    + Any:
    + Name only
    + Phone only
    + Equality
    + + + + + + +
    NamePhone
    {{friendObj.name}}{{friendObj.phone}}
    +
    + + var expectFriendNames = function(expectedNames, key) { + element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) { + arr.forEach(function(wd, i) { + expect(wd.getText()).toMatch(expectedNames[i]); + }); + }); + }; + + it('should search across all fields when filtering with a string', function() { + var searchText = element(by.model('searchText')); + searchText.clear(); + searchText.sendKeys('m'); + expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend'); + + searchText.clear(); + searchText.sendKeys('76'); + expectFriendNames(['John', 'Julie'], 'friend'); + }); + + it('should search in specific fields when filtering with a predicate object', function() { + var searchAny = element(by.model('search.$')); + searchAny.clear(); + searchAny.sendKeys('i'); + expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj'); + }); + it('should use a equal comparison when comparator is true', function() { + var searchName = element(by.model('search.name')); + var strict = element(by.model('strict')); + searchName.clear(); + searchName.sendKeys('Julie'); + strict.click(); + expectFriendNames(['Julie'], 'friendObj'); + }); + +
    + */ +function filterFilter() { + return function(array, expression, comparator) { + if (!isArray(array)) return array; + + var predicateFn; + var matchAgainstAnyProp; + + switch (typeof expression) { + case 'function': + predicateFn = expression; + break; + case 'boolean': + case 'number': + case 'string': + matchAgainstAnyProp = true; + //jshint -W086 + case 'object': + //jshint +W086 + predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp); + break; + default: + return array; + } + + return array.filter(predicateFn); + }; +} + +// Helper functions for `filterFilter` +function createPredicateFn(expression, comparator, matchAgainstAnyProp) { + var shouldMatchPrimitives = isObject(expression) && ('$' in expression); + var predicateFn; + + if (comparator === true) { + comparator = equals; + } else if (!isFunction(comparator)) { + comparator = function(actual, expected) { + if (isObject(actual) || isObject(expected)) { + // Prevent an object to be considered equal to a string like `'[object'` + return false; + } + + actual = lowercase('' + actual); + expected = lowercase('' + expected); + return actual.indexOf(expected) !== -1; + }; + } + + predicateFn = function(item) { + if (shouldMatchPrimitives && !isObject(item)) { + return deepCompare(item, expression.$, comparator, false); + } + return deepCompare(item, expression, comparator, matchAgainstAnyProp); + }; + + return predicateFn; +} + +function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatchWholeObject) { + var actualType = typeof actual; + var expectedType = typeof expected; + + if ((expectedType === 'string') && (expected.charAt(0) === '!')) { + return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp); + } else if (isArray(actual)) { + // In case `actual` is an array, consider it a match + // if ANY of it's items matches `expected` + return actual.some(function(item) { + return deepCompare(item, expected, comparator, matchAgainstAnyProp); + }); + } + + switch (actualType) { + case 'object': + var key; + if (matchAgainstAnyProp) { + for (key in actual) { + if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, true)) { + return true; + } + } + return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, false); + } else if (expectedType === 'object') { + for (key in expected) { + var expectedVal = expected[key]; + if (isFunction(expectedVal)) { + continue; + } + + var matchAnyProperty = key === '$'; + var actualVal = matchAnyProperty ? actual : actual[key]; + if (!deepCompare(actualVal, expectedVal, comparator, matchAnyProperty, matchAnyProperty)) { + return false; + } + } + return true; + } else { + return comparator(actual, expected); + } + break; + case 'function': + return false; + default: + return comparator(actual, expected); + } +} + +/** + * @ngdoc filter + * @name currency + * @kind function + * + * @description + * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default + * symbol for current locale is used. + * + * @param {number} amount Input to filter. + * @param {string=} symbol Currency symbol or identifier to be displayed. + * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale + * @returns {string} Formatted number. + * + * + * @example + + + +
    +
    + default currency symbol ($): {{amount | currency}}
    + custom currency identifier (USD$): {{amount | currency:"USD$"}} + no fractions (0): {{amount | currency:"USD$":0}} +
    +
    + + it('should init with 1234.56', function() { + expect(element(by.id('currency-default')).getText()).toBe('$1,234.56'); + expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56'); + expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235'); + }); + it('should update', function() { + if (browser.params.browser == 'safari') { + // Safari does not understand the minus key. See + // https://github.com/angular/protractor/issues/481 + return; + } + element(by.model('amount')).clear(); + element(by.model('amount')).sendKeys('-1234'); + expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)'); + expect(element(by.id('currency-custom')).getText()).toBe('(USD$1,234.00)'); + expect(element(by.id('currency-no-fractions')).getText()).toBe('(USD$1,234)'); + }); + +
    + */ +currencyFilter.$inject = ['$locale']; +function currencyFilter($locale) { + var formats = $locale.NUMBER_FORMATS; + return function(amount, currencySymbol, fractionSize) { + if (isUndefined(currencySymbol)) { + currencySymbol = formats.CURRENCY_SYM; + } + + if (isUndefined(fractionSize)) { + fractionSize = formats.PATTERNS[1].maxFrac; + } + + // if null or undefined pass it through + return (amount == null) + ? amount + : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize). + replace(/\u00A4/g, currencySymbol); + }; +} + +/** + * @ngdoc filter + * @name number + * @kind function + * + * @description + * Formats a number as text. + * + * If the input is not a number an empty string is returned. + * + * @param {number|string} number Number to format. + * @param {(number|string)=} fractionSize Number of decimal places to round the number to. + * If this is not provided then the fraction size is computed from the current locale's number + * formatting pattern. In the case of the default locale, it will be 3. + * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit. + * + * @example + + + +
    + Enter number:
    + Default formatting: {{val | number}}
    + No fractions: {{val | number:0}}
    + Negative number: {{-val | number:4}} +
    +
    + + it('should format numbers', function() { + expect(element(by.id('number-default')).getText()).toBe('1,234.568'); + expect(element(by.binding('val | number:0')).getText()).toBe('1,235'); + expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679'); + }); + + it('should update', function() { + element(by.model('val')).clear(); + element(by.model('val')).sendKeys('3374.333'); + expect(element(by.id('number-default')).getText()).toBe('3,374.333'); + expect(element(by.binding('val | number:0')).getText()).toBe('3,374'); + expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330'); + }); + +
    + */ + + +numberFilter.$inject = ['$locale']; +function numberFilter($locale) { + var formats = $locale.NUMBER_FORMATS; + return function(number, fractionSize) { + + // if null or undefined pass it through + return (number == null) + ? number + : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP, + fractionSize); + }; +} + +var DECIMAL_SEP = '.'; +function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) { + if (!isFinite(number) || isObject(number)) return ''; + + var isNegative = number < 0; + number = Math.abs(number); + var numStr = number + '', + formatedText = '', + parts = []; + + var hasExponent = false; + if (numStr.indexOf('e') !== -1) { + var match = numStr.match(/([\d\.]+)e(-?)(\d+)/); + if (match && match[2] == '-' && match[3] > fractionSize + 1) { + number = 0; + } else { + formatedText = numStr; + hasExponent = true; + } + } + + if (!hasExponent) { + var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length; + + // determine fractionSize if it is not specified + if (isUndefined(fractionSize)) { + fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac); + } + + // safely round numbers in JS without hitting imprecisions of floating-point arithmetics + // inspired by: + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round + number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize); + + var fraction = ('' + number).split(DECIMAL_SEP); + var whole = fraction[0]; + fraction = fraction[1] || ''; + + var i, pos = 0, + lgroup = pattern.lgSize, + group = pattern.gSize; + + if (whole.length >= (lgroup + group)) { + pos = whole.length - lgroup; + for (i = 0; i < pos; i++) { + if ((pos - i) % group === 0 && i !== 0) { + formatedText += groupSep; + } + formatedText += whole.charAt(i); + } + } + + for (i = pos; i < whole.length; i++) { + if ((whole.length - i) % lgroup === 0 && i !== 0) { + formatedText += groupSep; + } + formatedText += whole.charAt(i); + } + + // format fraction part. + while (fraction.length < fractionSize) { + fraction += '0'; + } + + if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize); + } else { + if (fractionSize > 0 && number < 1) { + formatedText = number.toFixed(fractionSize); + number = parseFloat(formatedText); + } + } + + if (number === 0) { + isNegative = false; + } + + parts.push(isNegative ? pattern.negPre : pattern.posPre, + formatedText, + isNegative ? pattern.negSuf : pattern.posSuf); + return parts.join(''); +} + +function padNumber(num, digits, trim) { + var neg = ''; + if (num < 0) { + neg = '-'; + num = -num; + } + num = '' + num; + while (num.length < digits) num = '0' + num; + if (trim) + num = num.substr(num.length - digits); + return neg + num; +} + + +function dateGetter(name, size, offset, trim) { + offset = offset || 0; + return function(date) { + var value = date['get' + name](); + if (offset > 0 || value > -offset) + value += offset; + if (value === 0 && offset == -12) value = 12; + return padNumber(value, size, trim); + }; +} + +function dateStrGetter(name, shortForm) { + return function(date, formats) { + var value = date['get' + name](); + var get = uppercase(shortForm ? ('SHORT' + name) : name); + + return formats[get][value]; + }; +} + +function timeZoneGetter(date) { + var zone = -1 * date.getTimezoneOffset(); + var paddedZone = (zone >= 0) ? "+" : ""; + + paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) + + padNumber(Math.abs(zone % 60), 2); + + return paddedZone; +} + +function getFirstThursdayOfYear(year) { + // 0 = index of January + var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay(); + // 4 = index of Thursday (+1 to account for 1st = 5) + // 11 = index of *next* Thursday (+1 account for 1st = 12) + return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst); +} + +function getThursdayThisWeek(datetime) { + return new Date(datetime.getFullYear(), datetime.getMonth(), + // 4 = index of Thursday + datetime.getDate() + (4 - datetime.getDay())); +} + +function weekGetter(size) { + return function(date) { + var firstThurs = getFirstThursdayOfYear(date.getFullYear()), + thisThurs = getThursdayThisWeek(date); + + var diff = +thisThurs - +firstThurs, + result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week + + return padNumber(result, size); + }; +} + +function ampmGetter(date, formats) { + return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1]; +} + +var DATE_FORMATS = { + yyyy: dateGetter('FullYear', 4), + yy: dateGetter('FullYear', 2, 0, true), + y: dateGetter('FullYear', 1), + MMMM: dateStrGetter('Month'), + MMM: dateStrGetter('Month', true), + MM: dateGetter('Month', 2, 1), + M: dateGetter('Month', 1, 1), + dd: dateGetter('Date', 2), + d: dateGetter('Date', 1), + HH: dateGetter('Hours', 2), + H: dateGetter('Hours', 1), + hh: dateGetter('Hours', 2, -12), + h: dateGetter('Hours', 1, -12), + mm: dateGetter('Minutes', 2), + m: dateGetter('Minutes', 1), + ss: dateGetter('Seconds', 2), + s: dateGetter('Seconds', 1), + // while ISO 8601 requires fractions to be prefixed with `.` or `,` + // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions + sss: dateGetter('Milliseconds', 3), + EEEE: dateStrGetter('Day'), + EEE: dateStrGetter('Day', true), + a: ampmGetter, + Z: timeZoneGetter, + ww: weekGetter(2), + w: weekGetter(1) +}; + +var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEw']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|w+))(.*)/, + NUMBER_STRING = /^\-?\d+$/; + +/** + * @ngdoc filter + * @name date + * @kind function + * + * @description + * Formats `date` to a string based on the requested `format`. + * + * `format` string can be composed of the following elements: + * + * * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010) + * * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10) + * * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199) + * * `'MMMM'`: Month in year (January-December) + * * `'MMM'`: Month in year (Jan-Dec) + * * `'MM'`: Month in year, padded (01-12) + * * `'M'`: Month in year (1-12) + * * `'dd'`: Day in month, padded (01-31) + * * `'d'`: Day in month (1-31) + * * `'EEEE'`: Day in Week,(Sunday-Saturday) + * * `'EEE'`: Day in Week, (Sun-Sat) + * * `'HH'`: Hour in day, padded (00-23) + * * `'H'`: Hour in day (0-23) + * * `'hh'`: Hour in AM/PM, padded (01-12) + * * `'h'`: Hour in AM/PM, (1-12) + * * `'mm'`: Minute in hour, padded (00-59) + * * `'m'`: Minute in hour (0-59) + * * `'ss'`: Second in minute, padded (00-59) + * * `'s'`: Second in minute (0-59) + * * `'sss'`: Millisecond in second, padded (000-999) + * * `'a'`: AM/PM marker + * * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200) + * * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year + * * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year + * + * `format` string can also be one of the following predefined + * {@link guide/i18n localizable formats}: + * + * * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale + * (e.g. Sep 3, 2010 12:05:08 PM) + * * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US locale (e.g. 9/3/10 12:05 PM) + * * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US locale + * (e.g. Friday, September 3, 2010) + * * `'longDate'`: equivalent to `'MMMM d, y'` for en_US locale (e.g. September 3, 2010) + * * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US locale (e.g. Sep 3, 2010) + * * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10) + * * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM) + * * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM) + * + * `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g. + * `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence + * (e.g. `"h 'o''clock'"`). + * + * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or + * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its + * shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is + * specified in the string input, the time is considered to be in the local timezone. + * @param {string=} format Formatting rules (see Description). If not specified, + * `mediumDate` is used. + * @param {string=} timezone Timezone to be used for formatting. Right now, only `'UTC'` is supported. + * If not specified, the timezone of the browser will be used. + * @returns {string} Formatted string or the input if input is not recognized as date/millis. + * + * @example + + + {{1288323623006 | date:'medium'}}: + {{1288323623006 | date:'medium'}}
    + {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}: + {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}
    + {{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}: + {{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}
    + {{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}: + {{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}
    +
    + + it('should format date', function() { + expect(element(by.binding("1288323623006 | date:'medium'")).getText()). + toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/); + expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()). + toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/); + expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()). + toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/); + expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()). + toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/); + }); + +
    + */ +dateFilter.$inject = ['$locale']; +function dateFilter($locale) { + + + var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/; + // 1 2 3 4 5 6 7 8 9 10 11 + function jsonStringToDate(string) { + var match; + if (match = string.match(R_ISO8601_STR)) { + var date = new Date(0), + tzHour = 0, + tzMin = 0, + dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear, + timeSetter = match[8] ? date.setUTCHours : date.setHours; + + if (match[9]) { + tzHour = int(match[9] + match[10]); + tzMin = int(match[9] + match[11]); + } + dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3])); + var h = int(match[4] || 0) - tzHour; + var m = int(match[5] || 0) - tzMin; + var s = int(match[6] || 0); + var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000); + timeSetter.call(date, h, m, s, ms); + return date; + } + return string; + } + + + return function(date, format, timezone) { + var text = '', + parts = [], + fn, match; + + format = format || 'mediumDate'; + format = $locale.DATETIME_FORMATS[format] || format; + if (isString(date)) { + date = NUMBER_STRING.test(date) ? int(date) : jsonStringToDate(date); + } + + if (isNumber(date)) { + date = new Date(date); + } + + if (!isDate(date)) { + return date; + } + + while (format) { + match = DATE_FORMATS_SPLIT.exec(format); + if (match) { + parts = concat(parts, match, 1); + format = parts.pop(); + } else { + parts.push(format); + format = null; + } + } + + if (timezone && timezone === 'UTC') { + date = new Date(date.getTime()); + date.setMinutes(date.getMinutes() + date.getTimezoneOffset()); + } + forEach(parts, function(value) { + fn = DATE_FORMATS[value]; + text += fn ? fn(date, $locale.DATETIME_FORMATS) + : value.replace(/(^'|'$)/g, '').replace(/''/g, "'"); + }); + + return text; + }; +} + + +/** + * @ngdoc filter + * @name json + * @kind function + * + * @description + * Allows you to convert a JavaScript object into JSON string. + * + * This filter is mostly useful for debugging. When using the double curly {{value}} notation + * the binding is automatically converted to JSON. + * + * @param {*} object Any JavaScript object (including arrays and primitive types) to filter. + * @param {number=} spacing The number of spaces to use per indentation, defaults to 2. + * @returns {string} JSON string. + * + * + * @example + + +
    {{ {'name':'value'} | json }}
    +
    {{ {'name':'value'} | json:4 }}
    +
    + + it('should jsonify filtered objects', function() { + expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n "name": ?"value"\n}/); + expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n "name": ?"value"\n}/); + }); + +
    + * + */ +function jsonFilter() { + return function(object, spacing) { + if (isUndefined(spacing)) { + spacing = 2; + } + return toJson(object, spacing); + }; +} + + +/** + * @ngdoc filter + * @name lowercase + * @kind function + * @description + * Converts string to lowercase. + * @see angular.lowercase + */ +var lowercaseFilter = valueFn(lowercase); + + +/** + * @ngdoc filter + * @name uppercase + * @kind function + * @description + * Converts string to uppercase. + * @see angular.uppercase + */ +var uppercaseFilter = valueFn(uppercase); + +/** + * @ngdoc filter + * @name limitTo + * @kind function + * + * @description + * Creates a new array or string containing only a specified number of elements. The elements + * are taken from either the beginning or the end of the source array, string or number, as specified by + * the value and sign (positive or negative) of `limit`. If a number is used as input, it is + * converted to a string. + * + * @param {Array|string|number} input Source array, string or number to be limited. + * @param {string|number} limit The length of the returned array or string. If the `limit` number + * is positive, `limit` number of items from the beginning of the source array/string are copied. + * If the number is negative, `limit` number of items from the end of the source array/string + * are copied. The `limit` will be trimmed if it exceeds `array.length` + * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array + * had less than `limit` elements. + * + * @example + + + +
    + Limit {{numbers}} to: +

    Output numbers: {{ numbers | limitTo:numLimit }}

    + Limit {{letters}} to: +

    Output letters: {{ letters | limitTo:letterLimit }}

    + Limit {{longNumber}} to: +

    Output long number: {{ longNumber | limitTo:longNumberLimit }}

    +
    +
    + + var numLimitInput = element(by.model('numLimit')); + var letterLimitInput = element(by.model('letterLimit')); + var longNumberLimitInput = element(by.model('longNumberLimit')); + var limitedNumbers = element(by.binding('numbers | limitTo:numLimit')); + var limitedLetters = element(by.binding('letters | limitTo:letterLimit')); + var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit')); + + it('should limit the number array to first three items', function() { + expect(numLimitInput.getAttribute('value')).toBe('3'); + expect(letterLimitInput.getAttribute('value')).toBe('3'); + expect(longNumberLimitInput.getAttribute('value')).toBe('3'); + expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]'); + expect(limitedLetters.getText()).toEqual('Output letters: abc'); + expect(limitedLongNumber.getText()).toEqual('Output long number: 234'); + }); + + // There is a bug in safari and protractor that doesn't like the minus key + // it('should update the output when -3 is entered', function() { + // numLimitInput.clear(); + // numLimitInput.sendKeys('-3'); + // letterLimitInput.clear(); + // letterLimitInput.sendKeys('-3'); + // longNumberLimitInput.clear(); + // longNumberLimitInput.sendKeys('-3'); + // expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]'); + // expect(limitedLetters.getText()).toEqual('Output letters: ghi'); + // expect(limitedLongNumber.getText()).toEqual('Output long number: 342'); + // }); + + it('should not exceed the maximum size of input array', function() { + numLimitInput.clear(); + numLimitInput.sendKeys('100'); + letterLimitInput.clear(); + letterLimitInput.sendKeys('100'); + longNumberLimitInput.clear(); + longNumberLimitInput.sendKeys('100'); + expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]'); + expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi'); + expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342'); + }); + +
    +*/ +function limitToFilter() { + return function(input, limit) { + if (isNumber(input)) input = input.toString(); + if (!isArray(input) && !isString(input)) return input; + + if (Math.abs(Number(limit)) === Infinity) { + limit = Number(limit); + } else { + limit = int(limit); + } + + //NaN check on limit + if (limit) { + return limit > 0 ? input.slice(0, limit) : input.slice(limit); + } else { + return isString(input) ? "" : []; + } + }; +} + +/** + * @ngdoc filter + * @name orderBy + * @kind function + * + * @description + * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically + * for strings and numerically for numbers. Note: if you notice numbers are not being sorted + * correctly, make sure they are actually being saved as numbers and not strings. + * + * @param {Array} array The array to sort. + * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be + * used by the comparator to determine the order of elements. + * + * Can be one of: + * + * - `function`: Getter function. The result of this function will be sorted using the + * `<`, `=`, `>` operator. + * - `string`: An Angular expression. The result of this expression is used to compare elements + * (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by + * 3 first characters of a property called `name`). The result of a constant expression + * is interpreted as a property name to be used in comparisons (for example `"special name"` + * to sort object by the value of their `special name` property). An expression can be + * optionally prefixed with `+` or `-` to control ascending or descending sort order + * (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array + * element itself is used to compare where sorting. + * - `Array`: An array of function or string predicates. The first predicate in the array + * is used for sorting, but when two items are equivalent, the next predicate is used. + * + * If the predicate is missing or empty then it defaults to `'+'`. + * + * @param {boolean=} reverse Reverse the order of the array. + * @returns {Array} Sorted copy of the source array. + * + * @example + + + +
    +
    Sorting predicate = {{predicate}}; reverse = {{reverse}}
    +
    + [ unsorted ] + + + + + + + + + + + +
    Name + (^)Phone NumberAge
    {{friend.name}}{{friend.phone}}{{friend.age}}
    +
    +
    +
    + * + * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the + * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the + * desired parameters. + * + * Example: + * + * @example + + +
    + + + + + + + + + + + +
    Name + (^)Phone NumberAge
    {{friend.name}}{{friend.phone}}{{friend.age}}
    +
    +
    + + + angular.module('orderByExample', []) + .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) { + var orderBy = $filter('orderBy'); + $scope.friends = [ + { name: 'John', phone: '555-1212', age: 10 }, + { name: 'Mary', phone: '555-9876', age: 19 }, + { name: 'Mike', phone: '555-4321', age: 21 }, + { name: 'Adam', phone: '555-5678', age: 35 }, + { name: 'Julie', phone: '555-8765', age: 29 } + ]; + $scope.order = function(predicate, reverse) { + $scope.friends = orderBy($scope.friends, predicate, reverse); + }; + $scope.order('-age',false); + }]); + +
    + */ +orderByFilter.$inject = ['$parse']; +function orderByFilter($parse) { + return function(array, sortPredicate, reverseOrder) { + if (!(isArrayLike(array))) return array; + sortPredicate = isArray(sortPredicate) ? sortPredicate : [sortPredicate]; + if (sortPredicate.length === 0) { sortPredicate = ['+']; } + sortPredicate = sortPredicate.map(function(predicate) { + var descending = false, get = predicate || identity; + if (isString(predicate)) { + if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) { + descending = predicate.charAt(0) == '-'; + predicate = predicate.substring(1); + } + if (predicate === '') { + // Effectively no predicate was passed so we compare identity + return reverseComparator(compare, descending); + } + get = $parse(predicate); + if (get.constant) { + var key = get(); + return reverseComparator(function(a, b) { + return compare(a[key], b[key]); + }, descending); + } + } + return reverseComparator(function(a, b) { + return compare(get(a),get(b)); + }, descending); + }); + return slice.call(array).sort(reverseComparator(comparator, reverseOrder)); + + function comparator(o1, o2) { + for (var i = 0; i < sortPredicate.length; i++) { + var comp = sortPredicate[i](o1, o2); + if (comp !== 0) return comp; + } + return 0; + } + function reverseComparator(comp, descending) { + return descending + ? function(a, b) {return comp(b,a);} + : comp; + } + + function isPrimitive(value) { + switch (typeof value) { + case 'number': /* falls through */ + case 'boolean': /* falls through */ + case 'string': + return true; + default: + return false; + } + } + + function objectToString(value) { + if (value === null) return 'null'; + if (typeof value.valueOf === 'function') { + value = value.valueOf(); + if (isPrimitive(value)) return value; + } + if (typeof value.toString === 'function') { + value = value.toString(); + if (isPrimitive(value)) return value; + } + return ''; + } + + function compare(v1, v2) { + var t1 = typeof v1; + var t2 = typeof v2; + if (t1 === t2 && t1 === "object") { + v1 = objectToString(v1); + v2 = objectToString(v2); + } + if (t1 === t2) { + if (t1 === "string") { + v1 = v1.toLowerCase(); + v2 = v2.toLowerCase(); + } + if (v1 === v2) return 0; + return v1 < v2 ? -1 : 1; + } else { + return t1 < t2 ? -1 : 1; + } + } + }; +} + +function ngDirective(directive) { + if (isFunction(directive)) { + directive = { + link: directive + }; + } + directive.restrict = directive.restrict || 'AC'; + return valueFn(directive); +} + +/** + * @ngdoc directive + * @name a + * @restrict E + * + * @description + * Modifies the default behavior of the html A tag so that the default action is prevented when + * the href attribute is empty. + * + * This change permits the easy creation of action links with the `ngClick` directive + * without changing the location or causing page reloads, e.g.: + * `Add Item` + */ +var htmlAnchorDirective = valueFn({ + restrict: 'E', + compile: function(element, attr) { + if (!attr.href && !attr.xlinkHref && !attr.name) { + return function(scope, element) { + // If the linked element is not an anchor tag anymore, do nothing + if (element[0].nodeName.toLowerCase() !== 'a') return; + + // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute. + var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ? + 'xlink:href' : 'href'; + element.on('click', function(event) { + // if we have no href url, then don't navigate anywhere. + if (!element.attr(href)) { + event.preventDefault(); + } + }); + }; + } + } +}); + +/** + * @ngdoc directive + * @name ngHref + * @restrict A + * @priority 99 + * + * @description + * Using Angular markup like `{{hash}}` in an href attribute will + * make the link go to the wrong URL if the user clicks it before + * Angular has a chance to replace the `{{hash}}` markup with its + * value. Until Angular replaces the markup the link will be broken + * and will most likely return a 404 error. The `ngHref` directive + * solves this problem. + * + * The wrong way to write it: + * ```html + * link1 + * ``` + * + * The correct way to write it: + * ```html + * link1 + * ``` + * + * @element A + * @param {template} ngHref any string which can contain `{{}}` markup. + * + * @example + * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes + * in links and their different behaviors: + + +
    + link 1 (link, don't reload)
    + link 2 (link, don't reload)
    + link 3 (link, reload!)
    + anchor (link, don't reload)
    + anchor (no link)
    + link (link, change location) +
    + + it('should execute ng-click but not reload when href without value', function() { + element(by.id('link-1')).click(); + expect(element(by.model('value')).getAttribute('value')).toEqual('1'); + expect(element(by.id('link-1')).getAttribute('href')).toBe(''); + }); + + it('should execute ng-click but not reload when href empty string', function() { + element(by.id('link-2')).click(); + expect(element(by.model('value')).getAttribute('value')).toEqual('2'); + expect(element(by.id('link-2')).getAttribute('href')).toBe(''); + }); + + it('should execute ng-click and change url when ng-href specified', function() { + expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/); + + element(by.id('link-3')).click(); + + // At this point, we navigate away from an Angular page, so we need + // to use browser.driver to get the base webdriver. + + browser.wait(function() { + return browser.driver.getCurrentUrl().then(function(url) { + return url.match(/\/123$/); + }); + }, 5000, 'page should navigate to /123'); + }); + + xit('should execute ng-click but not reload when href empty string and name specified', function() { + element(by.id('link-4')).click(); + expect(element(by.model('value')).getAttribute('value')).toEqual('4'); + expect(element(by.id('link-4')).getAttribute('href')).toBe(''); + }); + + it('should execute ng-click but not reload when no href but name specified', function() { + element(by.id('link-5')).click(); + expect(element(by.model('value')).getAttribute('value')).toEqual('5'); + expect(element(by.id('link-5')).getAttribute('href')).toBe(null); + }); + + it('should only change url when only ng-href', function() { + element(by.model('value')).clear(); + element(by.model('value')).sendKeys('6'); + expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/); + + element(by.id('link-6')).click(); + + // At this point, we navigate away from an Angular page, so we need + // to use browser.driver to get the base webdriver. + browser.wait(function() { + return browser.driver.getCurrentUrl().then(function(url) { + return url.match(/\/6$/); + }); + }, 5000, 'page should navigate to /6'); + }); + +
    + */ + +/** + * @ngdoc directive + * @name ngSrc + * @restrict A + * @priority 99 + * + * @description + * Using Angular markup like `{{hash}}` in a `src` attribute doesn't + * work right: The browser will fetch from the URL with the literal + * text `{{hash}}` until Angular replaces the expression inside + * `{{hash}}`. The `ngSrc` directive solves this problem. + * + * The buggy way to write it: + * ```html + * + * ``` + * + * The correct way to write it: + * ```html + * + * ``` + * + * @element IMG + * @param {template} ngSrc any string which can contain `{{}}` markup. + */ + +/** + * @ngdoc directive + * @name ngSrcset + * @restrict A + * @priority 99 + * + * @description + * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't + * work right: The browser will fetch from the URL with the literal + * text `{{hash}}` until Angular replaces the expression inside + * `{{hash}}`. The `ngSrcset` directive solves this problem. + * + * The buggy way to write it: + * ```html + * + * ``` + * + * The correct way to write it: + * ```html + * + * ``` + * + * @element IMG + * @param {template} ngSrcset any string which can contain `{{}}` markup. + */ + +/** + * @ngdoc directive + * @name ngDisabled + * @restrict A + * @priority 100 + * + * @description + * + * We shouldn't do this, because it will make the button enabled on Chrome/Firefox but not on IE8 and older IEs: + * ```html + *
    + * + *
    + * ``` + * + * The HTML specification does not require browsers to preserve the values of boolean attributes + * such as disabled. (Their presence means true and their absence means false.) + * If we put an Angular interpolation expression into such an attribute then the + * binding information would be lost when the browser removes the attribute. + * The `ngDisabled` directive solves this problem for the `disabled` attribute. + * This complementary directive is not removed by the browser and so provides + * a permanent reliable place to store the binding information. + * + * @example + + + Click me to toggle:
    + +
    + + it('should toggle button', function() { + expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy(); + element(by.model('checked')).click(); + expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy(); + }); + +
    + * + * @element INPUT + * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy, + * then special attribute "disabled" will be set on the element + */ + + +/** + * @ngdoc directive + * @name ngChecked + * @restrict A + * @priority 100 + * + * @description + * The HTML specification does not require browsers to preserve the values of boolean attributes + * such as checked. (Their presence means true and their absence means false.) + * If we put an Angular interpolation expression into such an attribute then the + * binding information would be lost when the browser removes the attribute. + * The `ngChecked` directive solves this problem for the `checked` attribute. + * This complementary directive is not removed by the browser and so provides + * a permanent reliable place to store the binding information. + * @example + + + Check me to check both:
    + +
    + + it('should check both checkBoxes', function() { + expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy(); + element(by.model('master')).click(); + expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy(); + }); + +
    + * + * @element INPUT + * @param {expression} ngChecked If the {@link guide/expression expression} is truthy, + * then special attribute "checked" will be set on the element + */ + + +/** + * @ngdoc directive + * @name ngReadonly + * @restrict A + * @priority 100 + * + * @description + * The HTML specification does not require browsers to preserve the values of boolean attributes + * such as readonly. (Their presence means true and their absence means false.) + * If we put an Angular interpolation expression into such an attribute then the + * binding information would be lost when the browser removes the attribute. + * The `ngReadonly` directive solves this problem for the `readonly` attribute. + * This complementary directive is not removed by the browser and so provides + * a permanent reliable place to store the binding information. + * @example + + + Check me to make text readonly:
    + +
    + + it('should toggle readonly attr', function() { + expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy(); + element(by.model('checked')).click(); + expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy(); + }); + +
    + * + * @element INPUT + * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy, + * then special attribute "readonly" will be set on the element + */ + + +/** + * @ngdoc directive + * @name ngSelected + * @restrict A + * @priority 100 + * + * @description + * The HTML specification does not require browsers to preserve the values of boolean attributes + * such as selected. (Their presence means true and their absence means false.) + * If we put an Angular interpolation expression into such an attribute then the + * binding information would be lost when the browser removes the attribute. + * The `ngSelected` directive solves this problem for the `selected` attribute. + * This complementary directive is not removed by the browser and so provides + * a permanent reliable place to store the binding information. + * + * @example + + + Check me to select:
    + +
    + + it('should select Greetings!', function() { + expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy(); + element(by.model('selected')).click(); + expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy(); + }); + +
    + * + * @element OPTION + * @param {expression} ngSelected If the {@link guide/expression expression} is truthy, + * then special attribute "selected" will be set on the element + */ + +/** + * @ngdoc directive + * @name ngOpen + * @restrict A + * @priority 100 + * + * @description + * The HTML specification does not require browsers to preserve the values of boolean attributes + * such as open. (Their presence means true and their absence means false.) + * If we put an Angular interpolation expression into such an attribute then the + * binding information would be lost when the browser removes the attribute. + * The `ngOpen` directive solves this problem for the `open` attribute. + * This complementary directive is not removed by the browser and so provides + * a permanent reliable place to store the binding information. + * @example + + + Check me check multiple:
    +
    + Show/Hide me +
    +
    + + it('should toggle open', function() { + expect(element(by.id('details')).getAttribute('open')).toBeFalsy(); + element(by.model('open')).click(); + expect(element(by.id('details')).getAttribute('open')).toBeTruthy(); + }); + +
    + * + * @element DETAILS + * @param {expression} ngOpen If the {@link guide/expression expression} is truthy, + * then special attribute "open" will be set on the element + */ + +var ngAttributeAliasDirectives = {}; + + +// boolean attrs are evaluated +forEach(BOOLEAN_ATTR, function(propName, attrName) { + // binding to multiple is not supported + if (propName == "multiple") return; + + var normalized = directiveNormalize('ng-' + attrName); + ngAttributeAliasDirectives[normalized] = function() { + return { + restrict: 'A', + priority: 100, + link: function(scope, element, attr) { + scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) { + attr.$set(attrName, !!value); + }); + } + }; + }; +}); + +// aliased input attrs are evaluated +forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) { + ngAttributeAliasDirectives[ngAttr] = function() { + return { + priority: 100, + link: function(scope, element, attr) { + //special case ngPattern when a literal regular expression value + //is used as the expression (this way we don't have to watch anything). + if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") { + var match = attr.ngPattern.match(REGEX_STRING_REGEXP); + if (match) { + attr.$set("ngPattern", new RegExp(match[1], match[2])); + return; + } + } + + scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) { + attr.$set(ngAttr, value); + }); + } + }; + }; +}); + +// ng-src, ng-srcset, ng-href are interpolated +forEach(['src', 'srcset', 'href'], function(attrName) { + var normalized = directiveNormalize('ng-' + attrName); + ngAttributeAliasDirectives[normalized] = function() { + return { + priority: 99, // it needs to run after the attributes are interpolated + link: function(scope, element, attr) { + var propName = attrName, + name = attrName; + + if (attrName === 'href' && + toString.call(element.prop('href')) === '[object SVGAnimatedString]') { + name = 'xlinkHref'; + attr.$attr[name] = 'xlink:href'; + propName = null; + } + + attr.$observe(normalized, function(value) { + if (!value) { + if (attrName === 'href') { + attr.$set(name, null); + } + return; + } + + attr.$set(name, value); + + // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist + // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need + // to set the property as well to achieve the desired effect. + // we use attr[attrName] value since $set can sanitize the url. + if (msie && propName) element.prop(propName, attr[name]); + }); + } + }; + }; +}); + +/* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true + */ +var nullFormCtrl = { + $addControl: noop, + $$renameControl: nullFormRenameControl, + $removeControl: noop, + $setValidity: noop, + $setDirty: noop, + $setPristine: noop, + $setSubmitted: noop +}, +SUBMITTED_CLASS = 'ng-submitted'; + +function nullFormRenameControl(control, name) { + control.$name = name; +} + +/** + * @ngdoc type + * @name form.FormController + * + * @property {boolean} $pristine True if user has not interacted with the form yet. + * @property {boolean} $dirty True if user has already interacted with the form. + * @property {boolean} $valid True if all of the containing forms and controls are valid. + * @property {boolean} $invalid True if at least one containing control or form is invalid. + * @property {boolean} $submitted True if user has submitted the form even if its invalid. + * + * @property {Object} $error Is an object hash, containing references to controls or + * forms with failing validators, where: + * + * - keys are validation tokens (error names), + * - values are arrays of controls or forms that have a failing validator for given error name. + * + * Built-in validation tokens: + * + * - `email` + * - `max` + * - `maxlength` + * - `min` + * - `minlength` + * - `number` + * - `pattern` + * - `required` + * - `url` + * - `date` + * - `datetimelocal` + * - `time` + * - `week` + * - `month` + * + * @description + * `FormController` keeps track of all its controls and nested forms as well as the state of them, + * such as being valid/invalid or dirty/pristine. + * + * Each {@link ng.directive:form form} directive creates an instance + * of `FormController`. + * + */ +//asks for $scope to fool the BC controller module +FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate']; +function FormController(element, attrs, $scope, $animate, $interpolate) { + var form = this, + controls = []; + + var parentForm = form.$$parentForm = element.parent().controller('form') || nullFormCtrl; + + // init state + form.$error = {}; + form.$$success = {}; + form.$pending = undefined; + form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope); + form.$dirty = false; + form.$pristine = true; + form.$valid = true; + form.$invalid = false; + form.$submitted = false; + + parentForm.$addControl(form); + + /** + * @ngdoc method + * @name form.FormController#$rollbackViewValue + * + * @description + * Rollback all form controls pending updates to the `$modelValue`. + * + * Updates may be pending by a debounced event or because the input is waiting for a some future + * event defined in `ng-model-options`. This method is typically needed by the reset button of + * a form that uses `ng-model-options` to pend updates. + */ + form.$rollbackViewValue = function() { + forEach(controls, function(control) { + control.$rollbackViewValue(); + }); + }; + + /** + * @ngdoc method + * @name form.FormController#$commitViewValue + * + * @description + * Commit all form controls pending updates to the `$modelValue`. + * + * Updates may be pending by a debounced event or because the input is waiting for a some future + * event defined in `ng-model-options`. This method is rarely needed as `NgModelController` + * usually handles calling this in response to input events. + */ + form.$commitViewValue = function() { + forEach(controls, function(control) { + control.$commitViewValue(); + }); + }; + + /** + * @ngdoc method + * @name form.FormController#$addControl + * + * @description + * Register a control with the form. + * + * Input elements using ngModelController do this automatically when they are linked. + */ + form.$addControl = function(control) { + // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored + // and not added to the scope. Now we throw an error. + assertNotHasOwnProperty(control.$name, 'input'); + controls.push(control); + + if (control.$name) { + form[control.$name] = control; + } + }; + + // Private API: rename a form control + form.$$renameControl = function(control, newName) { + var oldName = control.$name; + + if (form[oldName] === control) { + delete form[oldName]; + } + form[newName] = control; + control.$name = newName; + }; + + /** + * @ngdoc method + * @name form.FormController#$removeControl + * + * @description + * Deregister a control from the form. + * + * Input elements using ngModelController do this automatically when they are destroyed. + */ + form.$removeControl = function(control) { + if (control.$name && form[control.$name] === control) { + delete form[control.$name]; + } + forEach(form.$pending, function(value, name) { + form.$setValidity(name, null, control); + }); + forEach(form.$error, function(value, name) { + form.$setValidity(name, null, control); + }); + forEach(form.$$success, function(value, name) { + form.$setValidity(name, null, control); + }); + + arrayRemove(controls, control); + }; + + + /** + * @ngdoc method + * @name form.FormController#$setValidity + * + * @description + * Sets the validity of a form control. + * + * This method will also propagate to parent forms. + */ + addSetValidityMethod({ + ctrl: this, + $element: element, + set: function(object, property, controller) { + var list = object[property]; + if (!list) { + object[property] = [controller]; + } else { + var index = list.indexOf(controller); + if (index === -1) { + list.push(controller); + } + } + }, + unset: function(object, property, controller) { + var list = object[property]; + if (!list) { + return; + } + arrayRemove(list, controller); + if (list.length === 0) { + delete object[property]; + } + }, + parentForm: parentForm, + $animate: $animate + }); + + /** + * @ngdoc method + * @name form.FormController#$setDirty + * + * @description + * Sets the form to a dirty state. + * + * This method can be called to add the 'ng-dirty' class and set the form to a dirty + * state (ng-dirty class). This method will also propagate to parent forms. + */ + form.$setDirty = function() { + $animate.removeClass(element, PRISTINE_CLASS); + $animate.addClass(element, DIRTY_CLASS); + form.$dirty = true; + form.$pristine = false; + parentForm.$setDirty(); + }; + + /** + * @ngdoc method + * @name form.FormController#$setPristine + * + * @description + * Sets the form to its pristine state. + * + * This method can be called to remove the 'ng-dirty' class and set the form to its pristine + * state (ng-pristine class). This method will also propagate to all the controls contained + * in this form. + * + * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after + * saving or resetting it. + */ + form.$setPristine = function() { + $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS); + form.$dirty = false; + form.$pristine = true; + form.$submitted = false; + forEach(controls, function(control) { + control.$setPristine(); + }); + }; + + /** + * @ngdoc method + * @name form.FormController#$setUntouched + * + * @description + * Sets the form to its untouched state. + * + * This method can be called to remove the 'ng-touched' class and set the form controls to their + * untouched state (ng-untouched class). + * + * Setting a form controls back to their untouched state is often useful when setting the form + * back to its pristine state. + */ + form.$setUntouched = function() { + forEach(controls, function(control) { + control.$setUntouched(); + }); + }; + + /** + * @ngdoc method + * @name form.FormController#$setSubmitted + * + * @description + * Sets the form to its submitted state. + */ + form.$setSubmitted = function() { + $animate.addClass(element, SUBMITTED_CLASS); + form.$submitted = true; + parentForm.$setSubmitted(); + }; +} + +/** + * @ngdoc directive + * @name ngForm + * @restrict EAC + * + * @description + * Nestable alias of {@link ng.directive:form `form`} directive. HTML + * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a + * sub-group of controls needs to be determined. + * + * Note: the purpose of `ngForm` is to group controls, + * but not to be a replacement for the `
    ` tag with all of its capabilities + * (e.g. posting to the server, ...). + * + * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into + * related scope, under this name. + * + */ + + /** + * @ngdoc directive + * @name form + * @restrict E + * + * @description + * Directive that instantiates + * {@link form.FormController FormController}. + * + * If the `name` attribute is specified, the form controller is published onto the current scope under + * this name. + * + * # Alias: {@link ng.directive:ngForm `ngForm`} + * + * In Angular forms can be nested. This means that the outer form is valid when all of the child + * forms are valid as well. However, browsers do not allow nesting of `` elements, so + * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to + * `` but can be nested. This allows you to have nested forms, which is very useful when + * using Angular validation directives in forms that are dynamically generated using the + * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name` + * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an + * `ngForm` directive and nest these in an outer `form` element. + * + * + * # CSS classes + * - `ng-valid` is set if the form is valid. + * - `ng-invalid` is set if the form is invalid. + * - `ng-pristine` is set if the form is pristine. + * - `ng-dirty` is set if the form is dirty. + * - `ng-submitted` is set if the form was submitted. + * + * Keep in mind that ngAnimate can detect each of these classes when added and removed. + * + * + * # Submitting a form and preventing the default action + * + * Since the role of forms in client-side Angular applications is different than in classical + * roundtrip apps, it is desirable for the browser not to translate the form submission into a full + * page reload that sends the data to the server. Instead some javascript logic should be triggered + * to handle the form submission in an application-specific way. + * + * For this reason, Angular prevents the default action (form submission to the server) unless the + * `` element has an `action` attribute specified. + * + * You can use one of the following two ways to specify what javascript method should be called when + * a form is submitted: + * + * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element + * - {@link ng.directive:ngClick ngClick} directive on the first + * button or input field of type submit (input[type=submit]) + * + * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit} + * or {@link ng.directive:ngClick ngClick} directives. + * This is because of the following form submission rules in the HTML specification: + * + * - If a form has only one input field then hitting enter in this field triggers form submit + * (`ngSubmit`) + * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter + * doesn't trigger submit + * - if a form has one or more input fields and one or more buttons or input[type=submit] then + * hitting enter in any of the input fields will trigger the click handler on the *first* button or + * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`) + * + * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is + * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit` + * to have access to the updated model. + * + * ## Animation Hooks + * + * Animations in ngForm are triggered when any of the associated CSS classes are added and removed. + * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any + * other validations that are performed within the form. Animations in ngForm are similar to how + * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well + * as JS animations. + * + * The following example shows a simple way to utilize CSS transitions to style a form element + * that has been rendered as invalid after it has been validated: + * + *
    + * //be sure to include ngAnimate as a module to hook into more
    + * //advanced animations
    + * .my-form {
    + *   transition:0.5s linear all;
    + *   background: white;
    + * }
    + * .my-form.ng-invalid {
    + *   background: red;
    + *   color:white;
    + * }
    + * 
    + * + * @example + + + + + + userType: + Required!
    + userType = {{userType}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    + +
    + + it('should initialize to model', function() { + var userType = element(by.binding('userType')); + var valid = element(by.binding('myForm.input.$valid')); + + expect(userType.getText()).toContain('guest'); + expect(valid.getText()).toContain('true'); + }); + + it('should be invalid if empty', function() { + var userType = element(by.binding('userType')); + var valid = element(by.binding('myForm.input.$valid')); + var userInput = element(by.model('userType')); + + userInput.clear(); + userInput.sendKeys(''); + + expect(userType.getText()).toEqual('userType ='); + expect(valid.getText()).toContain('false'); + }); + +
    + * + * @param {string=} name Name of the form. If specified, the form controller will be published into + * related scope, under this name. + */ +var formDirectiveFactory = function(isNgForm) { + return ['$timeout', function($timeout) { + var formDirective = { + name: 'form', + restrict: isNgForm ? 'EAC' : 'E', + controller: FormController, + compile: function ngFormCompile(formElement) { + // Setup initial state of the control + formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS); + + return { + pre: function ngFormPreLink(scope, formElement, attr, controller) { + // if `action` attr is not present on the form, prevent the default action (submission) + if (!('action' in attr)) { + // we can't use jq events because if a form is destroyed during submission the default + // action is not prevented. see #1238 + // + // IE 9 is not affected because it doesn't fire a submit event and try to do a full + // page reload if the form was destroyed by submission of the form via a click handler + // on a button in the form. Looks like an IE9 specific bug. + var handleFormSubmission = function(event) { + scope.$apply(function() { + controller.$commitViewValue(); + controller.$setSubmitted(); + }); + + event.preventDefault(); + }; + + addEventListenerFn(formElement[0], 'submit', handleFormSubmission); + + // unregister the preventDefault listener so that we don't not leak memory but in a + // way that will achieve the prevention of the default action. + formElement.on('$destroy', function() { + $timeout(function() { + removeEventListenerFn(formElement[0], 'submit', handleFormSubmission); + }, 0, false); + }); + } + + var parentFormCtrl = controller.$$parentForm, + alias = controller.$name; + + if (alias) { + setter(scope, null, alias, controller, alias); + attr.$observe(attr.name ? 'name' : 'ngForm', function(newValue) { + if (alias === newValue) return; + setter(scope, null, alias, undefined, alias); + alias = newValue; + setter(scope, null, alias, controller, alias); + parentFormCtrl.$$renameControl(controller, alias); + }); + } + formElement.on('$destroy', function() { + parentFormCtrl.$removeControl(controller); + if (alias) { + setter(scope, null, alias, undefined, alias); + } + extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards + }); + } + }; + } + }; + + return formDirective; + }]; +}; + +var formDirective = formDirectiveFactory(); +var ngFormDirective = formDirectiveFactory(true); + +/* global VALID_CLASS: false, + INVALID_CLASS: false, + PRISTINE_CLASS: false, + DIRTY_CLASS: false, + UNTOUCHED_CLASS: false, + TOUCHED_CLASS: false, + $ngModelMinErr: false, +*/ + +// Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231 +var ISO_DATE_REGEXP = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/; +var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/; +var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i; +var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/; +var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/; +var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/; +var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/; +var MONTH_REGEXP = /^(\d{4})-(\d\d)$/; +var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/; + +var inputType = { + + /** + * @ngdoc input + * @name input[text] + * + * @description + * Standard HTML text input with angular data binding, inherited by most of the `input` elements. + * + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Adds `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of + * any length. + * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string + * that contains the regular expression body that will be converted to a regular expression + * as in the ngPattern directive. + * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match + * a RegExp found by evaluating the Angular expression given in the attribute value. + * If the expression evaluates to a RegExp object then this is used directly. + * If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$` + * characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input. + * This parameter is ignored for input[type=password] controls, which will never trim the + * input. + * + * @example + + + +
    + Single word: + + Required! + + Single word only! + + text = {{example.text}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    +
    +
    + + var text = element(by.binding('example.text')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('example.text')); + + it('should initialize to model', function() { + expect(text.getText()).toContain('guest'); + expect(valid.getText()).toContain('true'); + }); + + it('should be invalid if empty', function() { + input.clear(); + input.sendKeys(''); + + expect(text.getText()).toEqual('text ='); + expect(valid.getText()).toContain('false'); + }); + + it('should be invalid if multi word', function() { + input.clear(); + input.sendKeys('hello world'); + + expect(valid.getText()).toContain('false'); + }); + +
    + */ + 'text': textInputType, + + /** + * @ngdoc input + * @name input[date] + * + * @description + * Input with date validation and transformation. In browsers that do not yet support + * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601 + * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many + * modern browsers do not yet support this input type, it is important to provide cues to users on the + * expected input format via a placeholder or label. + * + * The model must always be a Date object, otherwise Angular will throw an error. + * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. + * + * The timezone to be used to read/write the `Date` instance in the model can be defined using + * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a + * valid ISO date string (yyyy-MM-dd). + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be + * a valid ISO date string (yyyy-MM-dd). + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
    + Pick a date in 2013: + + + Required! + + Not a valid date! + value = {{example.value | date: "yyyy-MM-dd"}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    +
    +
    + + var value = element(by.binding('example.value | date: "yyyy-MM-dd"')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('example.value')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (see https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('2013-10-22'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('2015-01-01'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
    + */ + 'date': createDateInputType('date', DATE_REGEXP, + createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']), + 'yyyy-MM-dd'), + + /** + * @ngdoc input + * @name input[datetime-local] + * + * @description + * Input with datetime validation and transformation. In browsers that do not yet support + * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 + * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`. + * + * The model must always be a Date object, otherwise Angular will throw an error. + * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. + * + * The timezone to be used to read/write the `Date` instance in the model can be defined using + * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a + * valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be + * a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
    + Pick a date between in 2013: + + + Required! + + Not a valid date! + value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    +
    +
    + + var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('example.value')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('2010-12-28T14:57:00'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('2015-01-01T23:59:00'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
    + */ + 'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP, + createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']), + 'yyyy-MM-ddTHH:mm:ss.sss'), + + /** + * @ngdoc input + * @name input[time] + * + * @description + * Input with time validation and transformation. In browsers that do not yet support + * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 + * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a + * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`. + * + * The model must always be a Date object, otherwise Angular will throw an error. + * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. + * + * The timezone to be used to read/write the `Date` instance in the model can be defined using + * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a + * valid ISO time format (HH:mm:ss). + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be a + * valid ISO time format (HH:mm:ss). + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
    + Pick a between 8am and 5pm: + + + Required! + + Not a valid date! + value = {{example.value | date: "HH:mm:ss"}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    +
    +
    + + var value = element(by.binding('example.value | date: "HH:mm:ss"')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('example.value')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('14:57:00'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('23:59:00'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
    + */ + 'time': createDateInputType('time', TIME_REGEXP, + createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']), + 'HH:mm:ss.sss'), + + /** + * @ngdoc input + * @name input[week] + * + * @description + * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support + * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 + * week format (yyyy-W##), for example: `2013-W02`. + * + * The model must always be a Date object, otherwise Angular will throw an error. + * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. + * + * The timezone to be used to read/write the `Date` instance in the model can be defined using + * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a + * valid ISO week format (yyyy-W##). + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be + * a valid ISO week format (yyyy-W##). + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
    + Pick a date between in 2013: + + + Required! + + Not a valid date! + value = {{example.value | date: "yyyy-Www"}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    +
    +
    + + var value = element(by.binding('example.value | date: "yyyy-Www"')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('example.value')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('2013-W01'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('2015-W01'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
    + */ + 'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'), + + /** + * @ngdoc input + * @name input[month] + * + * @description + * Input with month validation and transformation. In browsers that do not yet support + * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 + * month format (yyyy-MM), for example: `2009-01`. + * + * The model must always be a Date object, otherwise Angular will throw an error. + * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. + * If the model is not set to the first of the month, the next view to model update will set it + * to the first of the month. + * + * The timezone to be used to read/write the `Date` instance in the model can be defined using + * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be + * a valid ISO month format (yyyy-MM). + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must + * be a valid ISO month format (yyyy-MM). + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
    + Pick a month in 2013: + + + Required! + + Not a valid month! + value = {{example.value | date: "yyyy-MM"}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    +
    +
    + + var value = element(by.binding('example.value | date: "yyyy-MM"')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('example.value')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('2013-10'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('2015-01'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
    + */ + 'month': createDateInputType('month', MONTH_REGEXP, + createDateParser(MONTH_REGEXP, ['yyyy', 'MM']), + 'yyyy-MM'), + + /** + * @ngdoc input + * @name input[number] + * + * @description + * Text input with number validation and transformation. Sets the `number` validation + * error if not a valid number. + * + * The model must always be a number, otherwise Angular will throw an error. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of + * any length. + * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string + * that contains the regular expression body that will be converted to a regular expression + * as in the ngPattern directive. + * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match + * a RegExp found by evaluating the Angular expression given in the attribute value. + * If the expression evaluates to a RegExp object then this is used directly. + * If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$` + * characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
    + Number: + + Required! + + Not valid number! + value = {{example.value}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    +
    +
    + + var value = element(by.binding('example.value')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('example.value')); + + it('should initialize to model', function() { + expect(value.getText()).toContain('12'); + expect(valid.getText()).toContain('true'); + }); + + it('should be invalid if empty', function() { + input.clear(); + input.sendKeys(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('false'); + }); + + it('should be invalid if over max', function() { + input.clear(); + input.sendKeys('123'); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('false'); + }); + +
    + */ + 'number': numberInputType, + + + /** + * @ngdoc input + * @name input[url] + * + * @description + * Text input with URL validation. Sets the `url` validation error key if the content is not a + * valid URL. + * + *
    + * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex + * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify + * the built-in validators (see the {@link guide/forms Forms guide}) + *
    + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of + * any length. + * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string + * that contains the regular expression body that will be converted to a regular expression + * as in the ngPattern directive. + * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match + * a RegExp found by evaluating the Angular expression given in the attribute value. + * If the expression evaluates to a RegExp object then this is used directly. + * If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$` + * characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
    + URL: + + Required! + + Not valid url! + text = {{url.text}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    + myForm.$error.url = {{!!myForm.$error.url}}
    +
    +
    + + var text = element(by.binding('url.text')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('url.text')); + + it('should initialize to model', function() { + expect(text.getText()).toContain('http://google.com'); + expect(valid.getText()).toContain('true'); + }); + + it('should be invalid if empty', function() { + input.clear(); + input.sendKeys(''); + + expect(text.getText()).toEqual('text ='); + expect(valid.getText()).toContain('false'); + }); + + it('should be invalid if not url', function() { + input.clear(); + input.sendKeys('box'); + + expect(valid.getText()).toContain('false'); + }); + +
    + */ + 'url': urlInputType, + + + /** + * @ngdoc input + * @name input[email] + * + * @description + * Text input with email validation. Sets the `email` validation error key if not a valid email + * address. + * + *
    + * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex + * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can + * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide}) + *
    + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of + * any length. + * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string + * that contains the regular expression body that will be converted to a regular expression + * as in the ngPattern directive. + * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match + * a RegExp found by evaluating the Angular expression given in the attribute value. + * If the expression evaluates to a RegExp object then this is used directly. + * If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$` + * characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
    + Email: + + Required! + + Not valid email! + text = {{email.text}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    + myForm.$error.email = {{!!myForm.$error.email}}
    +
    +
    + + var text = element(by.binding('email.text')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('email.text')); + + it('should initialize to model', function() { + expect(text.getText()).toContain('me@example.com'); + expect(valid.getText()).toContain('true'); + }); + + it('should be invalid if empty', function() { + input.clear(); + input.sendKeys(''); + expect(text.getText()).toEqual('text ='); + expect(valid.getText()).toContain('false'); + }); + + it('should be invalid if not email', function() { + input.clear(); + input.sendKeys('xxx'); + + expect(valid.getText()).toContain('false'); + }); + +
    + */ + 'email': emailInputType, + + + /** + * @ngdoc input + * @name input[radio] + * + * @description + * HTML radio button. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} value The value to which the expression should be set when selected. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * @param {string} ngValue Angular expression which sets the value to which the expression should + * be set when selected. + * + * @example + + + +
    + Red
    + Green
    + Blue
    + color = {{color.name | json}}
    +
    + Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`. +
    + + it('should change state', function() { + var color = element(by.binding('color.name')); + + expect(color.getText()).toContain('blue'); + + element.all(by.model('color.name')).get(0).click(); + + expect(color.getText()).toContain('red'); + }); + +
    + */ + 'radio': radioInputType, + + + /** + * @ngdoc input + * @name input[checkbox] + * + * @description + * HTML checkbox. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {expression=} ngTrueValue The value to which the expression should be set when selected. + * @param {expression=} ngFalseValue The value to which the expression should be set when not selected. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
    + Value1:
    + Value2:
    + value1 = {{checkboxModel.value1}}
    + value2 = {{checkboxModel.value2}}
    +
    +
    + + it('should change state', function() { + var value1 = element(by.binding('checkboxModel.value1')); + var value2 = element(by.binding('checkboxModel.value2')); + + expect(value1.getText()).toContain('true'); + expect(value2.getText()).toContain('YES'); + + element(by.model('checkboxModel.value1')).click(); + element(by.model('checkboxModel.value2')).click(); + + expect(value1.getText()).toContain('false'); + expect(value2.getText()).toContain('NO'); + }); + +
    + */ + 'checkbox': checkboxInputType, + + 'hidden': noop, + 'button': noop, + 'submit': noop, + 'reset': noop, + 'file': noop +}; + +function stringBasedInputType(ctrl) { + ctrl.$formatters.push(function(value) { + return ctrl.$isEmpty(value) ? value : value.toString(); + }); +} + +function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { + baseInputType(scope, element, attr, ctrl, $sniffer, $browser); + stringBasedInputType(ctrl); +} + +function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) { + var type = lowercase(element[0].type); + + // In composition mode, users are still inputing intermediate text buffer, + // hold the listener until composition is done. + // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent + if (!$sniffer.android) { + var composing = false; + + element.on('compositionstart', function(data) { + composing = true; + }); + + element.on('compositionend', function() { + composing = false; + listener(); + }); + } + + var listener = function(ev) { + if (timeout) { + $browser.defer.cancel(timeout); + timeout = null; + } + if (composing) return; + var value = element.val(), + event = ev && ev.type; + + // By default we will trim the value + // If the attribute ng-trim exists we will avoid trimming + // If input type is 'password', the value is never trimmed + if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) { + value = trim(value); + } + + // If a control is suffering from bad input (due to native validators), browsers discard its + // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the + // control's value is the same empty value twice in a row. + if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) { + ctrl.$setViewValue(value, event); + } + }; + + // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the + // input event on backspace, delete or cut + if ($sniffer.hasEvent('input')) { + element.on('input', listener); + } else { + var timeout; + + var deferListener = function(ev, input, origValue) { + if (!timeout) { + timeout = $browser.defer(function() { + timeout = null; + if (!input || input.value !== origValue) { + listener(ev); + } + }); + } + }; + + element.on('keydown', function(event) { + var key = event.keyCode; + + // ignore + // command modifiers arrows + if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return; + + deferListener(event, this, this.value); + }); + + // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it + if ($sniffer.hasEvent('paste')) { + element.on('paste cut', deferListener); + } + } + + // if user paste into input using mouse on older browser + // or form autocomplete on newer browser, we need "change" event to catch it + element.on('change', listener); + + ctrl.$render = function() { + element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue); + }; +} + +function weekParser(isoWeek, existingDate) { + if (isDate(isoWeek)) { + return isoWeek; + } + + if (isString(isoWeek)) { + WEEK_REGEXP.lastIndex = 0; + var parts = WEEK_REGEXP.exec(isoWeek); + if (parts) { + var year = +parts[1], + week = +parts[2], + hours = 0, + minutes = 0, + seconds = 0, + milliseconds = 0, + firstThurs = getFirstThursdayOfYear(year), + addDays = (week - 1) * 7; + + if (existingDate) { + hours = existingDate.getHours(); + minutes = existingDate.getMinutes(); + seconds = existingDate.getSeconds(); + milliseconds = existingDate.getMilliseconds(); + } + + return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds); + } + } + + return NaN; +} + +function createDateParser(regexp, mapping) { + return function(iso, date) { + var parts, map; + + if (isDate(iso)) { + return iso; + } + + if (isString(iso)) { + // When a date is JSON'ified to wraps itself inside of an extra + // set of double quotes. This makes the date parsing code unable + // to match the date string and parse it as a date. + if (iso.charAt(0) == '"' && iso.charAt(iso.length - 1) == '"') { + iso = iso.substring(1, iso.length - 1); + } + if (ISO_DATE_REGEXP.test(iso)) { + return new Date(iso); + } + regexp.lastIndex = 0; + parts = regexp.exec(iso); + + if (parts) { + parts.shift(); + if (date) { + map = { + yyyy: date.getFullYear(), + MM: date.getMonth() + 1, + dd: date.getDate(), + HH: date.getHours(), + mm: date.getMinutes(), + ss: date.getSeconds(), + sss: date.getMilliseconds() / 1000 + }; + } else { + map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 }; + } + + forEach(parts, function(part, index) { + if (index < mapping.length) { + map[mapping[index]] = +part; + } + }); + return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0); + } + } + + return NaN; + }; +} + +function createDateInputType(type, regexp, parseDate, format) { + return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) { + badInputChecker(scope, element, attr, ctrl); + baseInputType(scope, element, attr, ctrl, $sniffer, $browser); + var timezone = ctrl && ctrl.$options && ctrl.$options.timezone; + var previousDate; + + ctrl.$$parserName = type; + ctrl.$parsers.push(function(value) { + if (ctrl.$isEmpty(value)) return null; + if (regexp.test(value)) { + // Note: We cannot read ctrl.$modelValue, as there might be a different + // parser/formatter in the processing chain so that the model + // contains some different data format! + var parsedDate = parseDate(value, previousDate); + if (timezone === 'UTC') { + parsedDate.setMinutes(parsedDate.getMinutes() - parsedDate.getTimezoneOffset()); + } + return parsedDate; + } + return undefined; + }); + + ctrl.$formatters.push(function(value) { + if (value && !isDate(value)) { + throw $ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value); + } + if (isValidDate(value)) { + previousDate = value; + if (previousDate && timezone === 'UTC') { + var timezoneOffset = 60000 * previousDate.getTimezoneOffset(); + previousDate = new Date(previousDate.getTime() + timezoneOffset); + } + return $filter('date')(value, format, timezone); + } else { + previousDate = null; + return ''; + } + }); + + if (isDefined(attr.min) || attr.ngMin) { + var minVal; + ctrl.$validators.min = function(value) { + return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal; + }; + attr.$observe('min', function(val) { + minVal = parseObservedDateValue(val); + ctrl.$validate(); + }); + } + + if (isDefined(attr.max) || attr.ngMax) { + var maxVal; + ctrl.$validators.max = function(value) { + return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal; + }; + attr.$observe('max', function(val) { + maxVal = parseObservedDateValue(val); + ctrl.$validate(); + }); + } + + function isValidDate(value) { + // Invalid Date: getTime() returns NaN + return value && !(value.getTime && value.getTime() !== value.getTime()); + } + + function parseObservedDateValue(val) { + return isDefined(val) ? (isDate(val) ? val : parseDate(val)) : undefined; + } + }; +} + +function badInputChecker(scope, element, attr, ctrl) { + var node = element[0]; + var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity); + if (nativeValidation) { + ctrl.$parsers.push(function(value) { + var validity = element.prop(VALIDITY_STATE_PROPERTY) || {}; + // Detect bug in FF35 for input[email] (https://bugzilla.mozilla.org/show_bug.cgi?id=1064430): + // - also sets validity.badInput (should only be validity.typeMismatch). + // - see http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email) + // - can ignore this case as we can still read out the erroneous email... + return validity.badInput && !validity.typeMismatch ? undefined : value; + }); + } +} + +function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) { + badInputChecker(scope, element, attr, ctrl); + baseInputType(scope, element, attr, ctrl, $sniffer, $browser); + + ctrl.$$parserName = 'number'; + ctrl.$parsers.push(function(value) { + if (ctrl.$isEmpty(value)) return null; + if (NUMBER_REGEXP.test(value)) return parseFloat(value); + return undefined; + }); + + ctrl.$formatters.push(function(value) { + if (!ctrl.$isEmpty(value)) { + if (!isNumber(value)) { + throw $ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value); + } + value = value.toString(); + } + return value; + }); + + if (attr.min || attr.ngMin) { + var minVal; + ctrl.$validators.min = function(value) { + return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal; + }; + + attr.$observe('min', function(val) { + if (isDefined(val) && !isNumber(val)) { + val = parseFloat(val, 10); + } + minVal = isNumber(val) && !isNaN(val) ? val : undefined; + // TODO(matsko): implement validateLater to reduce number of validations + ctrl.$validate(); + }); + } + + if (attr.max || attr.ngMax) { + var maxVal; + ctrl.$validators.max = function(value) { + return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal; + }; + + attr.$observe('max', function(val) { + if (isDefined(val) && !isNumber(val)) { + val = parseFloat(val, 10); + } + maxVal = isNumber(val) && !isNaN(val) ? val : undefined; + // TODO(matsko): implement validateLater to reduce number of validations + ctrl.$validate(); + }); + } +} + +function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) { + // Note: no badInputChecker here by purpose as `url` is only a validation + // in browsers, i.e. we can always read out input.value even if it is not valid! + baseInputType(scope, element, attr, ctrl, $sniffer, $browser); + stringBasedInputType(ctrl); + + ctrl.$$parserName = 'url'; + ctrl.$validators.url = function(modelValue, viewValue) { + var value = modelValue || viewValue; + return ctrl.$isEmpty(value) || URL_REGEXP.test(value); + }; +} + +function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) { + // Note: no badInputChecker here by purpose as `url` is only a validation + // in browsers, i.e. we can always read out input.value even if it is not valid! + baseInputType(scope, element, attr, ctrl, $sniffer, $browser); + stringBasedInputType(ctrl); + + ctrl.$$parserName = 'email'; + ctrl.$validators.email = function(modelValue, viewValue) { + var value = modelValue || viewValue; + return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value); + }; +} + +function radioInputType(scope, element, attr, ctrl) { + // make the name unique, if not defined + if (isUndefined(attr.name)) { + element.attr('name', nextUid()); + } + + var listener = function(ev) { + if (element[0].checked) { + ctrl.$setViewValue(attr.value, ev && ev.type); + } + }; + + element.on('click', listener); + + ctrl.$render = function() { + var value = attr.value; + element[0].checked = (value == ctrl.$viewValue); + }; + + attr.$observe('value', ctrl.$render); +} + +function parseConstantExpr($parse, context, name, expression, fallback) { + var parseFn; + if (isDefined(expression)) { + parseFn = $parse(expression); + if (!parseFn.constant) { + throw minErr('ngModel')('constexpr', 'Expected constant expression for `{0}`, but saw ' + + '`{1}`.', name, expression); + } + return parseFn(context); + } + return fallback; +} + +function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) { + var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true); + var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false); + + var listener = function(ev) { + ctrl.$setViewValue(element[0].checked, ev && ev.type); + }; + + element.on('click', listener); + + ctrl.$render = function() { + element[0].checked = ctrl.$viewValue; + }; + + // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false` + // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert + // it to a boolean. + ctrl.$isEmpty = function(value) { + return value === false; + }; + + ctrl.$formatters.push(function(value) { + return equals(value, trueValue); + }); + + ctrl.$parsers.push(function(value) { + return value ? trueValue : falseValue; + }); +} + + +/** + * @ngdoc directive + * @name textarea + * @restrict E + * + * @description + * HTML textarea element control with angular data-binding. The data-binding and validation + * properties of this element are exactly the same as those of the + * {@link ng.directive:input input element}. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any + * length. + * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the + * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for + * patterns defined as scope expressions. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input. + */ + + +/** + * @ngdoc directive + * @name input + * @restrict E + * + * @description + * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding, + * input state control, and validation. + * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers. + * + *
    + * **Note:** Not every feature offered is available for all input types. + * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`. + *
    + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {boolean=} ngRequired Sets `required` attribute if set to true + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any + * length. + * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the + * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for + * patterns defined as scope expressions. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input. + * This parameter is ignored for input[type=password] controls, which will never trim the + * input. + * + * @example + + + +
    +
    + User name: + + Required!
    + Last name: + + Too short! + + Too long!
    +
    +
    + user = {{user}}
    + myForm.userName.$valid = {{myForm.userName.$valid}}
    + myForm.userName.$error = {{myForm.userName.$error}}
    + myForm.lastName.$valid = {{myForm.lastName.$valid}}
    + myForm.lastName.$error = {{myForm.lastName.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    + myForm.$error.minlength = {{!!myForm.$error.minlength}}
    + myForm.$error.maxlength = {{!!myForm.$error.maxlength}}
    +
    +
    + + var user = element(by.exactBinding('user')); + var userNameValid = element(by.binding('myForm.userName.$valid')); + var lastNameValid = element(by.binding('myForm.lastName.$valid')); + var lastNameError = element(by.binding('myForm.lastName.$error')); + var formValid = element(by.binding('myForm.$valid')); + var userNameInput = element(by.model('user.name')); + var userLastInput = element(by.model('user.last')); + + it('should initialize to model', function() { + expect(user.getText()).toContain('{"name":"guest","last":"visitor"}'); + expect(userNameValid.getText()).toContain('true'); + expect(formValid.getText()).toContain('true'); + }); + + it('should be invalid if empty when required', function() { + userNameInput.clear(); + userNameInput.sendKeys(''); + + expect(user.getText()).toContain('{"last":"visitor"}'); + expect(userNameValid.getText()).toContain('false'); + expect(formValid.getText()).toContain('false'); + }); + + it('should be valid if empty when min length is set', function() { + userLastInput.clear(); + userLastInput.sendKeys(''); + + expect(user.getText()).toContain('{"name":"guest","last":""}'); + expect(lastNameValid.getText()).toContain('true'); + expect(formValid.getText()).toContain('true'); + }); + + it('should be invalid if less than required min length', function() { + userLastInput.clear(); + userLastInput.sendKeys('xx'); + + expect(user.getText()).toContain('{"name":"guest"}'); + expect(lastNameValid.getText()).toContain('false'); + expect(lastNameError.getText()).toContain('minlength'); + expect(formValid.getText()).toContain('false'); + }); + + it('should be invalid if longer than max length', function() { + userLastInput.clear(); + userLastInput.sendKeys('some ridiculously long name'); + + expect(user.getText()).toContain('{"name":"guest"}'); + expect(lastNameValid.getText()).toContain('false'); + expect(lastNameError.getText()).toContain('maxlength'); + expect(formValid.getText()).toContain('false'); + }); + +
    + */ +var inputDirective = ['$browser', '$sniffer', '$filter', '$parse', + function($browser, $sniffer, $filter, $parse) { + return { + restrict: 'E', + require: ['?ngModel'], + link: { + pre: function(scope, element, attr, ctrls) { + if (ctrls[0]) { + (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer, + $browser, $filter, $parse); + } + } + } + }; +}]; + + + +var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/; +/** + * @ngdoc directive + * @name ngValue + * + * @description + * Binds the given expression to the value of `
    + + it('should load template defined inside script tag', function() { + element(by.css('#tpl-link')).click(); + expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/); + }); + + + */ +var scriptDirective = ['$templateCache', function($templateCache) { + return { + restrict: 'E', + terminal: true, + compile: function(element, attr) { + if (attr.type == 'text/ng-template') { + var templateUrl = attr.id, + text = element[0].text; + + $templateCache.put(templateUrl, text); + } + } + }; +}]; + +var ngOptionsMinErr = minErr('ngOptions'); +/** + * @ngdoc directive + * @name select + * @restrict E + * + * @description + * HTML `SELECT` element with angular data-binding. + * + * # `ngOptions` + * + * The `ngOptions` attribute can be used to dynamically generate a list of `