diff --git a/pom.xml b/pom.xml index 66a985877..7a5b6c456 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,7 @@ 2.3.2 2.7.0 1.11.3 + 3.17 @@ -83,13 +84,6 @@ spring-boot-starter-thymeleaf - - - org.springframework.boot - spring-boot-devtools - true - - net.sourceforge.nekohtml @@ -238,14 +232,25 @@ springfox-swagger-ui ${swagger.version} - org.jsoup jsoup ${jsoup.version} - + + + + org.apache.poi + poi + ${poi.version} + + + + org.apache.poi + poi-ooxml + ${poi.version} + @@ -255,7 +260,7 @@ org.springframework.boot spring-boot-maven-plugin - true + true diff --git a/sql/ry_20180604.sql b/sql/ry_20180604.sql index 61e05976c..d2247b21f 100644 --- a/sql/ry_20180604.sql +++ b/sql/ry_20180604.sql @@ -171,68 +171,69 @@ insert into sys_menu values('22', '用户删除', '4', '4', '#', 'F', '0', 'sy insert into sys_menu values('23', '用户保存', '4', '5', '#', 'F', '0', 'system:user:save', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); insert into sys_menu values('24', '批量删除', '4', '6', '#', 'F', '0', 'system:user:batchRemove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); insert into sys_menu values('25', '重置密码', '4', '7', '#', 'F', '0', 'system:user:resetPwd', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('26', '批量新增', '4', '8', '#', 'F', '0', 'system:user:batchAdd', '#', 'admin', '2018-06-02 11-33-00', 'ry', '2018-06-02 11-33-00', ''); -- 角色管理按钮 -insert into sys_menu values('26', '角色查询', '5', '1', '#', 'F', '0', 'system:role:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('27', '角色新增', '5', '2', '#', 'F', '0', 'system:role:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('28', '角色修改', '5', '3', '#', 'F', '0', 'system:role:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('29', '角色删除', '5', '4', '#', 'F', '0', 'system:role:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('30', '角色保存', '5', '5', '#', 'F', '0', 'system:role:save', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('31', '批量删除', '5', '6', '#', 'F', '0', 'system:role:batchRemove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('27', '角色查询', '5', '1', '#', 'F', '0', 'system:role:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('28', '角色新增', '5', '2', '#', 'F', '0', 'system:role:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('29', '角色修改', '5', '3', '#', 'F', '0', 'system:role:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('30', '角色删除', '5', '4', '#', 'F', '0', 'system:role:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('31', '角色保存', '5', '5', '#', 'F', '0', 'system:role:save', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('32', '批量删除', '5', '6', '#', 'F', '0', 'system:role:batchRemove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -- 菜单管理按钮 -insert into sys_menu values('32', '菜单查询', '6', '1', '#', 'F', '0', 'system:menu:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('33', '菜单新增', '6', '2', '#', 'F', '0', 'system:menu:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('34', '菜单修改', '6', '3', '#', 'F', '0', 'system:menu:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('35', '菜单删除', '6', '4', '#', 'F', '0', 'system:menu:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('36', '菜单保存', '6', '5', '#', 'F', '0', 'system:menu:save', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('33', '菜单查询', '6', '1', '#', 'F', '0', 'system:menu:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('34', '菜单新增', '6', '2', '#', 'F', '0', 'system:menu:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('35', '菜单修改', '6', '3', '#', 'F', '0', 'system:menu:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('36', '菜单删除', '6', '4', '#', 'F', '0', 'system:menu:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('37', '菜单保存', '6', '5', '#', 'F', '0', 'system:menu:save', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -- 部门管理按钮 -insert into sys_menu values('37', '部门查询', '7', '1', '#', 'F', '0', 'system:dept:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('38', '部门新增', '7', '2', '#', 'F', '0', 'system:dept:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('39', '部门修改', '7', '3', '#', 'F', '0', 'system:dept:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('40', '部门删除', '7', '4', '#', 'F', '0', 'system:dept:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('41', '部门保存', '7', '5', '#', 'F', '0', 'system:dept:save', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('38', '部门查询', '7', '1', '#', 'F', '0', 'system:dept:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('39', '部门新增', '7', '2', '#', 'F', '0', 'system:dept:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('40', '部门修改', '7', '3', '#', 'F', '0', 'system:dept:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('41', '部门删除', '7', '4', '#', 'F', '0', 'system:dept:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('42', '部门保存', '7', '5', '#', 'F', '0', 'system:dept:save', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -- 岗位管理按钮 -insert into sys_menu values('42', '岗位查询', '8', '1', '#', 'F', '0', 'system:post:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('43', '岗位新增', '8', '2', '#', 'F', '0', 'system:post:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('44', '岗位修改', '8', '3', '#', 'F', '0', 'system:post:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('45', '岗位删除', '8', '4', '#', 'F', '0', 'system:post:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('46', '岗位保存', '8', '5', '#', 'F', '0', 'system:post:save', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('47', '批量删除', '8', '6', '#', 'F', '0', 'system:post:batchRemove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('43', '岗位查询', '8', '1', '#', 'F', '0', 'system:post:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('44', '岗位新增', '8', '2', '#', 'F', '0', 'system:post:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('45', '岗位修改', '8', '3', '#', 'F', '0', 'system:post:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('46', '岗位删除', '8', '4', '#', 'F', '0', 'system:post:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('47', '岗位保存', '8', '5', '#', 'F', '0', 'system:post:save', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('48', '批量删除', '8', '6', '#', 'F', '0', 'system:post:batchRemove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -- 字典管理按钮 -insert into sys_menu values('48', '字典查询', '9', '1', '#', 'F', '0', 'system:dict:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('49', '字典新增', '9', '2', '#', 'F', '0', 'system:dict:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('50', '字典修改', '9', '3', '#', 'F', '0', 'system:dict:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('51', '字典删除', '9', '4', '#', 'F', '0', 'system:dict:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('52', '字典保存', '9', '5', '#', 'F', '0', 'system:dict:save', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('53', '批量删除', '9', '6', '#', 'F', '0', 'system:dict:batchRemove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('49', '字典查询', '9', '1', '#', 'F', '0', 'system:dict:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('50', '字典新增', '9', '2', '#', 'F', '0', 'system:dict:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('51', '字典修改', '9', '3', '#', 'F', '0', 'system:dict:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('52', '字典删除', '9', '4', '#', 'F', '0', 'system:dict:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('53', '字典保存', '9', '5', '#', 'F', '0', 'system:dict:save', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('54', '批量删除', '9', '6', '#', 'F', '0', 'system:dict:batchRemove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -- 参数设置按钮 -insert into sys_menu values('54', '参数查询', '10', '1', '#', 'F', '0', 'system:config:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('55', '参数新增', '10', '2', '#', 'F', '0', 'system:config:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('56', '参数修改', '10', '3', '#', 'F', '0', 'system:config:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('57', '参数删除', '10', '4', '#', 'F', '0', 'system:config:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('58', '参数保存', '10', '5', '#', 'F', '0', 'system:config:save', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('59', '批量删除', '10', '6', '#', 'F', '0', 'system:config:batchRemove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('55', '参数查询', '10', '1', '#', 'F', '0', 'system:config:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('56', '参数新增', '10', '2', '#', 'F', '0', 'system:config:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('57', '参数修改', '10', '3', '#', 'F', '0', 'system:config:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('58', '参数删除', '10', '4', '#', 'F', '0', 'system:config:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('59', '参数保存', '10', '5', '#', 'F', '0', 'system:config:save', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('60', '批量删除', '10', '6', '#', 'F', '0', 'system:config:batchRemove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -- 操作日志按钮 -insert into sys_menu values('60', '操作查询', '11', '1', '#', 'F', '0', 'monitor:operlog:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('61', '批量删除', '11', '2', '#', 'F', '0', 'monitor:operlog:batchRemove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('62', '详细信息', '11', '3', '#', 'F', '0', 'monitor:operlog:detail', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('61', '操作查询', '11', '1', '#', 'F', '0', 'monitor:operlog:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('62', '批量删除', '11', '2', '#', 'F', '0', 'monitor:operlog:batchRemove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('63', '详细信息', '11', '3', '#', 'F', '0', 'monitor:operlog:detail', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -- 登录日志按钮 -insert into sys_menu values('63', '登录查询', '12', '1', '#', 'F', '0', 'monitor:logininfor:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('64', '批量删除', '12', '2', '#', 'F', '0', 'monitor:logininfor:batchRemove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('64', '登录查询', '12', '1', '#', 'F', '0', 'monitor:logininfor:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('65', '批量删除', '12', '2', '#', 'F', '0', 'monitor:logininfor:batchRemove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -- 在线用户按钮 -insert into sys_menu values('65', '在线查询', '13', '1', '#', 'F', '0', 'monitor:online:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('66', '批量强退', '13', '2', '#', 'F', '0', 'monitor:online:batchForceLogout', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('67', '单条强退', '13', '3', '#', 'F', '0', 'monitor:online:forceLogout', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('66', '在线查询', '13', '1', '#', 'F', '0', 'monitor:online:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('67', '批量强退', '13', '2', '#', 'F', '0', 'monitor:online:batchForceLogout', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('68', '单条强退', '13', '3', '#', 'F', '0', 'monitor:online:forceLogout', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -- 定时任务按钮 -insert into sys_menu values('68', '任务查询', '14', '1', '#', 'F', '0', 'monitor:job:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('69', '任务新增', '14', '2', '#', 'F', '0', 'monitor:job:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('70', '任务修改', '14', '3', '#', 'F', '0', 'monitor:job:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('71', '任务删除', '14', '4', '#', 'F', '0', 'monitor:job:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('72', '任务保存', '14', '5', '#', 'F', '0', 'monitor:job:save', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('73', '状态修改', '14', '6', '#', 'F', '0', 'monitor:job:changeStatus', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('74', '批量删除', '14', '7', '#', 'F', '0', 'monitor:job:batchRemove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('69', '任务查询', '14', '1', '#', 'F', '0', 'monitor:job:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('70', '任务新增', '14', '2', '#', 'F', '0', 'monitor:job:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('71', '任务修改', '14', '3', '#', 'F', '0', 'monitor:job:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('72', '任务删除', '14', '4', '#', 'F', '0', 'monitor:job:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('73', '任务保存', '14', '5', '#', 'F', '0', 'monitor:job:save', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('74', '状态修改', '14', '6', '#', 'F', '0', 'monitor:job:changeStatus', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('75', '批量删除', '14', '7', '#', 'F', '0', 'monitor:job:batchRemove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -- 代码生成按钮 -insert into sys_menu values('75', '生成查询', '16', '1', '#', 'F', '0', 'tool:gen:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -insert into sys_menu values('76', '生成代码', '16', '2', '#', 'F', '0', 'tool:gen:code', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('76', '生成查询', '16', '1', '#', 'F', '0', 'tool:gen:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); +insert into sys_menu values('77', '生成代码', '16', '2', '#', 'F', '0', 'tool:gen:code', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); -- ---------------------------- @@ -341,6 +342,7 @@ insert into sys_role_menu values ('1', '73'); insert into sys_role_menu values ('1', '74'); insert into sys_role_menu values ('1', '75'); insert into sys_role_menu values ('1', '76'); +insert into sys_role_menu values ('1', '77'); -- ---------------------------- -- 8、用户与岗位关联表 用户1-N岗位 diff --git a/src/main/java/com/ruoyi/common/utils/ExcelImportUtils.java b/src/main/java/com/ruoyi/common/utils/ExcelImportUtils.java new file mode 100644 index 000000000..79f591b61 --- /dev/null +++ b/src/main/java/com/ruoyi/common/utils/ExcelImportUtils.java @@ -0,0 +1,78 @@ +package com.ruoyi.common.utils; + +import org.apache.poi.hssf.usermodel.HSSFDateUtil; +import org.apache.poi.ss.usermodel.Cell; + +import java.text.DecimalFormat; +import java.util.Date; + +/** + * 导入Excel工具类 + */ +public class ExcelImportUtils { + + /** 是否是2003的excel,返回true是2003Excel文件**/ + public static boolean isExcel2003(String filePath){ + return filePath.matches("^.+\\.(?i)(xls)$"); + } + /** 是否是2007以上的excel,返回true是2007Excel文件**/ + public static boolean isExcel2007(String filePath){ + return filePath.matches("^.+\\.(?i)(xlsx)$"); + } + /** + * 验证EXCEL文件 + * + * @param filePath + * @return + */ + public static boolean validateExcel(String filePath) { + if (filePath == null || !(isExcel2003(filePath) || isExcel2007(filePath))) { + return false; + } + return true; + } + + /** + * 获取单元格的值 + * @param cell + * @return + */ + public static String getCellValue(Cell cell) { + String value = ""; + if (cell != null) { + switch(cell.getCellTypeEnum()){ + case NUMERIC:// 数字 + value = cell.getNumericCellValue()+ " "; + if(HSSFDateUtil.isCellDateFormatted(cell)){ + Date date = cell.getDateCellValue(); + if(date != null){ + value = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,date); // 日期格式化 + }else{ + value = ""; + } + }else { + // 解析cell时候 数字类型默认是double类型的 但是想要获取整数类型 需要格式化 + value = new DecimalFormat("0").format(cell.getNumericCellValue()); + } + break; + case STRING: // 字符串 + value = cell.getStringCellValue(); + break; + case BOOLEAN: // Boolean类型 + value = cell.getBooleanCellValue()+""; + break; + case BLANK: // 空值 + value = ""; + break; + case ERROR: // 错误类型 + value ="非法字符"; + break; + default: + value = "未知类型"; + break; + } + + } + return value.trim(); + } +} diff --git a/src/main/java/com/ruoyi/project/system/user/controller/UserController.java b/src/main/java/com/ruoyi/project/system/user/controller/UserController.java index 639bcfb2c..e6374787d 100644 --- a/src/main/java/com/ruoyi/project/system/user/controller/UserController.java +++ b/src/main/java/com/ruoyi/project/system/user/controller/UserController.java @@ -1,18 +1,5 @@ package com.ruoyi.project.system.user.controller; -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.transaction.annotation.Transactional; -import org.springframework.ui.Model; -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.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.aspectj.lang.annotation.Log; import com.ruoyi.framework.web.controller.BaseController; @@ -25,6 +12,17 @@ import com.ruoyi.project.system.role.service.IRoleService; import com.ruoyi.project.system.user.domain.User; import com.ruoyi.project.system.user.domain.UserStatus; import com.ruoyi.project.system.user.service.IUserService; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; /** * 用户信息 @@ -35,7 +33,7 @@ import com.ruoyi.project.system.user.service.IUserService; @RequestMapping("/system/user") public class UserController extends BaseController { - + private static final Logger log = LoggerFactory.getLogger(UserController.class); private String prefix = "system/user"; @Autowired @@ -172,6 +170,28 @@ public class UserController extends BaseController return userService.saveUser(user) > 0 ? Message.success() : Message.error(); } + /** + * 批量新增用户 + */ + @RequiresPermissions("system:user:batchAdd") + @Log(title = "系统管理", action = "用户管理-批量新增用户") + @PostMapping("/batchAdd") + @Transactional(rollbackFor = Exception.class) + @ResponseBody + public Message batchAdd( @RequestParam("uploadfile") MultipartFile file) + { + try { + if(!file.isEmpty()){ + int rows=userService.batchImportUsers(file); + return Message.success(String.valueOf(rows)); + } + return Message.error(); + }catch (Exception e){ + log.error("批量添加用户失败 !", e); + return Message.error(e.getMessage()); + } + } + /** * 校验用户名 */ diff --git a/src/main/java/com/ruoyi/project/system/user/mapper/UserMapper.java b/src/main/java/com/ruoyi/project/system/user/mapper/UserMapper.java index b553707f4..7f6a2bbb5 100644 --- a/src/main/java/com/ruoyi/project/system/user/mapper/UserMapper.java +++ b/src/main/java/com/ruoyi/project/system/user/mapper/UserMapper.java @@ -1,8 +1,9 @@ package com.ruoyi.project.system.user.mapper; -import java.util.List; import com.ruoyi.project.system.user.domain.User; +import java.util.List; + /** * 用户表 数据层 * @@ -108,4 +109,12 @@ public interface UserMapper * @return 结果 */ public User checkEmailUnique(String email); + + + /** + * 批量添加用户 + * @param userList + * @return + */ + public int batchAddUser(List userList); } diff --git a/src/main/java/com/ruoyi/project/system/user/service/IUserService.java b/src/main/java/com/ruoyi/project/system/user/service/IUserService.java index c81bf5730..b433357ba 100644 --- a/src/main/java/com/ruoyi/project/system/user/service/IUserService.java +++ b/src/main/java/com/ruoyi/project/system/user/service/IUserService.java @@ -1,7 +1,9 @@ package com.ruoyi.project.system.user.service; -import java.util.List; import com.ruoyi.project.system.user.domain.User; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; /** * 用户 业务层 @@ -133,4 +135,11 @@ public interface IUserService */ public String selectUserPostGroup(Long userId); + /** + * Excel批量导入用户 + * @param myFile + * @return + */ + public int batchImportUsers(MultipartFile myFile); + } diff --git a/src/main/java/com/ruoyi/project/system/user/service/UserServiceImpl.java b/src/main/java/com/ruoyi/project/system/user/service/UserServiceImpl.java index d8fdd4d64..593a6d4e6 100644 --- a/src/main/java/com/ruoyi/project/system/user/service/UserServiceImpl.java +++ b/src/main/java/com/ruoyi/project/system/user/service/UserServiceImpl.java @@ -1,13 +1,13 @@ package com.ruoyi.project.system.user.service; -import java.util.ArrayList; -import java.util.List; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; import com.ruoyi.common.constant.UserConstants; +import com.ruoyi.common.exception.user.UserException; +import com.ruoyi.common.utils.ExcelImportUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.security.ShiroUtils; import com.ruoyi.framework.shiro.service.PasswordService; +import com.ruoyi.project.system.dept.domain.Dept; +import com.ruoyi.project.system.dept.service.IDeptService; import com.ruoyi.project.system.post.domain.Post; import com.ruoyi.project.system.post.mapper.PostMapper; import com.ruoyi.project.system.role.domain.Role; @@ -18,6 +18,19 @@ import com.ruoyi.project.system.user.domain.UserRole; import com.ruoyi.project.system.user.mapper.UserMapper; import com.ruoyi.project.system.user.mapper.UserPostMapper; import com.ruoyi.project.system.user.mapper.UserRoleMapper; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.*; /** * 用户 业务层处理 @@ -27,7 +40,7 @@ import com.ruoyi.project.system.user.mapper.UserRoleMapper; @Service("userService") public class UserServiceImpl implements IUserService { - + private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class); @Autowired private UserMapper userMapper; @@ -46,6 +59,10 @@ public class UserServiceImpl implements IUserService @Autowired private PasswordService passwordService; + @Autowired + private IDeptService deptService; + + /** * 根据条件分页查询用户对象 * @@ -178,6 +195,245 @@ public class UserServiceImpl implements IUserService return count; } + /** + * 根据Execl 批量保存用户 + * 1. 使用HSSFWorkbook 打开或者创建 “Excel对象” + * 2. 用HSSFWorkbook返回对象或者创建sheet对象 + * 3. 用sheet返回行对象,用行对象得到Cell对象 + * 4. 对Cell对象进行读写 + * @param myFile + * @return + */ + @Override + public int batchImportUsers(MultipartFile myFile) { + //Excel工作簿 + Workbook workbook=null; + //获取文件名 + String filename=myFile.getOriginalFilename(); + log.info("【ExeclfileName】{}",filename); + //根据文件名判断文件是2003版本还是2007版本 + if(ExcelImportUtils.isExcel2003(filename)){ + try { + workbook=new HSSFWorkbook(myFile.getInputStream());//2003版本 + }catch (IOException e){ + log.error("获取Excel2003流错误"+e.getMessage()); + } + }else if(ExcelImportUtils.isExcel2007(filename)){ + try { + workbook=new XSSFWorkbook(myFile.getInputStream());//2007以上版本 + }catch (IOException e){ + log.error("获取Excel2007以上版本流错误"+e.getMessage()); + } + }else{ + + throw new UserException("1000",new Object[]{"文件不是Excel格式"}); + } + //得到第一个sheet + Sheet sheet = workbook.getSheetAt(0); + //得到Excel的行数 + int totalRows = sheet.getLastRowNum(); + log.info("【rows】{}",totalRows); + //新建用户list + List users=new ArrayList(); + + List depts; + List roles; + List posts; + + //如果行数为空 + /** + * getPhysicalNumberOfRows + * + * 获取有记录的行数,即:最后有数据的行是第n行,前面有m行是空行没数据,则返回n-m; + */ + if((totalRows==0)&&(sheet.getPhysicalNumberOfRows()==0)){ + throw new UserException("1001",new Object[]{"数据为空 请填写数据"}); + }else{ + //获取全部部门信息 + depts=deptService.selectDeptAll(); + //获取全部角色信息 + roles=roleMapper.selectRolesAll(); + //获取全部岗位信息 + posts=postMapper.selectPostAll(); + } + + for(int i=1;i<=totalRows;i++){ + Row row = sheet.getRow(i); + if(row!=null){ + User user=new User(); + //登录名(用户名) + String userName=ExcelImportUtils.getCellValue(row.getCell(0)); + if(userName.isEmpty()){ + continue; + }else{ + //判断用户名是否唯一 + if(checkLoginNameUnique(userName).equals(UserConstants.USER_NAME_UNIQUE)){ + user.setLoginName(userName); + }else { + log.error("【rows】{}行用户名已经存在",i+1); + continue; + } + } + //姓名 + String userRealName=ExcelImportUtils.getCellValue(row.getCell(1)); + user.setUserName(userRealName); + //性别 + String userSex=ExcelImportUtils.getCellValue(row.getCell(2)); + if(StringUtils.isNotEmpty(userSex)){ + if(userSex.equals("男")){ + user.setSex("0"); + }else if(userSex.equals("女")){ + user.setSex("1"); + }else { + user.setSex("2"); + } + } + //密码 + String passWord=ExcelImportUtils.getCellValue(row.getCell(3)); + user.randomSalt(); + user.setPassword(passwordService.encryptPassword(userName, passWord, user.getSalt())); + //部门 + String dept=ExcelImportUtils.getCellValue(row.getCell(4)); + if(StringUtils.isNotEmpty(dept)){ + for (int k=0;k sets=new HashSet(); + //判断是否有"," 号 + if(userRolesExcel.contains(",")){ + List results= Arrays.asList(userRolesExcel.split(",")); + for(String s:results){ + for(int l=0;l setPosts=new HashSet(); + //判断是否有"," 号 + if(userPostExcel.contains(",")){ + List resultsp= Arrays.asList(userPostExcel.split(",")); + for(String p:resultsp){ + for(int h=0;h0){ + //批量插入用户 + realRow=userMapper.batchAddUser(users); + } + System.out.println(realRow); + if(realRow>0){ + //用户和角色关联 + List userRoles=new ArrayList(); + //用户和岗位关联 + List userPosts=new ArrayList(); + for(User test:users){ + System.out.println("userID="+test.getUserId()); + System.out.println("username="+test.getUserName()); + System.out.println("useroleids"+Arrays.toString(test.getRoleIds())); + System.out.println("userpostids"+Arrays.toString(test.getPostIds())); + + //添加用户-角色关联表 + for(int q=0;q + + + insert into sys_user( + dept_id, + login_name, + user_name, + email, + phonenumber, + sex, + password, + salt, + status, + create_by, + remark, + create_time + )values + + ( + #{item.deptId}, + #{item.loginName}, + #{item.userName}, + #{item.email}, + #{item.phonenumber}, + #{item.sex}, + #{item.password}, + #{item.salt}, + #{item.status}, + #{item.createBy}, + #{item.remark}, + sysdate() + ) + + \ No newline at end of file diff --git a/src/main/resources/static/css/plugins/fileinput/fileinput.css b/src/main/resources/static/css/plugins/fileinput/fileinput.css new file mode 100644 index 000000000..f249a2cf8 --- /dev/null +++ b/src/main/resources/static/css/plugins/fileinput/fileinput.css @@ -0,0 +1,554 @@ +/*! + * bootstrap-fileinput v4.4.9 + * http://plugins.krajee.com/file-input + * + * Krajee default styling for bootstrap-fileinput. + * + * Author: Kartik Visweswaran + * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com + * + * Licensed under the BSD 3-Clause + * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md + */ +.file-loading input[type=file], input[type=file].file-loading { + width: 0; + height: 0; +} + +.file-no-browse { + position: absolute; + left: 50%; + bottom: 20%; + width: 1px; + height: 1px; + font-size: 0; + opacity: 0; + border: none; + background: none; + outline: none; + box-shadow: none; +} + +.kv-hidden, .file-caption-icon, .file-zoom-dialog .modal-header:before, .file-zoom-dialog .modal-header:after, .file-input-new .file-preview, .file-input-new .close, .file-input-new .glyphicon-file, .file-input-new .fileinput-remove-button, .file-input-new .fileinput-upload-button, .file-input-new .no-browse .input-group-btn, .file-input-ajax-new .fileinput-remove-button, .file-input-ajax-new .fileinput-upload-button, .file-input-ajax-new .no-browse .input-group-btn, .hide-content .kv-file-content { + display: none; +} + +.btn-file input[type=file], .file-caption-icon, .file-preview .fileinput-remove, .krajee-default .file-thumb-progress, .file-zoom-dialog .btn-navigate, .file-zoom-dialog .floating-buttons { + position: absolute; +} + +.file-input, .file-loading:before, .btn-file, .file-caption, .file-preview, .krajee-default.file-preview-frame, .krajee-default .file-thumbnail-footer, .file-zoom-dialog .modal-dialog { + position: relative; +} + +.file-error-message pre, .file-error-message ul, .krajee-default .file-actions, .krajee-default .file-other-error { + text-align: left; +} + +.file-error-message pre, .file-error-message ul { + margin: 0; +} + +.krajee-default .file-drag-handle, .krajee-default .file-upload-indicator { + float: left; + margin: 5px 0 -5px; + width: 16px; + height: 16px; +} + +.krajee-default .file-thumb-progress .progress, .krajee-default .file-thumb-progress .progress-bar { + height: 11px; + font-size: 9px; + line-height: 10px; +} + +.krajee-default .file-caption-info, .krajee-default .file-size-info { + display: block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + width: 160px; + height: 15px; + margin: auto; +} + +.file-zoom-content > .file-object.type-video, .file-zoom-content > .file-object.type-flash, .file-zoom-content > .file-object.type-image { + max-width: 100%; + max-height: 100%; + width: auto; +} + +.file-zoom-content > .file-object.type-video, .file-zoom-content > .file-object.type-flash { + height: 100%; +} + +.file-zoom-content > .file-object.type-pdf, .file-zoom-content > .file-object.type-html, .file-zoom-content > .file-object.type-text, .file-zoom-content > .file-object.type-default { + width: 100%; +} + +.rotate-2 { + transform: rotateY(180deg); +} + +.rotate-3 { + transform: rotate(180deg); +} + +.rotate-4 { + transform: rotate(180deg) rotateY(180deg); +} + +.rotate-5 { + transform: rotate(270deg) rotateY(180deg); +} + +.rotate-6 { + transform: rotate(90deg); +} + +.rotate-7 { + transform: rotate(90deg) rotateY(180deg); +} + +.rotate-8 { + transform: rotate(270deg); +} + +.file-loading:before { + content: " Loading..."; + display: inline-block; + padding-left: 20px; + line-height: 16px; + font-size: 13px; + font-variant: small-caps; + color: #999; + background: transparent url(../img/loading.gif) top left no-repeat; +} + +.file-object { + margin: 0 0 -5px 0; + padding: 0; +} + +.btn-file { + overflow: hidden; +} + +.btn-file input[type=file] { + top: 0; + left: 0; + min-width: 100%; + min-height: 100%; + text-align: right; + opacity: 0; + background: none repeat scroll 0 0 transparent; + cursor: inherit; + display: block; +} + +.btn-file ::-ms-browse { + font-size: 10000px; + width: 100%; + height: 100%; +} + +.file-caption .file-caption-name { + width: 100%; + margin: 0; + padding: 0; + box-shadow: none; + border: none; + background: none; + outline: none; +} + +.file-caption.icon-visible .file-caption-icon { + display: inline-block; +} + +.file-caption.icon-visible .file-caption-name { + padding-left: 15px; +} + +.file-caption-icon { + left: 8px; +} + +.file-error-message { + color: #a94442; + background-color: #f2dede; + margin: 5px; + border: 1px solid #ebccd1; + border-radius: 4px; + padding: 15px; +} + +.file-error-message pre { + margin: 5px 0; +} + +.file-caption-disabled { + background-color: #eee; + cursor: not-allowed; + opacity: 1; +} + +.file-preview { + border-radius: 5px; + border: 1px solid #ddd; + padding: 8px; + width: 100%; + margin-bottom: 5px; +} + +.file-preview .btn-xs { + padding: 1px 5px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} + +.file-preview .fileinput-remove { + top: 1px; + right: 1px; + line-height: 10px; +} + +.file-preview .clickable { + cursor: pointer; +} + +.file-preview-image { + font: 40px Impact, Charcoal, sans-serif; + color: #008000; +} + +.krajee-default.file-preview-frame { + margin: 8px; + border: 1px solid #ddd; + box-shadow: 1px 1px 5px 0 #a2958a; + padding: 6px; + float: left; + text-align: center; +} + +.krajee-default.file-preview-frame .kv-file-content { + width: 213px; + height: 160px; +} + +.krajee-default.file-preview-frame .file-thumbnail-footer { + height: 70px; +} + +.krajee-default.file-preview-frame:not(.file-preview-error):hover { + box-shadow: 3px 3px 5px 0 #333; +} + +.krajee-default .file-preview-text { + display: block; + color: #428bca; + border: 1px solid #ddd; + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + outline: none; + padding: 8px; + resize: none; +} + +.krajee-default .file-preview-html { + border: 1px solid #ddd; + padding: 8px; + overflow: auto; +} + +.krajee-default .file-other-icon { + font-size: 6em; +} + +.krajee-default .file-footer-buttons { + float: right; +} + +.krajee-default .file-footer-caption { + display: block; + text-align: center; + padding-top: 4px; + font-size: 11px; + color: #777; + margin-bottom: 15px; +} + +.krajee-default .file-preview-error { + opacity: 0.65; + box-shadow: none; +} + +.krajee-default .file-thumb-progress { + height: 11px; + top: 37px; + left: 0; + right: 0; +} + +.krajee-default.kvsortable-ghost { + background: #e1edf7; + border: 2px solid #a1abff; +} + +.krajee-default .file-preview-other:hover { + opacity: 0.8; +} + +.krajee-default .file-preview-frame:not(.file-preview-error) .file-footer-caption:hover { + color: #000; +} + +.kv-upload-progress .progress { + height: 20px; + line-height: 20px; + margin: 10px 0; + overflow: hidden; +} + +.kv-upload-progress .progress-bar { + height: 20px; + line-height: 20px; +} + +/*noinspection CssOverwrittenProperties*/ +.file-zoom-dialog .file-other-icon { + font-size: 22em; + font-size: 50vmin; +} + +.file-zoom-dialog .modal-dialog { + width: auto; +} + +.file-zoom-dialog .modal-header { + display: flex; + align-items: center; + justify-content: space-between; +} + +.file-zoom-dialog .btn-navigate { + padding: 0; + margin: 0; + background: transparent; + text-decoration: none; + outline: none; + opacity: 0.7; + top: 45%; + font-size: 4em; + color: #1c94c4; +} + +.file-zoom-dialog .btn-navigate:not([disabled]):hover { + outline: none; + box-shadow: none; + opacity: 0.6; +} + +.file-zoom-dialog .floating-buttons { + top: 5px; + right: 10px; +} + +.file-zoom-dialog .btn-navigate[disabled] { + opacity: 0.3; +} + +.file-zoom-dialog .btn-prev { + left: 1px; +} + +.file-zoom-dialog .btn-next { + right: 1px; +} + +.file-zoom-dialog .kv-zoom-title { + font-weight: 300; + color: #999; + max-width: 50%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.file-input-new .no-browse .form-control { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} + +.file-input-ajax-new .no-browse .form-control { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} + +.file-caption-main { + width: 100%; +} + +.file-thumb-loading { + background: transparent url(../img/loading.gif) no-repeat scroll center center content-box !important; +} + +.file-drop-zone { + border: 1px dashed #aaa; + border-radius: 4px; + height: 100%; + text-align: center; + vertical-align: middle; + margin: 12px 15px 12px 12px; + padding: 5px; +} + +.file-drop-zone.clickable:hover { + border: 2px dashed #999; +} + +.file-drop-zone.clickable:focus { + border: 2px solid #5acde2; +} + +.file-drop-zone .file-preview-thumbnails { + cursor: default; +} + +.file-drop-zone-title { + color: #aaa; + font-size: 1.6em; + padding: 85px 10px; + cursor: default; +} + +.file-highlighted { + border: 2px dashed #999 !important; + background-color: #eee; +} + +.file-uploading { + background: url(../img/loading-sm.gif) no-repeat center bottom 10px; + opacity: 0.65; +} + +@media (min-width: 576px) { + .file-zoom-dialog .modal-dialog { + max-width: 500px; + } +} + +@media (min-width: 992px) { + .file-zoom-dialog .modal-lg { + max-width: 800px; + } +} + +.file-zoom-fullscreen.modal { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; +} + +.file-zoom-fullscreen .modal-dialog { + position: fixed; + margin: 0; + padding: 0; + width: 100%; + height: 100%; + max-width: 100%; + max-height: 100%; +} + +.file-zoom-fullscreen .modal-content { + border-radius: 0; + box-shadow: none; +} + +.file-zoom-fullscreen .modal-body { + overflow-y: auto; +} + +.floating-buttons { + z-index: 3000; +} + +.floating-buttons .btn-kv { + margin-left: 3px; + z-index: 3000; +} + +.file-zoom-content { + height: 480px; + text-align: center; +} + +.file-zoom-content .file-preview-image { + max-height: 100%; +} + +.file-zoom-content .file-preview-video { + max-height: 100%; +} + +.file-zoom-content .is-portrait-gt4 { + margin-top: 60px; +} + +.file-zoom-content > .file-object.type-image { + height: auto; + min-height: inherit; +} + +.file-zoom-content > .file-object.type-audio { + width: auto; + height: 30px; +} + +@media screen and (max-width: 767px) { + .file-preview-thumbnails { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + } + + .file-zoom-dialog .modal-header { + flex-direction: column; + } +} + +@media screen and (max-width: 350px) { + .krajee-default.file-preview-frame .kv-file-content { + width: 160px; + } +} + +.file-loading[dir=rtl]:before { + background: transparent url(../img/loading.gif) top right no-repeat; + padding-left: 0; + padding-right: 20px; +} + +.file-sortable .file-drag-handle { + cursor: move; + opacity: 1; +} + +.file-sortable .file-drag-handle:hover { + opacity: 0.7; +} + +.clickable .file-drop-zone-title { + cursor: pointer; +} + +.kv-zoom-actions .btn-kv { + margin-left: 3px; +} + +.file-preview-initial.sortable-chosen { + background-color: #d9edf7; +} \ No newline at end of file diff --git a/src/main/resources/static/css/plugins/fileinput/fileinput.min.css b/src/main/resources/static/css/plugins/fileinput/fileinput.min.css new file mode 100644 index 000000000..2ed85981b --- /dev/null +++ b/src/main/resources/static/css/plugins/fileinput/fileinput.min.css @@ -0,0 +1,12 @@ +/*! + * bootstrap-fileinput v4.4.9 + * http://plugins.krajee.com/file-input + * + * Krajee default styling for bootstrap-fileinput. + * + * Author: Kartik Visweswaran + * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com + * + * Licensed under the BSD 3-Clause + * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md + */.btn-file input[type=file],.file-caption-icon,.file-no-browse,.file-preview .fileinput-remove,.file-zoom-dialog .btn-navigate,.file-zoom-dialog .floating-buttons,.krajee-default .file-thumb-progress{position:absolute}.file-loading input[type=file],input[type=file].file-loading{width:0;height:0}.file-no-browse{left:50%;bottom:20%;width:1px;height:1px;font-size:0;opacity:0;border:none;background:0 0;outline:0;box-shadow:none}.file-caption-icon,.file-input-ajax-new .fileinput-remove-button,.file-input-ajax-new .fileinput-upload-button,.file-input-ajax-new .no-browse .input-group-btn,.file-input-new .close,.file-input-new .file-preview,.file-input-new .fileinput-remove-button,.file-input-new .fileinput-upload-button,.file-input-new .glyphicon-file,.file-input-new .no-browse .input-group-btn,.file-zoom-dialog .modal-header:after,.file-zoom-dialog .modal-header:before,.hide-content .kv-file-content,.kv-hidden{display:none}.btn-file,.file-caption,.file-input,.file-loading:before,.file-preview,.file-zoom-dialog .modal-dialog,.krajee-default .file-thumbnail-footer,.krajee-default.file-preview-frame{position:relative}.file-error-message pre,.file-error-message ul,.krajee-default .file-actions,.krajee-default .file-other-error{text-align:left}.file-error-message pre,.file-error-message ul{margin:0}.krajee-default .file-drag-handle,.krajee-default .file-upload-indicator{float:left;margin:5px 0 -5px;width:16px;height:16px}.krajee-default .file-thumb-progress .progress,.krajee-default .file-thumb-progress .progress-bar{height:11px;font-size:9px;line-height:10px}.krajee-default .file-caption-info,.krajee-default .file-size-info{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:160px;height:15px;margin:auto}.file-zoom-content>.file-object.type-flash,.file-zoom-content>.file-object.type-image,.file-zoom-content>.file-object.type-video{max-width:100%;max-height:100%;width:auto}.file-zoom-content>.file-object.type-flash,.file-zoom-content>.file-object.type-video{height:100%}.file-zoom-content>.file-object.type-default,.file-zoom-content>.file-object.type-html,.file-zoom-content>.file-object.type-pdf,.file-zoom-content>.file-object.type-text{width:100%}.rotate-2{transform:rotateY(180deg)}.rotate-3{transform:rotate(180deg)}.rotate-4{transform:rotate(180deg) rotateY(180deg)}.rotate-5{transform:rotate(270deg) rotateY(180deg)}.rotate-6{transform:rotate(90deg)}.rotate-7{transform:rotate(90deg) rotateY(180deg)}.rotate-8{transform:rotate(270deg)}.file-loading:before{content:" Loading...";display:inline-block;padding-left:20px;line-height:16px;font-size:13px;font-variant:small-caps;color:#999;background:url(../img/loading.gif) top left no-repeat}.file-object{margin:0 0 -5px;padding:0}.btn-file{overflow:hidden}.btn-file input[type=file]{top:0;left:0;min-width:100%;min-height:100%;text-align:right;opacity:0;background:none;cursor:inherit;display:block}.btn-file ::-ms-browse{font-size:10000px;width:100%;height:100%}.file-caption .file-caption-name{width:100%;margin:0;padding:0;box-shadow:none;border:none;background:0 0;outline:0}.file-caption.icon-visible .file-caption-icon{display:inline-block}.file-caption.icon-visible .file-caption-name{padding-left:15px}.file-caption-icon{left:8px}.file-error-message{color:#a94442;background-color:#f2dede;margin:5px;border:1px solid #ebccd1;border-radius:4px;padding:15px}.file-error-message pre{margin:5px 0}.file-caption-disabled{background-color:#eee;cursor:not-allowed;opacity:1}.file-preview{border-radius:5px;border:1px solid #ddd;padding:8px;width:100%;margin-bottom:5px}.file-preview .btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.file-preview .fileinput-remove{top:1px;right:1px;line-height:10px}.file-preview .clickable{cursor:pointer}.file-preview-image{font:40px Impact,Charcoal,sans-serif;color:green}.krajee-default.file-preview-frame{margin:8px;border:1px solid #ddd;box-shadow:1px 1px 5px 0 #a2958a;padding:6px;float:left;text-align:center}.krajee-default.file-preview-frame .kv-file-content{width:213px;height:160px}.krajee-default.file-preview-frame .file-thumbnail-footer{height:70px}.krajee-default.file-preview-frame:not(.file-preview-error):hover{box-shadow:3px 3px 5px 0 #333}.krajee-default .file-preview-text{display:block;color:#428bca;border:1px solid #ddd;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;outline:0;padding:8px;resize:none}.krajee-default .file-preview-html{border:1px solid #ddd;padding:8px;overflow:auto}.krajee-default .file-other-icon{font-size:6em}.krajee-default .file-footer-buttons{float:right}.krajee-default .file-footer-caption{display:block;text-align:center;padding-top:4px;font-size:11px;color:#777;margin-bottom:15px}.krajee-default .file-preview-error{opacity:.65;box-shadow:none}.krajee-default .file-thumb-progress{height:11px;top:37px;left:0;right:0}.krajee-default.kvsortable-ghost{background:#e1edf7;border:2px solid #a1abff}.krajee-default .file-preview-other:hover{opacity:.8}.krajee-default .file-preview-frame:not(.file-preview-error) .file-footer-caption:hover{color:#000}.kv-upload-progress .progress{height:20px;line-height:20px;margin:10px 0;overflow:hidden}.kv-upload-progress .progress-bar{height:20px;line-height:20px}.file-zoom-dialog .file-other-icon{font-size:22em;font-size:50vmin}.file-zoom-dialog .modal-dialog{width:auto}.file-zoom-dialog .modal-header{display:flex;align-items:center;justify-content:space-between}.file-zoom-dialog .btn-navigate{padding:0;margin:0;background:0 0;text-decoration:none;outline:0;opacity:.7;top:45%;font-size:4em;color:#1c94c4}.file-zoom-dialog .btn-navigate:not([disabled]):hover{outline:0;box-shadow:none;opacity:.6}.file-zoom-dialog .floating-buttons{top:5px;right:10px}.file-zoom-dialog .btn-navigate[disabled]{opacity:.3}.file-zoom-dialog .btn-prev{left:1px}.file-zoom-dialog .btn-next{right:1px}.file-zoom-dialog .kv-zoom-title{font-weight:300;color:#999;max-width:50%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.file-input-ajax-new .no-browse .form-control,.file-input-new .no-browse .form-control{border-top-right-radius:4px;border-bottom-right-radius:4px}.file-caption-main{width:100%}.file-thumb-loading{background:url(../img/loading.gif) center center no-repeat content-box!important}.file-drop-zone{border:1px dashed #aaa;border-radius:4px;height:100%;text-align:center;vertical-align:middle;margin:12px 15px 12px 12px;padding:5px}.file-drop-zone.clickable:hover{border:2px dashed #999}.file-drop-zone.clickable:focus{border:2px solid #5acde2}.file-drop-zone .file-preview-thumbnails{cursor:default}.file-drop-zone-title{color:#aaa;font-size:1.6em;padding:85px 10px;cursor:default}.file-highlighted{border:2px dashed #999!important;background-color:#eee}.file-uploading{background:url(../img/loading-sm.gif) center bottom 10px no-repeat;opacity:.65}@media (min-width:576px){.file-zoom-dialog .modal-dialog{max-width:500px}}@media (min-width:992px){.file-zoom-dialog .modal-lg{max-width:800px}}.file-zoom-fullscreen.modal{position:fixed;top:0;right:0;bottom:0;left:0}.file-zoom-fullscreen .modal-dialog{position:fixed;margin:0;padding:0;width:100%;height:100%;max-width:100%;max-height:100%}.file-zoom-fullscreen .modal-content{border-radius:0;box-shadow:none}.file-zoom-fullscreen .modal-body{overflow-y:auto}.floating-buttons{z-index:3000}.floating-buttons .btn-kv{margin-left:3px;z-index:3000}.file-zoom-content{height:480px;text-align:center}.file-zoom-content .file-preview-image,.file-zoom-content .file-preview-video{max-height:100%}.file-zoom-content .is-portrait-gt4{margin-top:60px}.file-zoom-content>.file-object.type-image{height:auto;min-height:inherit}.file-zoom-content>.file-object.type-audio{width:auto;height:30px}@media screen and (max-width:767px){.file-preview-thumbnails{display:flex;justify-content:center;align-items:center;flex-direction:column}.file-zoom-dialog .modal-header{flex-direction:column}}@media screen and (max-width:350px){.krajee-default.file-preview-frame .kv-file-content{width:160px}}.file-loading[dir=rtl]:before{background:url(../img/loading.gif) top right no-repeat;padding-left:0;padding-right:20px}.file-sortable .file-drag-handle{cursor:move;opacity:1}.file-sortable .file-drag-handle:hover{opacity:.7}.clickable .file-drop-zone-title{cursor:pointer}.kv-zoom-actions .btn-kv{margin-left:3px}.file-preview-initial.sortable-chosen{background-color:#d9edf7} \ No newline at end of file diff --git a/src/main/resources/static/js/plugins/fileinput/fileinput.js b/src/main/resources/static/js/plugins/fileinput/fileinput.js new file mode 100644 index 000000000..201c9c880 --- /dev/null +++ b/src/main/resources/static/js/plugins/fileinput/fileinput.js @@ -0,0 +1,4463 @@ +/*! + * bootstrap-fileinput v4.4.9 + * http://plugins.krajee.com/file-input + * + * Author: Kartik Visweswaran + * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com + * + * Licensed under the BSD 3-Clause + * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md + */ +(function (factory) { + "use strict"; + //noinspection JSUnresolvedVariable + if (typeof define === 'function' && define.amd) { // jshint ignore:line + // AMD. Register as an anonymous module. + define(['jquery'], factory); // jshint ignore:line + } else { // noinspection JSUnresolvedVariable + if (typeof module === 'object' && module.exports) { // jshint ignore:line + // Node/CommonJS + // noinspection JSUnresolvedVariable + module.exports = factory(require('jquery')); // jshint ignore:line + } else { + // Browser globals + factory(window.jQuery); + } + } +}(function ($) { + "use strict"; + + $.fn.fileinputLocales = {}; + $.fn.fileinputThemes = {}; + + String.prototype.setTokens = function (replacePairs) { + var str = this.toString(), key, re; + for (key in replacePairs) { + if (replacePairs.hasOwnProperty(key)) { + re = new RegExp("\{" + key + "\}", "g"); + str = str.replace(re, replacePairs[key]); + } + } + return str; + }; + + var $h, FileInput; + + // fileinput helper object for all global variables and internal helper methods + //noinspection JSUnresolvedVariable + $h = { + FRAMES: '.kv-preview-thumb', + SORT_CSS: 'file-sortable', + OBJECT_PARAMS: '\n' + + '\n' + + '\n' + + '\n' + + '\n' + + '\n', + DEFAULT_PREVIEW: '\n' + + '{previewFileIcon}\n' + + '', + MODAL_ID: 'kvFileinputModal', + MODAL_EVENTS: ['show', 'shown', 'hide', 'hidden', 'loaded'], + objUrl: window.URL || window.webkitURL, + compare: function (input, str, exact) { + return input !== undefined && (exact ? input === str : input.match(str)); + }, + isIE: function (ver) { + // check for IE versions < 11 + if (navigator.appName !== 'Microsoft Internet Explorer') { + return false; + } + if (ver === 10) { + return new RegExp('msie\\s' + ver, 'i').test(navigator.userAgent); + } + var div = document.createElement("div"), status; + div.innerHTML = ""; + status = div.getElementsByTagName("i").length; + document.body.appendChild(div); + div.parentNode.removeChild(div); + return status; + }, + canAssignFilesToInput: function () { + var input = document.createElement('input'); + try { + input.type = "file"; + input.files = null; + return true; + } catch (err) { + return false; + } + }, + getDragDropFolders: function (items) { + var i, item, len = items.length, folders = 0; + if (len > 0 && items[0].webkitGetAsEntry()) { + for (i = 0; i < len; i++) { + item = items[i].webkitGetAsEntry(); + if (item && item.isDirectory) { + folders++; + } + } + } + return folders; + }, + initModal: function ($modal) { + var $body = $('body'); + if ($body.length) { + $modal.appendTo($body); + } + }, + isEmpty: function (value, trim) { + return value === undefined || value === null || value.length === 0 || (trim && $.trim(value) === ''); + }, + isArray: function (a) { + return Array.isArray(a) || Object.prototype.toString.call(a) === '[object Array]'; + }, + ifSet: function (needle, haystack, def) { + def = def || ''; + return (haystack && typeof haystack === 'object' && needle in haystack) ? haystack[needle] : def; + }, + cleanArray: function (arr) { + if (!(arr instanceof Array)) { + arr = []; + } + return arr.filter(function (e) { + return (e !== undefined && e !== null); + }); + }, + spliceArray: function (arr, index, reverseOrder) { + var i, j = 0, out = [], newArr; + if (!(arr instanceof Array)) { + return []; + } + newArr = $.extend(true, [], arr); + if (reverseOrder) { + newArr.reverse(); + } + for (i = 0; i < newArr.length; i++) { + if (i !== index) { + out[j] = newArr[i]; + j++; + } + } + if (reverseOrder) { + out.reverse(); + } + return out; + }, + getNum: function (num, def) { + def = def || 0; + if (typeof num === "number") { + return num; + } + if (typeof num === "string") { + num = parseFloat(num); + } + return isNaN(num) ? def : num; + }, + hasFileAPISupport: function () { + return !!(window.File && window.FileReader); + }, + hasDragDropSupport: function () { + var div = document.createElement('div'); + /** @namespace div.draggable */ + /** @namespace div.ondragstart */ + /** @namespace div.ondrop */ + return !$h.isIE(9) && + (div.draggable !== undefined || (div.ondragstart !== undefined && div.ondrop !== undefined)); + }, + hasFileUploadSupport: function () { + return $h.hasFileAPISupport() && window.FormData; + }, + hasBlobSupport: function () { + try { + return !!window.Blob && Boolean(new Blob()); + } catch (e) { + return false; + } + }, + hasArrayBufferViewSupport: function () { + try { + return new Blob([new Uint8Array(100)]).size === 100; + } catch (e) { + return false; + } + }, + dataURI2Blob: function (dataURI) { + //noinspection JSUnresolvedVariable + var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || + window.MSBlobBuilder, canBlob = $h.hasBlobSupport(), byteStr, arrayBuffer, intArray, i, mimeStr, bb, + canProceed = (canBlob || BlobBuilder) && window.atob && window.ArrayBuffer && window.Uint8Array; + if (!canProceed) { + return null; + } + if (dataURI.split(',')[0].indexOf('base64') >= 0) { + byteStr = atob(dataURI.split(',')[1]); + } else { + byteStr = decodeURIComponent(dataURI.split(',')[1]); + } + arrayBuffer = new ArrayBuffer(byteStr.length); + intArray = new Uint8Array(arrayBuffer); + for (i = 0; i < byteStr.length; i += 1) { + intArray[i] = byteStr.charCodeAt(i); + } + mimeStr = dataURI.split(',')[0].split(':')[1].split(';')[0]; + if (canBlob) { + return new Blob([$h.hasArrayBufferViewSupport() ? intArray : arrayBuffer], {type: mimeStr}); + } + bb = new BlobBuilder(); + bb.append(arrayBuffer); + return bb.getBlob(mimeStr); + }, + arrayBuffer2String: function (buffer) { + //noinspection JSUnresolvedVariable + if (window.TextDecoder) { + // noinspection JSUnresolvedFunction + return new TextDecoder("utf-8").decode(buffer); + } + var array = Array.prototype.slice.apply(new Uint8Array(buffer)), out = '', i = 0, len, c, char2, char3; + len = array.length; + while (i < len) { + c = array[i++]; + switch (c >> 4) { // jshint ignore:line + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + // 0xxxxxxx + out += String.fromCharCode(c); + break; + case 12: + case 13: + // 110x xxxx 10xx xxxx + char2 = array[i++]; + out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F)); // jshint ignore:line + break; + case 14: + // 1110 xxxx 10xx xxxx 10xx xxxx + char2 = array[i++]; + char3 = array[i++]; + out += String.fromCharCode(((c & 0x0F) << 12) | // jshint ignore:line + ((char2 & 0x3F) << 6) | // jshint ignore:line + ((char3 & 0x3F) << 0)); // jshint ignore:line + break; + } + } + return out; + }, + isHtml: function (str) { + var a = document.createElement('div'); + a.innerHTML = str; + for (var c = a.childNodes, i = c.length; i--;) { + if (c[i].nodeType === 1) { + return true; + } + } + return false; + }, + isSvg: function (str) { + return str.match(/^\s*<\?xml/i) && (str.match(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + }, + replaceTags: function (str, tags) { + var out = str; + if (!tags) { + return out; + } + $.each(tags, function (key, value) { + if (typeof value === "function") { + value = value(); + } + out = out.split(key).join(value); + }); + return out; + }, + cleanMemory: function ($thumb) { + var data = $thumb.is('img') ? $thumb.attr('src') : $thumb.find('source').attr('src'); + /** @namespace $h.objUrl.revokeObjectURL */ + $h.objUrl.revokeObjectURL(data); + }, + findFileName: function (filePath) { + var sepIndex = filePath.lastIndexOf('/'); + if (sepIndex === -1) { + sepIndex = filePath.lastIndexOf('\\'); + } + return filePath.split(filePath.substring(sepIndex, sepIndex + 1)).pop(); + }, + checkFullScreen: function () { + //noinspection JSUnresolvedVariable + return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || + document.msFullscreenElement; + }, + toggleFullScreen: function (maximize) { + var doc = document, de = doc.documentElement; + if (de && maximize && !$h.checkFullScreen()) { + /** @namespace document.requestFullscreen */ + /** @namespace document.msRequestFullscreen */ + /** @namespace document.mozRequestFullScreen */ + /** @namespace document.webkitRequestFullscreen */ + /** @namespace Element.ALLOW_KEYBOARD_INPUT */ + if (de.requestFullscreen) { + de.requestFullscreen(); + } else if (de.msRequestFullscreen) { + de.msRequestFullscreen(); + } else if (de.mozRequestFullScreen) { + de.mozRequestFullScreen(); + } else if (de.webkitRequestFullscreen) { + de.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); + } + } else { + /** @namespace document.exitFullscreen */ + /** @namespace document.msExitFullscreen */ + /** @namespace document.mozCancelFullScreen */ + /** @namespace document.webkitExitFullscreen */ + if (doc.exitFullscreen) { + doc.exitFullscreen(); + } else if (doc.msExitFullscreen) { + doc.msExitFullscreen(); + } else if (doc.mozCancelFullScreen) { + doc.mozCancelFullScreen(); + } else if (doc.webkitExitFullscreen) { + doc.webkitExitFullscreen(); + } + } + }, + moveArray: function (arr, oldIndex, newIndex, reverseOrder) { + var newArr = $.extend(true, [], arr); + if (reverseOrder) { + newArr.reverse(); + } + if (newIndex >= newArr.length) { + var k = newIndex - newArr.length; + while ((k--) + 1) { + newArr.push(undefined); + } + } + newArr.splice(newIndex, 0, newArr.splice(oldIndex, 1)[0]); + if (reverseOrder) { + newArr.reverse(); + } + return newArr; + }, + cleanZoomCache: function ($el) { + var $cache = $el.closest('.kv-zoom-cache-theme'); + if (!$cache.length) { + $cache = $el.closest('.kv-zoom-cache'); + } + $cache.remove(); + }, + setOrientation: function (buffer, callback) { + var scanner = new DataView(buffer), idx = 0, value = 1, // Non-rotated is the default + maxBytes, uInt16, exifLength; + if (scanner.getUint16(idx) !== 0xFFD8 || buffer.length < 2) { // not a proper JPEG + if (callback) { + callback(); + } + return; + } + idx += 2; + maxBytes = scanner.byteLength; + while (idx < maxBytes - 2) { + uInt16 = scanner.getUint16(idx); + idx += 2; + switch (uInt16) { + case 0xFFE1: // Start of EXIF + exifLength = scanner.getUint16(idx); + maxBytes = exifLength - idx; + idx += 2; + break; + case 0x0112: // Orientation tag + value = scanner.getUint16(idx + 6, false); + maxBytes = 0; // Stop scanning + break; + } + } + if (callback) { + callback(value); + } + }, + validateOrientation: function (file, callback) { + if (!window.FileReader || !window.DataView) { + return; // skip orientation if pre-requisite libraries not supported by browser + } + var reader = new FileReader(), buffer; + reader.onloadend = function () { + buffer = reader.result; + $h.setOrientation(buffer, callback); + }; + reader.readAsArrayBuffer(file); + }, + adjustOrientedImage: function ($img, isZoom) { + var offsetContTop, offsetTop, newTop; + if (!$img.hasClass('is-portrait-gt4')) { + return; + } + if (isZoom) { + $img.css({width: $img.parent().height()}); + return; + } else { + $img.css({height: 'auto', width: $img.height()}); + } + offsetContTop = $img.parent().offset().top; + offsetTop = $img.offset().top; + newTop = offsetContTop - offsetTop; + $img.css('margin-top', newTop); + }, + closeButton: function (css) { + css = css ? 'close ' + css : 'close'; + return '\n' + + ' ×\n' + + ''; + } + }; + FileInput = function (element, options) { + var self = this; + self.$element = $(element); + self.$parent = self.$element.parent(); + if (!self._validate()) { + return; + } + self.isPreviewable = $h.hasFileAPISupport(); + self.isIE9 = $h.isIE(9); + self.isIE10 = $h.isIE(10); + if (self.isPreviewable || self.isIE9) { + self._init(options); + self._listen(); + } + self.$element.removeClass('file-loading'); + }; + //noinspection JSUnusedGlobalSymbols + FileInput.prototype = { + constructor: FileInput, + _cleanup: function () { + var self = this; + self.reader = null; + self.formdata = {}; + self.uploadCount = 0; + self.uploadStatus = {}; + self.uploadLog = []; + self.uploadAsyncCount = 0; + self.loadedImages = []; + self.totalImagesCount = 0; + self.ajaxRequests = []; + self.clearStack(); + self.fileBatchCompleted = true; + if (!self.isPreviewable) { + self.showPreview = false; + } + self.isError = false; + self.ajaxAborted = false; + self.cancelling = false; + }, + _init: function (options, refreshMode) { + var self = this, f, $el = self.$element, $cont, t, tmp; + self.options = options; + $.each(options, function (key, value) { + switch (key) { + case 'minFileCount': + case 'maxFileCount': + case 'minFileSize': + case 'maxFileSize': + case 'maxFilePreviewSize': + case 'resizeImageQuality': + case 'resizeIfSizeMoreThan': + case 'progressUploadThreshold': + case 'initialPreviewCount': + case 'zoomModalHeight': + case 'minImageHeight': + case 'maxImageHeight': + case 'minImageWidth': + case 'maxImageWidth': + self[key] = $h.getNum(value); + break; + default: + self[key] = value; + break; + } + }); + if (self.rtl) { // swap buttons for rtl + tmp = self.previewZoomButtonIcons.prev; + self.previewZoomButtonIcons.prev = self.previewZoomButtonIcons.next; + self.previewZoomButtonIcons.next = tmp; + } + if (!refreshMode) { + self._cleanup(); + } + self.$form = $el.closest('form'); + self._initTemplateDefaults(); + self.uploadFileAttr = !$h.isEmpty($el.attr('name')) ? $el.attr('name') : 'file_data'; + t = self._getLayoutTemplate('progress'); + self.progressTemplate = t.replace('{class}', self.progressClass); + self.progressCompleteTemplate = t.replace('{class}', self.progressCompleteClass); + self.progressErrorTemplate = t.replace('{class}', self.progressErrorClass); + self.isDisabled = $el.attr('disabled') || $el.attr('readonly'); + if (self.isDisabled) { + $el.attr('disabled', true); + } + self.isAjaxUpload = $h.hasFileUploadSupport() && !$h.isEmpty(self.uploadUrl); + self.dropZoneEnabled = $h.hasDragDropSupport() && self.dropZoneEnabled; + if (!self.isAjaxUpload) { + self.dropZoneEnabled = self.dropZoneEnabled && $h.canAssignFilesToInput(); + } + self.isClickable = self.browseOnZoneClick && self.showPreview && + (self.dropZoneEnabled || !$h.isEmpty(self.defaultPreviewContent)); + self.slug = typeof options.slugCallback === "function" ? options.slugCallback : self._slugDefault; + self.mainTemplate = self.showCaption ? self._getLayoutTemplate('main1') : self._getLayoutTemplate('main2'); + self.captionTemplate = self._getLayoutTemplate('caption'); + self.previewGenericTemplate = self._getPreviewTemplate('generic'); + if (!self.imageCanvas && self.resizeImage && (self.maxImageWidth || self.maxImageHeight)) { + self.imageCanvas = document.createElement('canvas'); + self.imageCanvasContext = self.imageCanvas.getContext('2d'); + } + if ($h.isEmpty($el.attr('id'))) { + $el.attr('id', $h.uniqId()); + } + self.namespace = '.fileinput_' + $el.attr('id').replace(/-/g, '_'); + if (self.$container === undefined) { + self.$container = self._createContainer(); + } else { + self._refreshContainer(); + } + $cont = self.$container; + self.$dropZone = $cont.find('.file-drop-zone'); + self.$progress = $cont.find('.kv-upload-progress'); + self.$btnUpload = $cont.find('.fileinput-upload'); + self.$captionContainer = $h.getElement(options, 'elCaptionContainer', $cont.find('.file-caption')); + self.$caption = $h.getElement(options, 'elCaptionText', $cont.find('.file-caption-name')); + if (!$h.isEmpty(self.msgPlaceholder)) { + f = $el.attr('multiple') ? self.filePlural : self.fileSingle; + self.$caption.attr('placeholder', self.msgPlaceholder.replace('{files}', f)); + } + self.$captionIcon = self.$captionContainer.find('.file-caption-icon'); + self.$previewContainer = $h.getElement(options, 'elPreviewContainer', $cont.find('.file-preview')); + self.$preview = $h.getElement(options, 'elPreviewImage', $cont.find('.file-preview-thumbnails')); + self.$previewStatus = $h.getElement(options, 'elPreviewStatus', $cont.find('.file-preview-status')); + self.$errorContainer = $h.getElement(options, 'elErrorContainer', self.$previewContainer.find('.kv-fileinput-error')); + self._validateDisabled(); + if (!$h.isEmpty(self.msgErrorClass)) { + $h.addCss(self.$errorContainer, self.msgErrorClass); + } + if (!refreshMode) { + self.$errorContainer.hide(); + self.previewInitId = "preview-" + $h.uniqId(); + self._initPreviewCache(); + self._initPreview(true); + self._initPreviewActions(); + if (self.$parent.hasClass('file-loading')) { + self.$container.insertBefore(self.$parent); + self.$parent.remove(); + } + } else { + if (!self._errorsExist()) { + self.$errorContainer.hide(); + } + } + self._setFileDropZoneTitle(); + if ($el.attr('disabled')) { + self.disable(); + } + self._initZoom(); + if (self.hideThumbnailContent) { + $h.addCss(self.$preview, 'hide-content'); + } + }, + _initTemplateDefaults: function () { + var self = this, tMain1, tMain2, tPreview, tFileIcon, tClose, tCaption, tBtnDefault, tBtnLink, tBtnBrowse, + tModalMain, tModal, tProgress, tSize, tFooter, tActions, tActionDelete, tActionUpload, tActionDownload, + tActionZoom, tActionDrag, tIndicator, tTagBef, tTagBef1, tTagBef2, tTagAft, tGeneric, tHtml, tImage, + tText, tOffice, tGdocs, tVideo, tAudio, tFlash, tObject, tPdf, tOther, tStyle, tZoomCache, vDefaultDim; + tMain1 = '{preview}\n' + + '\n' + + '\n' + + ' {caption}\n' + + '\n' + + ' {remove}\n' + + ' {cancel}\n' + + ' {upload}\n' + + ' {browse}\n' + + ' \n' + + ''; + tMain2 = '{preview}\n\n\n{remove}\n{cancel}\n{upload}\n{browse}\n'; + tPreview = '\n' + + ' {close}' + + ' \n' + + ' \n' + + ' \n' + + ' ' + + ' \n' + + ' \n' + + ' \n' + + ''; + tClose = $h.closeButton('fileinput-remove'); + tFileIcon = ''; + // noinspection HtmlUnknownAttribute + tCaption = '\n' + + ' \n' + + ' \n' + + ''; + //noinspection HtmlUnknownAttribute + tBtnDefault = '{icon} {label}'; + //noinspection HtmlUnknownAttribute + tBtnLink = '{icon} {label}'; + //noinspection HtmlUnknownAttribute + tBtnBrowse = '{icon} {label}'; + tModalMain = ''; + tModal = '\n' + + ' \n' + + ' \n' + + ' {heading}\n' + + ' \n' + + ' {toggleheader}{fullscreen}{borderless}{close}\n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + '{prev} {next}\n' + + ' \n' + + ' \n' + + '\n'; + tProgress = '\n' + + ' \n' + + ' {status}\n' + + ' \n' + + ''; + tSize = ' ({sizeText})'; + tFooter = ''; + tActions = '\n' + + ' \n' + + '\n' + + '{drag}\n' + + ''; + //noinspection HtmlUnknownAttribute + tActionDelete = '{removeIcon}\n'; + tActionUpload = '' + + '{uploadIcon}'; + tActionDownload = '{downloadIcon}'; + tActionZoom = '{zoomIcon}'; + tActionDrag = '{dragIcon}'; + tIndicator = '{indicator}'; + tTagBef = '\n'; + tTagBef2 = tTagBef + ' title="{caption}">\n'; + tTagAft = '{footer}\n\n'; + tGeneric = '{content}\n'; + tStyle = ' {style}'; + tHtml = '{data}\n'; + tImage = '\n'; + tText = '' + + '{data}\n'; + tOffice = ''; + tGdocs = ''; + tVideo = '\n' + + '\n' + $h.DEFAULT_PREVIEW + '\n\n'; + tAudio = '\n\n' + $h.DEFAULT_PREVIEW + '\n\n'; + tFlash = '\n'; + tPdf = '\n'; + tObject = '\n' + '\n' + + $h.OBJECT_PARAMS + ' ' + $h.DEFAULT_PREVIEW + '\n\n'; + tOther = '\n' + $h.DEFAULT_PREVIEW + '\n\n'; + tZoomCache = '{zoomContent}'; + vDefaultDim = {width: "100%", height: "100%", 'min-height': "480px"}; + self.defaults = { + layoutTemplates: { + main1: tMain1, + main2: tMain2, + preview: tPreview, + close: tClose, + fileIcon: tFileIcon, + caption: tCaption, + modalMain: tModalMain, + modal: tModal, + progress: tProgress, + size: tSize, + footer: tFooter, + indicator: tIndicator, + actions: tActions, + actionDelete: tActionDelete, + actionUpload: tActionUpload, + actionDownload: tActionDownload, + actionZoom: tActionZoom, + actionDrag: tActionDrag, + btnDefault: tBtnDefault, + btnLink: tBtnLink, + btnBrowse: tBtnBrowse, + zoomCache: tZoomCache + }, + previewMarkupTags: { + tagBefore1: tTagBef1, + tagBefore2: tTagBef2, + tagAfter: tTagAft + }, + previewContentTemplates: { + generic: tGeneric, + html: tHtml, + image: tImage, + text: tText, + office: tOffice, + gdocs: tGdocs, + video: tVideo, + audio: tAudio, + flash: tFlash, + object: tObject, + pdf: tPdf, + other: tOther + }, + allowedPreviewTypes: ['image', 'html', 'text', 'video', 'audio', 'flash', 'pdf', 'object'], + previewTemplates: {}, + previewSettings: { + image: {width: "auto", height: "auto", 'max-width': "100%", 'max-height': "100%"}, + html: {width: "213px", height: "160px"}, + text: {width: "213px", height: "160px"}, + office: {width: "213px", height: "160px"}, + gdocs: {width: "213px", height: "160px"}, + video: {width: "213px", height: "160px"}, + audio: {width: "100%", height: "30px"}, + flash: {width: "213px", height: "160px"}, + object: {width: "213px", height: "160px"}, + pdf: {width: "213px", height: "160px"}, + other: {width: "213px", height: "160px"} + }, + previewSettingsSmall: { + image: {width: "auto", height: "auto", 'max-width': "100%", 'max-height': "100%"}, + html: {width: "100%", height: "160px"}, + text: {width: "100%", height: "160px"}, + office: {width: "100%", height: "160px"}, + gdocs: {width: "100%", height: "160px"}, + video: {width: "100%", height: "auto"}, + audio: {width: "100%", height: "30px"}, + flash: {width: "100%", height: "auto"}, + object: {width: "100%", height: "auto"}, + pdf: {width: "100%", height: "160px"}, + other: {width: "100%", height: "160px"} + }, + previewZoomSettings: { + image: {width: "auto", height: "auto", 'max-width': "100%", 'max-height': "100%"}, + html: vDefaultDim, + text: vDefaultDim, + office: {width: "100%", height: "100%", 'max-width': "100%", 'min-height': "480px"}, + gdocs: {width: "100%", height: "100%", 'max-width': "100%", 'min-height': "480px"}, + video: {width: "auto", height: "100%", 'max-width': "100%"}, + audio: {width: "100%", height: "30px"}, + flash: {width: "auto", height: "480px"}, + object: {width: "auto", height: "100%", 'max-width': "100%", 'min-height': "480px"}, + pdf: vDefaultDim, + other: {width: "auto", height: "100%", 'min-height': "480px"} + }, + fileTypeSettings: { + image: function (vType, vName) { + return ($h.compare(vType, 'image.*') && !$h.compare(vType, /(tiff?|wmf)$/i) || + $h.compare(vName, /\.(gif|png|jpe?g)$/i)); + }, + html: function (vType, vName) { + return $h.compare(vType, 'text/html') || $h.compare(vName, /\.(htm|html)$/i); + }, + office: function (vType, vName) { + return $h.compare(vType, /(word|excel|powerpoint|office)$/i) || + $h.compare(vName, /\.(docx?|xlsx?|pptx?|pps|potx?)$/i); + }, + gdocs: function (vType, vName) { + return $h.compare(vType, /(word|excel|powerpoint|office|iwork-pages|tiff?)$/i) || + $h.compare(vName, /\.(docx?|xlsx?|pptx?|pps|potx?|rtf|ods|odt|pages|ai|dxf|ttf|tiff?|wmf|e?ps)$/i); + }, + text: function (vType, vName) { + return $h.compare(vType, 'text.*') || $h.compare(vName, /\.(xml|javascript)$/i) || + $h.compare(vName, /\.(txt|md|csv|nfo|ini|json|php|js|css)$/i); + }, + video: function (vType, vName) { + return $h.compare(vType, 'video.*') && ($h.compare(vType, /(ogg|mp4|mp?g|mov|webm|3gp)$/i) || + $h.compare(vName, /\.(og?|mp4|webm|mp?g|mov|3gp)$/i)); + }, + audio: function (vType, vName) { + return $h.compare(vType, 'audio.*') && ($h.compare(vName, /(ogg|mp3|mp?g|wav)$/i) || + $h.compare(vName, /\.(og?|mp3|mp?g|wav)$/i)); + }, + flash: function (vType, vName) { + return $h.compare(vType, 'application/x-shockwave-flash', true) || $h.compare(vName, /\.(swf)$/i); + }, + pdf: function (vType, vName) { + return $h.compare(vType, 'application/pdf', true) || $h.compare(vName, /\.(pdf)$/i); + }, + object: function () { + return true; + }, + other: function () { + return true; + } + }, + fileActionSettings: { + showRemove: true, + showUpload: true, + showDownload: true, + showZoom: true, + showDrag: true, + removeIcon: '', + removeClass: 'btn btn-sm btn-kv btn-default btn-outline-secondary', + removeErrorClass: 'btn btn-sm btn-kv btn-danger', + removeTitle: 'Remove file', + uploadIcon: '', + uploadClass: 'btn btn-sm btn-kv btn-default btn-outline-secondary', + uploadTitle: 'Upload file', + uploadRetryIcon: '', + uploadRetryTitle: 'Retry upload', + downloadIcon: '', + downloadClass: 'btn btn-sm btn-kv btn-default btn-outline-secondary', + downloadTitle: 'Download file', + zoomIcon: '', + zoomClass: 'btn btn-sm btn-kv btn-default btn-outline-secondary', + zoomTitle: 'View Details', + dragIcon: '', + dragClass: 'text-info', + dragTitle: 'Move / Rearrange', + dragSettings: {}, + indicatorNew: '', + indicatorSuccess: '', + indicatorError: '', + indicatorLoading: '', + indicatorNewTitle: 'Not uploaded yet', + indicatorSuccessTitle: 'Uploaded', + indicatorErrorTitle: 'Upload Error', + indicatorLoadingTitle: 'Uploading ...' + } + }; + $.each(self.defaults, function (key, setting) { + if (key === 'allowedPreviewTypes') { + if (self.allowedPreviewTypes === undefined) { + self.allowedPreviewTypes = setting; + } + return; + } + self[key] = $.extend(true, {}, setting, self[key]); + }); + self._initPreviewTemplates(); + }, + _initPreviewTemplates: function () { + var self = this, cfg = self.defaults, tags = self.previewMarkupTags, tagBef, tagAft = tags.tagAfter; + $.each(cfg.previewContentTemplates, function (key, value) { + if ($h.isEmpty(self.previewTemplates[key])) { + tagBef = tags.tagBefore2; + if (key === 'generic' || key === 'image' || key === 'html' || key === 'text') { + tagBef = tags.tagBefore1; + } + self.previewTemplates[key] = tagBef + value + tagAft; + } + }); + }, + _initPreviewCache: function () { + var self = this; + self.previewCache = { + data: {}, + init: function () { + var content = self.initialPreview; + if (content.length > 0 && !$h.isArray(content)) { + content = content.split(self.initialPreviewDelimiter); + } + self.previewCache.data = { + content: content, + config: self.initialPreviewConfig, + tags: self.initialPreviewThumbTags + }; + }, + count: function () { + return !!self.previewCache.data && !!self.previewCache.data.content ? + self.previewCache.data.content.length : 0; + }, + get: function (i, isDisabled) { + var ind = 'init_' + i, data = self.previewCache.data, config = data.config[i], + content = data.content[i], previewId = self.previewInitId + '-' + ind, out, $tmp, cat, ftr, + fname, ftype, frameClass, asData = $h.ifSet('previewAsData', config, self.initialPreviewAsData), + parseTemplate = function (cat, dat, fn, ft, id, ftr, ind, fc, t) { + fc = ' file-preview-initial ' + $h.SORT_CSS + (fc ? ' ' + fc : ''); + return self._generatePreviewTemplate(cat, dat, fn, ft, id, false, null, fc, ftr, ind, t); + }; + if (!content) { + return ''; + } + isDisabled = isDisabled === undefined ? true : isDisabled; + cat = $h.ifSet('type', config, self.initialPreviewFileType || 'generic'); + fname = $h.ifSet('filename', config, $h.ifSet('caption', config)); + ftype = $h.ifSet('filetype', config, cat); + ftr = self.previewCache.footer(i, isDisabled, (config && config.size || null)); + frameClass = $h.ifSet('frameClass', config); + if (asData) { + out = parseTemplate(cat, content, fname, ftype, previewId, ftr, ind, frameClass); + } else { + out = parseTemplate('generic', content, fname, ftype, previewId, ftr, ind, frameClass, cat) + .setTokens({'content': data.content[i]}); + } + if (data.tags.length && data.tags[i]) { + out = $h.replaceTags(out, data.tags[i]); + } + /** @namespace config.frameAttr */ + if (!$h.isEmpty(config) && !$h.isEmpty(config.frameAttr)) { + $tmp = $(document.createElement('div')).html(out); + $tmp.find('.file-preview-initial').attr(config.frameAttr); + out = $tmp.html(); + $tmp.remove(); + } + return out; + }, + add: function (content, config, tags, append) { + var data = self.previewCache.data, index; + if (!$h.isArray(content)) { + content = content.split(self.initialPreviewDelimiter); + } + if (append) { + index = data.content.push(content) - 1; + data.config[index] = config; + data.tags[index] = tags; + } else { + index = content.length - 1; + data.content = content; + data.config = config; + data.tags = tags; + } + self.previewCache.data = data; + return index; + }, + set: function (content, config, tags, append) { + var data = self.previewCache.data, i, chk; + if (!content || !content.length) { + return; + } + if (!$h.isArray(content)) { + content = content.split(self.initialPreviewDelimiter); + } + chk = content.filter(function (n) { + return n !== null; + }); + if (!chk.length) { + return; + } + if (data.content === undefined) { + data.content = []; + } + if (data.config === undefined) { + data.config = []; + } + if (data.tags === undefined) { + data.tags = []; + } + if (append) { + for (i = 0; i < content.length; i++) { + if (content[i]) { + data.content.push(content[i]); + } + } + for (i = 0; i < config.length; i++) { + if (config[i]) { + data.config.push(config[i]); + } + } + for (i = 0; i < tags.length; i++) { + if (tags[i]) { + data.tags.push(tags[i]); + } + } + } else { + data.content = content; + data.config = config; + data.tags = tags; + } + self.previewCache.data = data; + }, + unset: function (index) { + var chk = self.previewCache.count(), rev = self.reversePreviewOrder; + if (!chk) { + return; + } + if (chk === 1) { + self.previewCache.data.content = []; + self.previewCache.data.config = []; + self.previewCache.data.tags = []; + self.initialPreview = []; + self.initialPreviewConfig = []; + self.initialPreviewThumbTags = []; + return; + } + self.previewCache.data.content = $h.spliceArray(self.previewCache.data.content, index, rev); + self.previewCache.data.config = $h.spliceArray(self.previewCache.data.config, index, rev); + self.previewCache.data.tags = $h.spliceArray(self.previewCache.data.tags, index, rev); + }, + out: function () { + var html = '', caption, len = self.previewCache.count(), i, content; + if (len === 0) { + return {content: '', caption: ''}; + } + for (i = 0; i < len; i++) { + content = self.previewCache.get(i); + html = self.reversePreviewOrder ? (content + html) : (html + content); + } + caption = self._getMsgSelected(len); + return {content: html, caption: caption}; + }, + footer: function (i, isDisabled, size) { + var data = self.previewCache.data || {}; + if ($h.isEmpty(data.content)) { + return ''; + } + if ($h.isEmpty(data.config) || $h.isEmpty(data.config[i])) { + data.config[i] = {}; + } + isDisabled = isDisabled === undefined ? true : isDisabled; + var config = data.config[i], caption = $h.ifSet('caption', config), a, + width = $h.ifSet('width', config, 'auto'), url = $h.ifSet('url', config, false), + key = $h.ifSet('key', config, null), fs = self.fileActionSettings, + initPreviewShowDel = self.initialPreviewShowDelete || false, + dUrl = config.downloadUrl || self.initialPreviewDownloadUrl || '', + dFil = config.filename || config.caption || '', + initPreviewShowDwl = !!(dUrl), + sDel = $h.ifSet('showRemove', config, $h.ifSet('showRemove', fs, initPreviewShowDel)), + sDwl = $h.ifSet('showDownload', config, $h.ifSet('showDownload', fs, initPreviewShowDwl)), + sZm = $h.ifSet('showZoom', config, $h.ifSet('showZoom', fs, true)), + sDrg = $h.ifSet('showDrag', config, $h.ifSet('showDrag', fs, true)), + dis = (url === false) && isDisabled; + sDwl = sDwl && config.downloadUrl !== false && !!dUrl; + a = self._renderFileActions(false, sDwl, sDel, sZm, sDrg, dis, url, key, true, dUrl, dFil); + return self._getLayoutTemplate('footer').setTokens({ + 'progress': self._renderThumbProgress(), + 'actions': a, + 'caption': caption, + 'size': self._getSize(size), + 'width': width, + 'indicator': '' + }); + } + }; + self.previewCache.init(); + }, + _handler: function ($el, event, callback) { + var self = this, ns = self.namespace, ev = event.split(' ').join(ns + ' ') + ns; + if (!$el || !$el.length) { + return; + } + $el.off(ev).on(ev, callback); + }, + _log: function (msg) { + var self = this, id = self.$element.attr('id'); + if (id) { + msg = '"' + id + '": ' + msg; + } + if (typeof window.console.log !== "undefined") { + window.console.log(msg); + } else { + window.alert(msg); + } + }, + _validate: function () { + var self = this, status = self.$element.attr('type') === 'file'; + if (!status) { + self._log('The input "type" must be set to "file" for initializing the "bootstrap-fileinput" plugin.'); + } + return status; + }, + _errorsExist: function () { + var self = this, $err, $errList = self.$errorContainer.find('li'); + if ($errList.length) { + return true; + } + $err = $(document.createElement('div')).html(self.$errorContainer.html()); + $err.find('.kv-error-close').remove(); + $err.find('ul').remove(); + return !!$.trim($err.text()).length; + }, + _errorHandler: function (evt, caption) { + var self = this, err = evt.target.error, showError = function (msg) { + self._showError(msg.replace('{name}', caption)); + }; + /** @namespace err.NOT_FOUND_ERR */ + /** @namespace err.SECURITY_ERR */ + /** @namespace err.NOT_READABLE_ERR */ + if (err.code === err.NOT_FOUND_ERR) { + showError(self.msgFileNotFound); + } else if (err.code === err.SECURITY_ERR) { + showError(self.msgFileSecured); + } else if (err.code === err.NOT_READABLE_ERR) { + showError(self.msgFileNotReadable); + } else if (err.code === err.ABORT_ERR) { + showError(self.msgFilePreviewAborted); + } else { + showError(self.msgFilePreviewError); + } + }, + _addError: function (msg) { + var self = this, $error = self.$errorContainer; + if (msg && $error.length) { + $error.html(self.errorCloseButton + msg); + self._handler($error.find('.kv-error-close'), 'click', function () { + setTimeout(function () { + if (self.showPreview && !self.getFrames().length) { + self.clear(); + } + $error.fadeOut('slow'); + }, 10); + }); + } + }, + _setValidationError: function (css) { + var self = this; + css = (css ? css + ' ' : '') + 'has-error'; + self.$container.removeClass(css).addClass('has-error'); + $h.addCss(self.$captionContainer, 'is-invalid'); + }, + _resetErrors: function (fade) { + var self = this, $error = self.$errorContainer; + self.isError = false; + self.$container.removeClass('has-error'); + self.$captionContainer.removeClass('is-invalid'); + $error.html(''); + if (fade) { + $error.fadeOut('slow'); + } else { + $error.hide(); + } + }, + _showFolderError: function (folders) { + var self = this, $error = self.$errorContainer, msg; + if (!folders) { + return; + } + if (!self.isAjaxUpload) { + self._clearFileInput(); + } + msg = self.msgFoldersNotAllowed.replace('{n}', folders); + self._addError(msg); + self._setValidationError(); + $error.fadeIn(800); + self._raise('filefoldererror', [folders, msg]); + }, + _showUploadError: function (msg, params, event) { + var self = this, $error = self.$errorContainer, ev = event || 'fileuploaderror', e = params && params.id ? + '' + msg + '' : '' + msg + ''; + if ($error.find('ul').length === 0) { + self._addError('' + e + ''); + } else { + $error.find('ul').append(e); + } + $error.fadeIn(800); + self._raise(ev, [params, msg]); + self._setValidationError('file-input-new'); + return true; + }, + _showError: function (msg, params, event) { + var self = this, $error = self.$errorContainer, ev = event || 'fileerror'; + params = params || {}; + params.reader = self.reader; + self._addError(msg); + $error.fadeIn(800); + self._raise(ev, [params, msg]); + if (!self.isAjaxUpload) { + self._clearFileInput(); + } + self._setValidationError('file-input-new'); + self.$btnUpload.attr('disabled', true); + return true; + }, + _noFilesError: function (params) { + var self = this, label = self.minFileCount > 1 ? self.filePlural : self.fileSingle, + msg = self.msgFilesTooLess.replace('{n}', self.minFileCount).replace('{files}', label), + $error = self.$errorContainer; + self._addError(msg); + self.isError = true; + self._updateFileDetails(0); + $error.fadeIn(800); + self._raise('fileerror', [params, msg]); + self._clearFileInput(); + self._setValidationError(); + }, + _parseError: function (operation, jqXHR, errorThrown, fileName) { + /** @namespace jqXHR.responseJSON */ + var self = this, errMsg = $.trim(errorThrown + ''), textPre, + text = jqXHR.responseJSON !== undefined && jqXHR.responseJSON.error !== undefined ? + jqXHR.responseJSON.error : jqXHR.responseText; + if (self.cancelling && self.msgUploadAborted) { + errMsg = self.msgUploadAborted; + } + if (self.showAjaxErrorDetails && text) { + text = $.trim(text.replace(/\n\s*\n/g, '\n')); + textPre = text.length ? '' + text + '' : ''; + errMsg += errMsg ? textPre : text; + } + if (!errMsg) { + errMsg = self.msgAjaxError.replace('{operation}', operation); + } + self.cancelling = false; + return fileName ? '' + fileName + ': ' + errMsg : errMsg; + }, + _parseFileType: function (type, name) { + var self = this, isValid, vType, cat, i, types = self.allowedPreviewTypes || []; + if (type === 'application/text-plain') { + return 'text'; + } + for (i = 0; i < types.length; i++) { + cat = types[i]; + isValid = self.fileTypeSettings[cat]; + vType = isValid(type, name) ? cat : ''; + if (!$h.isEmpty(vType)) { + return vType; + } + } + return 'other'; + }, + _getPreviewIcon: function (fname) { + var self = this, ext, out = null; + if (fname && fname.indexOf('.') > -1) { + ext = fname.split('.').pop(); + if (self.previewFileIconSettings) { + out = self.previewFileIconSettings[ext] || self.previewFileIconSettings[ext.toLowerCase()] || null; + } + if (self.previewFileExtSettings) { + $.each(self.previewFileExtSettings, function (key, func) { + if (self.previewFileIconSettings[key] && func(ext)) { + out = self.previewFileIconSettings[key]; + //noinspection UnnecessaryReturnStatementJS + return; + } + }); + } + } + return out; + }, + _parseFilePreviewIcon: function (content, fname) { + var self = this, icn = self._getPreviewIcon(fname) || self.previewFileIcon, out = content; + if (out.indexOf('{previewFileIcon}') > -1) { + out = out.setTokens({'previewFileIconClass': self.previewFileIconClass, 'previewFileIcon': icn}); + } + return out; + }, + _raise: function (event, params) { + var self = this, e = $.Event(event); + if (params !== undefined) { + self.$element.trigger(e, params); + } else { + self.$element.trigger(e); + } + if (e.isDefaultPrevented() || e.result === false) { + return false; + } + switch (event) { + // ignore these events + case 'filebatchuploadcomplete': + case 'filebatchuploadsuccess': + case 'fileuploaded': + case 'fileclear': + case 'filecleared': + case 'filereset': + case 'fileerror': + case 'filefoldererror': + case 'fileuploaderror': + case 'filebatchuploaderror': + case 'filedeleteerror': + case 'filecustomerror': + case 'filesuccessremove': + break; + // receive data response via `filecustomerror` event` + default: + if (!self.ajaxAborted) { + self.ajaxAborted = e.result; + } + break; + } + return true; + }, + _listenFullScreen: function (isFullScreen) { + var self = this, $modal = self.$modal, $btnFull, $btnBord; + if (!$modal || !$modal.length) { + return; + } + $btnFull = $modal && $modal.find('.btn-fullscreen'); + $btnBord = $modal && $modal.find('.btn-borderless'); + if (!$btnFull.length || !$btnBord.length) { + return; + } + $btnFull.removeClass('active').attr('aria-pressed', 'false'); + $btnBord.removeClass('active').attr('aria-pressed', 'false'); + if (isFullScreen) { + $btnFull.addClass('active').attr('aria-pressed', 'true'); + } else { + $btnBord.addClass('active').attr('aria-pressed', 'true'); + } + if ($modal.hasClass('file-zoom-fullscreen')) { + self._maximizeZoomDialog(); + } else { + if (isFullScreen) { + self._maximizeZoomDialog(); + } else { + $btnBord.removeClass('active').attr('aria-pressed', 'false'); + } + } + }, + _listen: function () { + var self = this, $el = self.$element, $form = self.$form, $cont = self.$container, fullScreenEvents; + self._handler($el, 'click', function(e) { + if ($el.hasClass('file-no-browse')) { + if ($el.data('zoneClicked')) { + $el.data('zoneClicked', false); + } else { + e.preventDefault(); + } + } + }); + self._handler($el, 'change', $.proxy(self._change, self)); + if (self.showBrowse) { + self._handler(self.$btnFile, 'click', $.proxy(self._browse, self)); + } + self._handler($cont.find('.fileinput-remove:not([disabled])'), 'click', $.proxy(self.clear, self)); + self._handler($cont.find('.fileinput-cancel'), 'click', $.proxy(self.cancel, self)); + self._initDragDrop(); + self._handler($form, 'reset', $.proxy(self.clear, self)); + if (!self.isAjaxUpload) { + self._handler($form, 'submit', $.proxy(self._submitForm, self)); + } + self._handler(self.$container.find('.fileinput-upload'), 'click', $.proxy(self._uploadClick, self)); + self._handler($(window), 'resize', function () { + self._listenFullScreen(screen.width === window.innerWidth && screen.height === window.innerHeight); + }); + fullScreenEvents = 'webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange'; + self._handler($(document), fullScreenEvents, function () { + self._listenFullScreen($h.checkFullScreen()); + }); + self._autoFitContent(); + self._initClickable(); + self._refreshPreview(); + }, + _autoFitContent: function () { + var width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth, + self = this, config = width < 400 ? (self.previewSettingsSmall || self.defaults.previewSettingsSmall) : + (self.previewSettings || self.defaults.previewSettings), sel; + $.each(config, function (cat, settings) { + sel = '.file-preview-frame .file-preview-' + cat; + self.$preview.find(sel + '.kv-preview-data,' + sel + ' .kv-preview-data').css(settings); + }); + }, + _scanDroppedItems: function (item, files, path) { + path = path || ""; + var self = this, i, dirReader, readDir, errorHandler = function (e) { + self._log('Error scanning dropped files!'); + self._log(e); + }; + if (item.isFile) { + item.file(function (file) { + files.push(file); + }, errorHandler); + } else { + if (item.isDirectory) { + dirReader = item.createReader(); + readDir = function () { + dirReader.readEntries(function (entries) { + if (entries && entries.length > 0) { + for (i = 0; i < entries.length; i++) { + self._scanDroppedItems(entries[i], files, path + item.name + "/"); + } + // recursively call readDir() again, since browser can only handle first 100 entries. + readDir(); + } + return null; + }, errorHandler); + }; + readDir(); + } + } + + }, + _initDragDrop: function () { + var self = this, $zone = self.$dropZone; + if (self.dropZoneEnabled && self.showPreview) { + self._handler($zone, 'dragenter dragover', $.proxy(self._zoneDragEnter, self)); + self._handler($zone, 'dragleave', $.proxy(self._zoneDragLeave, self)); + self._handler($zone, 'drop', $.proxy(self._zoneDrop, self)); + self._handler($(document), 'dragenter dragover drop', self._zoneDragDropInit); + } + }, + _zoneDragDropInit: function (e) { + e.stopPropagation(); + e.preventDefault(); + }, + _zoneDragEnter: function (e) { + var self = this, hasFiles = $.inArray('Files', e.originalEvent.dataTransfer.types) > -1; + self._zoneDragDropInit(e); + if (self.isDisabled || !hasFiles) { + e.originalEvent.dataTransfer.effectAllowed = 'none'; + e.originalEvent.dataTransfer.dropEffect = 'none'; + return; + } + $h.addCss(self.$dropZone, 'file-highlighted'); + }, + _zoneDragLeave: function (e) { + var self = this; + self._zoneDragDropInit(e); + if (self.isDisabled) { + return; + } + self.$dropZone.removeClass('file-highlighted'); + }, + _zoneDrop: function (e) { + /** @namespace e.originalEvent.dataTransfer */ + var self = this, i, $el = self.$element, dataTransfer = e.originalEvent.dataTransfer, + files = dataTransfer.files, items = dataTransfer.items, folders = $h.getDragDropFolders(items), + processFiles = function () { + if (!self.isAjaxUpload) { + self.changeTriggered = true; + $el.get(0).files = files; + setTimeout(function () { + self.changeTriggered = false; + $el.trigger('change' + self.namespace); + }, 10); + } else { + self._change(e, files); + } + self.$dropZone.removeClass('file-highlighted'); + }; + e.preventDefault(); + if (self.isDisabled || $h.isEmpty(files)) { + return; + } + if (folders > 0) { + if (!self.isAjaxUpload) { + self._showFolderError(folders); + return; + } + files = []; + for (i = 0; i < items.length; i++) { + var item = items[i].webkitGetAsEntry(); + if (item) { + self._scanDroppedItems(item, files); + } + } + setTimeout(function () { + processFiles(); + }, 500); + } else { + processFiles(); + } + }, + _uploadClick: function (e) { + var self = this, $btn = self.$container.find('.fileinput-upload'), $form, + isEnabled = !$btn.hasClass('disabled') && $h.isEmpty($btn.attr('disabled')); + if (e && e.isDefaultPrevented()) { + return; + } + if (!self.isAjaxUpload) { + if (isEnabled && $btn.attr('type') !== 'submit') { + $form = $btn.closest('form'); + // downgrade to normal form submit if possible + if ($form.length) { + $form.trigger('submit'); + } + e.preventDefault(); + } + return; + } + e.preventDefault(); + if (isEnabled) { + self.upload(); + } + }, + _submitForm: function () { + var self = this; + return self._isFileSelectionValid() && !self._abort({}); + }, + _clearPreview: function () { + var self = this, $p = self.$preview, + $thumbs = self.showUploadedThumbs ? self.getFrames(':not(.file-preview-success)') : self.getFrames(); + $thumbs.each(function () { + var $thumb = $(this); + $thumb.remove(); + $h.cleanZoomCache($p.find('#zoom-' + $thumb.attr('id'))); + }); + if (!self.getFrames().length || !self.showPreview) { + self._resetUpload(); + } + self._validateDefaultPreview(); + }, + _initSortable: function () { + var self = this, $el = self.$preview, settings, selector = '.' + $h.SORT_CSS, + rev = self.reversePreviewOrder; + if (!window.KvSortable || $el.find(selector).length === 0) { + return; + } + //noinspection JSUnusedGlobalSymbols + settings = { + handle: '.drag-handle-init', + dataIdAttr: 'data-preview-id', + scroll: false, + draggable: selector, + onSort: function (e) { + var oldIndex = e.oldIndex, newIndex = e.newIndex, i = 0; + self.initialPreview = $h.moveArray(self.initialPreview, oldIndex, newIndex, rev); + self.initialPreviewConfig = $h.moveArray(self.initialPreviewConfig, oldIndex, newIndex, rev); + self.previewCache.init(); + self.getFrames('.file-preview-initial').each(function () { + $(this).attr('data-fileindex', 'init_' + i); + i++; + }); + self._raise('filesorted', { + previewId: $(e.item).attr('id'), + 'oldIndex': oldIndex, + 'newIndex': newIndex, + stack: self.initialPreviewConfig + }); + } + }; + if ($el.data('kvsortable')) { + $el.kvsortable('destroy'); + } + $.extend(true, settings, self.fileActionSettings.dragSettings); + $el.kvsortable(settings); + }, + _setPreviewContent: function (content) { + var self = this; + self.$preview.html(content); + self._autoFitContent(); + }, + _initPreview: function (isInit) { + var self = this, cap = self.initialCaption || '', out; + if (!self.previewCache.count()) { + self._clearPreview(); + if (isInit) { + self._setCaption(cap); + } else { + self._initCaption(); + } + return; + } + out = self.previewCache.out(); + cap = isInit && self.initialCaption ? self.initialCaption : out.caption; + self._setPreviewContent(out.content); + self._setInitThumbAttr(); + self._setCaption(cap); + self._initSortable(); + if (!$h.isEmpty(out.content)) { + self.$container.removeClass('file-input-new'); + } + }, + _getZoomButton: function (type) { + var self = this, label = self.previewZoomButtonIcons[type], css = self.previewZoomButtonClasses[type], + title = ' title="' + (self.previewZoomButtonTitles[type] || '') + '" ', + params = title + (type === 'close' ? ' data-dismiss="modal" aria-hidden="true"' : ''); + if (type === 'fullscreen' || type === 'borderless' || type === 'toggleheader') { + params += ' data-toggle="button" aria-pressed="false" autocomplete="off"'; + } + return '' + label + ''; + }, + _getModalContent: function () { + var self = this; + return self._getLayoutTemplate('modal').setTokens({ + 'rtl': self.rtl ? ' kv-rtl' : '', + 'zoomFrameClass': self.frameClass, + 'heading': self.msgZoomModalHeading, + 'prev': self._getZoomButton('prev'), + 'next': self._getZoomButton('next'), + 'toggleheader': self._getZoomButton('toggleheader'), + 'fullscreen': self._getZoomButton('fullscreen'), + 'borderless': self._getZoomButton('borderless'), + 'close': self._getZoomButton('close') + }); + }, + _listenModalEvent: function (event) { + var self = this, $modal = self.$modal, getParams = function (e) { + return { + sourceEvent: e, + previewId: $modal.data('previewId'), + modal: $modal + }; + }; + $modal.on(event + '.bs.modal', function (e) { + var $btnFull = $modal.find('.btn-fullscreen'), $btnBord = $modal.find('.btn-borderless'); + self._raise('filezoom' + event, getParams(e)); + if (event === 'shown') { + $btnBord.removeClass('active').attr('aria-pressed', 'false'); + $btnFull.removeClass('active').attr('aria-pressed', 'false'); + if ($modal.hasClass('file-zoom-fullscreen')) { + self._maximizeZoomDialog(); + if ($h.checkFullScreen()) { + $btnFull.addClass('active').attr('aria-pressed', 'true'); + } else { + $btnBord.addClass('active').attr('aria-pressed', 'true'); + } + } + } + }); + }, + _initZoom: function () { + var self = this, $dialog, modalMain = self._getLayoutTemplate('modalMain'), modalId = '#' + $h.MODAL_ID; + if (!self.showPreview) { + return; + } + self.$modal = $(modalId); + if (!self.$modal || !self.$modal.length) { + $dialog = $(document.createElement('div')).html(modalMain).insertAfter(self.$container); + self.$modal = $(modalId).insertBefore($dialog); + $dialog.remove(); + } + $h.initModal(self.$modal); + self.$modal.html(self._getModalContent()); + $.each($h.MODAL_EVENTS, function (key, event) { + self._listenModalEvent(event); + }); + }, + _initZoomButtons: function () { + var self = this, previewId = self.$modal.data('previewId') || '', $first, $last, + thumbs = self.getFrames().toArray(), len = thumbs.length, $prev = self.$modal.find('.btn-prev'), + $next = self.$modal.find('.btn-next'); + if (thumbs.length < 2) { + $prev.hide(); + $next.hide(); + return; + } else { + $prev.show(); + $next.show(); + } + if (!len) { + return; + } + $first = $(thumbs[0]); + $last = $(thumbs[len - 1]); + $prev.removeAttr('disabled'); + $next.removeAttr('disabled'); + if ($first.length && $first.attr('id') === previewId) { + $prev.attr('disabled', true); + } + if ($last.length && $last.attr('id') === previewId) { + $next.attr('disabled', true); + } + }, + _maximizeZoomDialog: function () { + var self = this, $modal = self.$modal, $head = $modal.find('.modal-header:visible'), + $foot = $modal.find('.modal-footer:visible'), $body = $modal.find('.modal-body'), + h = $(window).height(), diff = 0; + $modal.addClass('file-zoom-fullscreen'); + if ($head && $head.length) { + h -= $head.outerHeight(true); + } + if ($foot && $foot.length) { + h -= $foot.outerHeight(true); + } + if ($body && $body.length) { + diff = $body.outerHeight(true) - $body.height(); + h -= diff; + } + $modal.find('.kv-zoom-body').height(h); + }, + _resizeZoomDialog: function (fullScreen) { + var self = this, $modal = self.$modal, $btnFull = $modal.find('.btn-fullscreen'), + $btnBord = $modal.find('.btn-borderless'); + if ($modal.hasClass('file-zoom-fullscreen')) { + $h.toggleFullScreen(false); + if (!fullScreen) { + if (!$btnFull.hasClass('active')) { + $modal.removeClass('file-zoom-fullscreen'); + self.$modal.find('.kv-zoom-body').css('height', self.zoomModalHeight); + } else { + $btnFull.removeClass('active').attr('aria-pressed', 'false'); + } + } else { + if (!$btnFull.hasClass('active')) { + $modal.removeClass('file-zoom-fullscreen'); + self._resizeZoomDialog(true); + if ($btnBord.hasClass('active')) { + $btnBord.removeClass('active').attr('aria-pressed', 'false'); + } + } + } + } else { + if (!fullScreen) { + self._maximizeZoomDialog(); + return; + } + $h.toggleFullScreen(true); + } + $modal.focus(); + }, + _setZoomContent: function ($frame, animate) { + var self = this, $content, tmplt, body, title, $body, $dataEl, config, pid = $frame.attr('id'), + $modal = self.$modal, $prev = $modal.find('.btn-prev'), $next = $modal.find('.btn-next'), $tmp, + $btnFull = $modal.find('.btn-fullscreen'), $btnBord = $modal.find('.btn-borderless'), cap, size, + $btnTogh = $modal.find('.btn-toggleheader'), $zoomPreview = self.$preview.find('#zoom-' + pid); + tmplt = $zoomPreview.attr('data-template') || 'generic'; + $content = $zoomPreview.find('.kv-file-content'); + body = $content.length ? $content.html() : ''; + cap = $frame.data('caption') || ''; + size = $frame.data('size') || ''; + title = cap + ' ' + size; + $modal.find('.kv-zoom-title').attr('title', $('').html(title).text()).html(title); + $body = $modal.find('.kv-zoom-body'); + $modal.removeClass('kv-single-content'); + if (animate) { + $tmp = $body.addClass('file-thumb-loading').clone().insertAfter($body); + $body.html(body).hide(); + $tmp.fadeOut('fast', function () { + $body.fadeIn('fast', function () { + $body.removeClass('file-thumb-loading'); + }); + $tmp.remove(); + }); + } else { + $body.html(body); + } + config = self.previewZoomSettings[tmplt]; + if (config) { + $dataEl = $body.find('.kv-preview-data'); + $h.addCss($dataEl, 'file-zoom-detail'); + $.each(config, function (key, value) { + $dataEl.css(key, value); + if (($dataEl.attr('width') && key === 'width') || ($dataEl.attr('height') && key === 'height')) { + $dataEl.removeAttr(key); + } + }); + } + $modal.data('previewId', pid); + var $img = $body.find('img'); + if ($img.length) { + $h.adjustOrientedImage($img, true); + } + self._handler($prev, 'click', function () { + self._zoomSlideShow('prev', pid); + }); + self._handler($next, 'click', function () { + self._zoomSlideShow('next', pid); + }); + self._handler($btnFull, 'click', function () { + self._resizeZoomDialog(true); + }); + self._handler($btnBord, 'click', function () { + self._resizeZoomDialog(false); + }); + self._handler($btnTogh, 'click', function () { + var $header = $modal.find('.modal-header'), $floatBar = $modal.find('.modal-body .floating-buttons'), + ht, $actions = $header.find('.kv-zoom-actions'), resize = function (height) { + var $body = self.$modal.find('.kv-zoom-body'), h = self.zoomModalHeight; + if ($modal.hasClass('file-zoom-fullscreen')) { + h = $body.outerHeight(true); + if (!height) { + h = h - $header.outerHeight(true); + } + } + $body.css('height', height ? h + height : h); + }; + if ($header.is(':visible')) { + ht = $header.outerHeight(true); + $header.slideUp('slow', function () { + $actions.find('.btn').appendTo($floatBar); + resize(ht); + }); + } else { + $floatBar.find('.btn').appendTo($actions); + $header.slideDown('slow', function () { + resize(); + }); + } + $modal.focus(); + }); + self._handler($modal, 'keydown', function (e) { + var key = e.which || e.keyCode; + if (key === 37 && !$prev.attr('disabled')) { + self._zoomSlideShow('prev', pid); + } + if (key === 39 && !$next.attr('disabled')) { + self._zoomSlideShow('next', pid); + } + }); + }, + _zoomPreview: function ($btn) { + var self = this, $frame, $modal = self.$modal; + if (!$btn.length) { + throw 'Cannot zoom to detailed preview!'; + } + $h.initModal($modal); + $modal.html(self._getModalContent()); + $frame = $btn.closest($h.FRAMES); + self._setZoomContent($frame); + $modal.modal('show'); + self._initZoomButtons(); + }, + _zoomSlideShow: function (dir, previewId) { + var self = this, $btn = self.$modal.find('.kv-zoom-actions .btn-' + dir), $targFrame, i, + thumbs = self.getFrames().toArray(), len = thumbs.length, out; + if ($btn.attr('disabled')) { + return; + } + for (i = 0; i < len; i++) { + if ($(thumbs[i]).attr('id') === previewId) { + out = dir === 'prev' ? i - 1 : i + 1; + break; + } + } + if (out < 0 || out >= len || !thumbs[out]) { + return; + } + $targFrame = $(thumbs[out]); + if ($targFrame.length) { + self._setZoomContent($targFrame, true); + } + self._initZoomButtons(); + self._raise('filezoom' + dir, {'previewId': previewId, modal: self.$modal}); + }, + _initZoomButton: function () { + var self = this; + self.$preview.find('.kv-file-zoom').each(function () { + var $el = $(this); + self._handler($el, 'click', function () { + self._zoomPreview($el); + }); + }); + }, + _inputFileCount: function() { + return this.$element.get(0).files.length; + }, + _refreshPreview: function() { + var self = this, files; + if (!self._inputFileCount() || !self.showPreview || !self.isPreviewable) { + return; + } + if (self.isAjaxUpload) { + files = self.getFileStack(); + self.filestack = []; + if (files.length) { + self._clearFileInput(); + } else { + files = self.$element.get(0).files; + } + } else { + files = self.$element.get(0).files; + } + if (files && files.length) { + self.readFiles(files); + self._setFileDropZoneTitle(); + } + }, + _clearObjects: function ($el) { + $el.find('video audio').each(function () { + this.pause(); + $(this).remove(); + }); + $el.find('img object div').each(function () { + $(this).remove(); + }); + }, + _clearFileInput: function () { + var self = this, $el = self.$element, $srcFrm, $tmpFrm, $tmpEl; + if (!self._inputFileCount()) { + return; + } + $srcFrm = $el.closest('form'); + $tmpFrm = $(document.createElement('form')); + $tmpEl = $(document.createElement('div')); + $el.before($tmpEl); + if ($srcFrm.length) { + $srcFrm.after($tmpFrm); + } else { + $tmpEl.after($tmpFrm); + } + $tmpFrm.append($el).trigger('reset'); + $tmpEl.before($el).remove(); + $tmpFrm.remove(); + }, + _resetUpload: function () { + var self = this; + self.uploadCache = {content: [], config: [], tags: [], append: true}; + self.uploadCount = 0; + self.uploadStatus = {}; + self.uploadLog = []; + self.uploadAsyncCount = 0; + self.loadedImages = []; + self.totalImagesCount = 0; + self.$btnUpload.removeAttr('disabled'); + self._setProgress(0); + self.$progress.hide(); + self._resetErrors(false); + self.ajaxAborted = false; + self.ajaxRequests = []; + self._resetCanvas(); + self.cacheInitialPreview = {}; + if (self.overwriteInitial) { + self.initialPreview = []; + self.initialPreviewConfig = []; + self.initialPreviewThumbTags = []; + self.previewCache.data = { + content: [], + config: [], + tags: [] + }; + } + }, + _resetCanvas: function () { + var self = this; + if (self.canvas && self.imageCanvasContext) { + self.imageCanvasContext.clearRect(0, 0, self.canvas.width, self.canvas.height); + } + }, + _hasInitialPreview: function () { + var self = this; + return !self.overwriteInitial && self.previewCache.count(); + }, + _resetPreview: function () { + var self = this, out, cap; + if (self.previewCache.count()) { + out = self.previewCache.out(); + self._setPreviewContent(out.content); + self._setInitThumbAttr(); + cap = self.initialCaption ? self.initialCaption : out.caption; + self._setCaption(cap); + } else { + self._clearPreview(); + self._initCaption(); + } + if (self.showPreview) { + self._initZoom(); + self._initSortable(); + } + }, + _clearDefaultPreview: function () { + var self = this; + self.$preview.find('.file-default-preview').remove(); + }, + _validateDefaultPreview: function () { + var self = this; + if (!self.showPreview || $h.isEmpty(self.defaultPreviewContent)) { + return; + } + self._setPreviewContent('' + self.defaultPreviewContent + ''); + self.$container.removeClass('file-input-new'); + self._initClickable(); + }, + _resetPreviewThumbs: function (isAjax) { + var self = this, out; + if (isAjax) { + self._clearPreview(); + self.clearStack(); + return; + } + if (self._hasInitialPreview()) { + out = self.previewCache.out(); + self._setPreviewContent(out.content); + self._setInitThumbAttr(); + self._setCaption(out.caption); + self._initPreviewActions(); + } else { + self._clearPreview(); + } + }, + _getLayoutTemplate: function (t) { + var self = this, template = self.layoutTemplates[t]; + if ($h.isEmpty(self.customLayoutTags)) { + return template; + } + return $h.replaceTags(template, self.customLayoutTags); + }, + _getPreviewTemplate: function (t) { + var self = this, template = self.previewTemplates[t]; + if ($h.isEmpty(self.customPreviewTags)) { + return template; + } + return $h.replaceTags(template, self.customPreviewTags); + }, + _getOutData: function (jqXHR, responseData, filesData) { + var self = this; + jqXHR = jqXHR || {}; + responseData = responseData || {}; + filesData = filesData || self.filestack.slice(0) || {}; + return { + form: self.formdata, + files: filesData, + filenames: self.filenames, + filescount: self.getFilesCount(), + extra: self._getExtraData(), + response: responseData, + reader: self.reader, + jqXHR: jqXHR + }; + }, + _getMsgSelected: function (n) { + var self = this, strFiles = n === 1 ? self.fileSingle : self.filePlural; + return n > 0 ? self.msgSelected.replace('{n}', n).replace('{files}', strFiles) : self.msgNoFilesSelected; + }, + _getFrame: function (id) { + var self = this, $frame = $('#' + id); + if (!$frame.length) { + self._log('Invalid thumb frame with id: "' + id + '".'); + return null; + } + return $frame; + }, + _getThumbs: function (css) { + css = css || ''; + return this.getFrames(':not(.file-preview-initial)' + css); + }, + _getExtraData: function (previewId, index) { + var self = this, data = self.uploadExtraData; + if (typeof self.uploadExtraData === "function") { + data = self.uploadExtraData(previewId, index); + } + return data; + }, + _initXhr: function (xhrobj, previewId, fileCount) { + var self = this; + if (xhrobj.upload) { + xhrobj.upload.addEventListener('progress', function (event) { + var pct = 0, total = event.total, position = event.loaded || event.position; + /** @namespace event.lengthComputable */ + if (event.lengthComputable) { + pct = Math.floor(position / total * 100); + } + if (previewId) { + self._setAsyncUploadStatus(previewId, pct, fileCount); + } else { + self._setProgress(pct); + } + }, false); + } + return xhrobj; + }, + _initAjaxSettings: function () { + var self = this; + self._ajaxSettings = $.extend(true, {}, self.ajaxSettings); + self._ajaxDeleteSettings = $.extend(true, {}, self.ajaxDeleteSettings); + }, + _mergeAjaxCallback: function (funcName, srcFunc, type) { + var self = this, settings = self._ajaxSettings, flag = self.mergeAjaxCallbacks, targFunc; + if (type === 'delete') { + settings = self._ajaxDeleteSettings; + flag = self.mergeAjaxDeleteCallbacks; + } + targFunc = settings[funcName]; + if (flag && typeof targFunc === "function") { + if (flag === 'before') { + settings[funcName] = function () { + targFunc.apply(this, arguments); + srcFunc.apply(this, arguments); + }; + } else { + settings[funcName] = function () { + srcFunc.apply(this, arguments); + targFunc.apply(this, arguments); + }; + } + } else { + settings[funcName] = srcFunc; + } + }, + _ajaxSubmit: function (fnBefore, fnSuccess, fnComplete, fnError, previewId, index) { + var self = this, settings; + if (!self._raise('filepreajax', [previewId, index])) { + return; + } + self._uploadExtra(previewId, index); + self._initAjaxSettings(); + self._mergeAjaxCallback('beforeSend', fnBefore); + self._mergeAjaxCallback('success', fnSuccess); + self._mergeAjaxCallback('complete', fnComplete); + self._mergeAjaxCallback('error', fnError); + settings = $.extend(true, {}, { + xhr: function () { + var xhrobj = $.ajaxSettings.xhr(); + return self._initXhr(xhrobj, previewId, self.getFileStack().length); + }, + url: index && self.uploadUrlThumb ? self.uploadUrlThumb : self.uploadUrl, + type: 'POST', + dataType: 'json', + data: self.formdata, + cache: false, + processData: false, + contentType: false + }, self._ajaxSettings); + self.ajaxRequests.push($.ajax(settings)); + }, + _mergeArray: function (prop, content) { + var self = this, arr1 = $h.cleanArray(self[prop]), arr2 = $h.cleanArray(content); + self[prop] = arr1.concat(arr2); + }, + _initUploadSuccess: function (out, $thumb, allFiles) { + var self = this, append, data, index, $div, $newCache, content, config, tags, i; + if (!self.showPreview || typeof out !== 'object' || $.isEmptyObject(out)) { + return; + } + if (out.initialPreview !== undefined && out.initialPreview.length > 0) { + self.hasInitData = true; + content = out.initialPreview || []; + config = out.initialPreviewConfig || []; + tags = out.initialPreviewThumbTags || []; + append = out.append === undefined || out.append; + if (content.length > 0 && !$h.isArray(content)) { + content = content.split(self.initialPreviewDelimiter); + } + self._mergeArray('initialPreview', content); + self._mergeArray('initialPreviewConfig', config); + self._mergeArray('initialPreviewThumbTags', tags); + if ($thumb !== undefined) { + if (!allFiles) { + index = self.previewCache.add(content, config[0], tags[0], append); + data = self.previewCache.get(index, false); + $div = $(document.createElement('div')).html(data).hide().insertAfter($thumb); + $newCache = $div.find('.kv-zoom-cache'); + if ($newCache && $newCache.length) { + $newCache.insertAfter($thumb); + } + $thumb.fadeOut('slow', function () { + var $newThumb = $div.find('.file-preview-frame'); + if ($newThumb && $newThumb.length) { + $newThumb.insertBefore($thumb).fadeIn('slow').css('display:inline-block'); + } + self._initPreviewActions(); + self._clearFileInput(); + $h.cleanZoomCache(self.$preview.find('#zoom-' + $thumb.attr('id'))); + $thumb.remove(); + $div.remove(); + self._initSortable(); + }); + } else { + i = $thumb.attr('data-fileindex'); + self.uploadCache.content[i] = content[0]; + self.uploadCache.config[i] = config[0] || []; + self.uploadCache.tags[i] = tags[0] || []; + self.uploadCache.append = append; + } + } else { + self.previewCache.set(content, config, tags, append); + self._initPreview(); + self._initPreviewActions(); + } + } + }, + _initSuccessThumbs: function () { + var self = this; + if (!self.showPreview) { + return; + } + self._getThumbs($h.FRAMES + '.file-preview-success').each(function () { + var $thumb = $(this), $preview = self.$preview, $remove = $thumb.find('.kv-file-remove'); + $remove.removeAttr('disabled'); + self._handler($remove, 'click', function () { + var id = $thumb.attr('id'), + out = self._raise('filesuccessremove', [id, $thumb.attr('data-fileindex')]); + $h.cleanMemory($thumb); + if (out === false) { + return; + } + $thumb.fadeOut('slow', function () { + $h.cleanZoomCache($preview.find('#zoom-' + id)); + $thumb.remove(); + if (!self.getFrames().length) { + self.reset(); + } + }); + }); + }); + }, + _checkAsyncComplete: function () { + var self = this, previewId, i; + for (i = 0; i < self.filestack.length; i++) { + if (self.filestack[i]) { + previewId = self.previewInitId + "-" + i; + if ($.inArray(previewId, self.uploadLog) === -1) { + return false; + } + } + } + return (self.uploadAsyncCount === self.uploadLog.length); + }, + _uploadExtra: function (previewId, index) { + var self = this, data = self._getExtraData(previewId, index); + if (data.length === 0) { + return; + } + $.each(data, function (key, value) { + self.formdata.append(key, value); + }); + }, + _uploadSingle: function (i, isBatch) { + var self = this, total = self.getFileStack().length, formdata = new FormData(), outData, + previewId = self.previewInitId + "-" + i, $thumb, chkComplete, $btnUpload, $btnDelete, + hasPostData = self.filestack.length > 0 || !$.isEmptyObject(self.uploadExtraData), uploadFailed, + $prog = $('#' + previewId).find('.file-thumb-progress'), fnBefore, fnSuccess, fnComplete, fnError, + updateUploadLog, params = {id: previewId, index: i}; + self.formdata = formdata; + if (self.showPreview) { + $thumb = $('#' + previewId + ':not(.file-preview-initial)'); + $btnUpload = $thumb.find('.kv-file-upload'); + $btnDelete = $thumb.find('.kv-file-remove'); + $prog.show(); + } + if (total === 0 || !hasPostData || ($btnUpload && $btnUpload.hasClass('disabled')) || self._abort(params)) { + return; + } + updateUploadLog = function (i, previewId) { + if (!uploadFailed) { + self.updateStack(i, undefined); + } + self.uploadLog.push(previewId); + if (self._checkAsyncComplete()) { + self.fileBatchCompleted = true; + } + }; + chkComplete = function () { + var u = self.uploadCache, $initThumbs, i, j, len = 0, data = self.cacheInitialPreview; + if (!self.fileBatchCompleted) { + return; + } + if (data && data.content) { + len = data.content.length; + } + setTimeout(function () { + var triggerReset = self.getFileStack(true).length === 0; + if (self.showPreview) { + self.previewCache.set(u.content, u.config, u.tags, u.append); + if (len) { + for (i = 0; i < u.content.length; i++) { + j = i + len; + data.content[j] = u.content[i]; + //noinspection JSUnresolvedVariable + if (data.config.length) { + data.config[j] = u.config[i]; + } + if (data.tags.length) { + data.tags[j] = u.tags[i]; + } + } + self.initialPreview = $h.cleanArray(data.content); + self.initialPreviewConfig = $h.cleanArray(data.config); + self.initialPreviewThumbTags = $h.cleanArray(data.tags); + } else { + self.initialPreview = u.content; + self.initialPreviewConfig = u.config; + self.initialPreviewThumbTags = u.tags; + } + self.cacheInitialPreview = {}; + if (self.hasInitData) { + self._initPreview(); + self._initPreviewActions(); + } + } + self.unlock(triggerReset); + if (triggerReset) { + self._clearFileInput(); + } + $initThumbs = self.$preview.find('.file-preview-initial'); + if (self.uploadAsync && $initThumbs.length) { + $h.addCss($initThumbs, $h.SORT_CSS); + self._initSortable(); + } + self._raise('filebatchuploadcomplete', [self.filestack, self._getExtraData()]); + self.uploadCount = 0; + self.uploadStatus = {}; + self.uploadLog = []; + self._setProgress(101); + self.ajaxAborted = false; + }, 100); + }; + fnBefore = function (jqXHR) { + outData = self._getOutData(jqXHR); + self.fileBatchCompleted = false; + if (!isBatch) { + self.ajaxAborted = false; + } + if (self.showPreview) { + if (!$thumb.hasClass('file-preview-success')) { + self._setThumbStatus($thumb, 'Loading'); + $h.addCss($thumb, 'file-uploading'); + } + $btnUpload.attr('disabled', true); + $btnDelete.attr('disabled', true); + } + if (!isBatch) { + self.lock(); + } + self._raise('filepreupload', [outData, previewId, i]); + $.extend(true, params, outData); + if (self._abort(params)) { + jqXHR.abort(); + if (!isBatch) { + self._setThumbStatus($thumb, 'New'); + $thumb.removeClass('file-uploading'); + $btnUpload.removeAttr('disabled'); + $btnDelete.removeAttr('disabled'); + self.unlock(); + } + self._setProgressCancelled(); + } + }; + fnSuccess = function (data, textStatus, jqXHR) { + var pid = self.showPreview && $thumb.attr('id') ? $thumb.attr('id') : previewId; + outData = self._getOutData(jqXHR, data); + $.extend(true, params, outData); + setTimeout(function () { + if ($h.isEmpty(data) || $h.isEmpty(data.error)) { + if (self.showPreview) { + self._setThumbStatus($thumb, 'Success'); + $btnUpload.hide(); + self._initUploadSuccess(data, $thumb, isBatch); + self._setProgress(101, $prog); + } + self._raise('fileuploaded', [outData, pid, i]); + if (!isBatch) { + self.updateStack(i, undefined); + } else { + updateUploadLog(i, pid); + } + } else { + uploadFailed = true; + self._showUploadError(data.error, params); + self._setPreviewError($thumb, i, self.filestack[i], self.retryErrorUploads); + if (!self.retryErrorUploads) { + $btnUpload.hide(); + } + if (isBatch) { + updateUploadLog(i, pid); + } + self._setProgress(101, $('#' + pid).find('.file-thumb-progress'), self.msgUploadError); + } + }, 100); + }; + fnComplete = function () { + setTimeout(function () { + if (self.showPreview) { + $btnUpload.removeAttr('disabled'); + $btnDelete.removeAttr('disabled'); + $thumb.removeClass('file-uploading'); + } + if (!isBatch) { + self.unlock(false); + self._clearFileInput(); + } else { + chkComplete(); + } + self._initSuccessThumbs(); + }, 100); + }; + fnError = function (jqXHR, textStatus, errorThrown) { + var op = self.ajaxOperations.uploadThumb, + errMsg = self._parseError(op, jqXHR, errorThrown, (isBatch && self.filestack[i].name ? self.filestack[i].name : null)); + uploadFailed = true; + setTimeout(function () { + if (isBatch) { + updateUploadLog(i, previewId); + } + self.uploadStatus[previewId] = 100; + self._setPreviewError($thumb, i, self.filestack[i], self.retryErrorUploads); + if (!self.retryErrorUploads) { + $btnUpload.hide(); + } + $.extend(true, params, self._getOutData(jqXHR)); + self._setProgress(101, $prog, self.msgAjaxProgressError.replace('{operation}', op)); + self._setProgress(101, $('#' + previewId).find('.file-thumb-progress'), self.msgUploadError); + self._showUploadError(errMsg, params); + }, 100); + }; + formdata.append(self.uploadFileAttr, self.filestack[i], self.filenames[i]); + formdata.append('file_id', i); + self._ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError, previewId, i); + }, + _uploadBatch: function () { + var self = this, files = self.filestack, total = files.length, params = {}, fnBefore, fnSuccess, fnError, + fnComplete, hasPostData = self.filestack.length > 0 || !$.isEmptyObject(self.uploadExtraData), + setAllUploaded; + self.formdata = new FormData(); + if (total === 0 || !hasPostData || self._abort(params)) { + return; + } + setAllUploaded = function () { + $.each(files, function (key) { + self.updateStack(key, undefined); + }); + self._clearFileInput(); + }; + fnBefore = function (jqXHR) { + self.lock(); + var outData = self._getOutData(jqXHR); + self.ajaxAborted = false; + if (self.showPreview) { + self._getThumbs().each(function () { + var $thumb = $(this), $btnUpload = $thumb.find('.kv-file-upload'), + $btnDelete = $thumb.find('.kv-file-remove'); + if (!$thumb.hasClass('file-preview-success')) { + self._setThumbStatus($thumb, 'Loading'); + $h.addCss($thumb, 'file-uploading'); + } + $btnUpload.attr('disabled', true); + $btnDelete.attr('disabled', true); + }); + } + self._raise('filebatchpreupload', [outData]); + if (self._abort(outData)) { + jqXHR.abort(); + self._getThumbs().each(function () { + var $thumb = $(this), $btnUpload = $thumb.find('.kv-file-upload'), + $btnDelete = $thumb.find('.kv-file-remove'); + if ($thumb.hasClass('file-preview-loading')) { + self._setThumbStatus($thumb, 'New'); + $thumb.removeClass('file-uploading'); + } + $btnUpload.removeAttr('disabled'); + $btnDelete.removeAttr('disabled'); + }); + self._setProgressCancelled(); + } + }; + fnSuccess = function (data, textStatus, jqXHR) { + /** @namespace data.errorkeys */ + var outData = self._getOutData(jqXHR, data), key = 0, + $thumbs = self._getThumbs(':not(.file-preview-success)'), + keys = $h.isEmpty(data) || $h.isEmpty(data.errorkeys) ? [] : data.errorkeys; + + if ($h.isEmpty(data) || $h.isEmpty(data.error)) { + self._raise('filebatchuploadsuccess', [outData]); + setAllUploaded(); + if (self.showPreview) { + $thumbs.each(function () { + var $thumb = $(this); + self._setThumbStatus($thumb, 'Success'); + $thumb.removeClass('file-uploading'); + $thumb.find('.kv-file-upload').hide().removeAttr('disabled'); + }); + self._initUploadSuccess(data); + } else { + self.reset(); + } + self._setProgress(101); + } else { + if (self.showPreview) { + $thumbs.each(function () { + var $thumb = $(this), i = $thumb.attr('data-fileindex'); + $thumb.removeClass('file-uploading'); + $thumb.find('.kv-file-upload').removeAttr('disabled'); + $thumb.find('.kv-file-remove').removeAttr('disabled'); + if (keys.length === 0 || $.inArray(key, keys) !== -1) { + self._setPreviewError($thumb, i, self.filestack[i], self.retryErrorUploads); + if (!self.retryErrorUploads) { + $thumb.find('.kv-file-upload').hide(); + self.updateStack(i, undefined); + } + } else { + $thumb.find('.kv-file-upload').hide(); + self._setThumbStatus($thumb, 'Success'); + self.updateStack(i, undefined); + } + if (!$thumb.hasClass('file-preview-error') || self.retryErrorUploads) { + key++; + } + }); + self._initUploadSuccess(data); + } + self._showUploadError(data.error, outData, 'filebatchuploaderror'); + self._setProgress(101, self.$progress, self.msgUploadError); + } + }; + fnComplete = function () { + self.unlock(); + self._initSuccessThumbs(); + self._clearFileInput(); + self._raise('filebatchuploadcomplete', [self.filestack, self._getExtraData()]); + }; + fnError = function (jqXHR, textStatus, errorThrown) { + var outData = self._getOutData(jqXHR), op = self.ajaxOperations.uploadBatch, + errMsg = self._parseError(op, jqXHR, errorThrown); + self._showUploadError(errMsg, outData, 'filebatchuploaderror'); + self.uploadFileCount = total - 1; + if (!self.showPreview) { + return; + } + self._getThumbs().each(function () { + var $thumb = $(this), key = $thumb.attr('data-fileindex'); + $thumb.removeClass('file-uploading'); + if (self.filestack[key] !== undefined) { + self._setPreviewError($thumb); + } + }); + self._getThumbs().removeClass('file-uploading'); + self._getThumbs(' .kv-file-upload').removeAttr('disabled'); + self._getThumbs(' .kv-file-delete').removeAttr('disabled'); + self._setProgress(101, self.$progress, self.msgAjaxProgressError.replace('{operation}', op)); + }; + $.each(files, function (key, data) { + if (!$h.isEmpty(files[key])) { + self.formdata.append(self.uploadFileAttr, data, self.filenames[key]); + } + }); + self._ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError); + }, + _uploadExtraOnly: function () { + var self = this, params = {}, fnBefore, fnSuccess, fnComplete, fnError; + self.formdata = new FormData(); + if (self._abort(params)) { + return; + } + fnBefore = function (jqXHR) { + self.lock(); + var outData = self._getOutData(jqXHR); + self._raise('filebatchpreupload', [outData]); + self._setProgress(50); + params.data = outData; + params.xhr = jqXHR; + if (self._abort(params)) { + jqXHR.abort(); + self._setProgressCancelled(); + } + }; + fnSuccess = function (data, textStatus, jqXHR) { + var outData = self._getOutData(jqXHR, data); + if ($h.isEmpty(data) || $h.isEmpty(data.error)) { + self._raise('filebatchuploadsuccess', [outData]); + self._clearFileInput(); + self._initUploadSuccess(data); + self._setProgress(101); + } else { + self._showUploadError(data.error, outData, 'filebatchuploaderror'); + } + }; + fnComplete = function () { + self.unlock(); + self._clearFileInput(); + self._raise('filebatchuploadcomplete', [self.filestack, self._getExtraData()]); + }; + fnError = function (jqXHR, textStatus, errorThrown) { + var outData = self._getOutData(jqXHR), op = self.ajaxOperations.uploadExtra, + errMsg = self._parseError(op, jqXHR, errorThrown); + params.data = outData; + self._showUploadError(errMsg, outData, 'filebatchuploaderror'); + self._setProgress(101, self.$progress, self.msgAjaxProgressError.replace('{operation}', op)); + }; + self._ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError); + }, + _deleteFileIndex: function ($frame) { + var self = this, ind = $frame.attr('data-fileindex'), rev = self.reversePreviewOrder; + if (ind.substring(0, 5) === 'init_') { + ind = parseInt(ind.replace('init_', '')); + self.initialPreview = $h.spliceArray(self.initialPreview, ind, rev); + self.initialPreviewConfig = $h.spliceArray(self.initialPreviewConfig, ind, rev); + self.initialPreviewThumbTags = $h.spliceArray(self.initialPreviewThumbTags, ind, rev); + self.getFrames().each(function () { + var $nFrame = $(this), nInd = $nFrame.attr('data-fileindex'); + if (nInd.substring(0, 5) === 'init_') { + nInd = parseInt(nInd.replace('init_', '')); + if (nInd > ind) { + nInd--; + $nFrame.attr('data-fileindex', 'init_' + nInd); + } + } + }); + if (self.uploadAsync) { + self.cacheInitialPreview = self.getPreview(); + } + } + }, + _initFileActions: function () { + var self = this, $preview = self.$preview; + if (!self.showPreview) { + return; + } + self._initZoomButton(); + self.getFrames(' .kv-file-remove').each(function () { + var $el = $(this), $frame = $el.closest($h.FRAMES), hasError, id = $frame.attr('id'), + ind = $frame.attr('data-fileindex'), n, cap, status; + self._handler($el, 'click', function () { + status = self._raise('filepreremove', [id, ind]); + if (status === false || !self._validateMinCount()) { + return false; + } + hasError = $frame.hasClass('file-preview-error'); + $h.cleanMemory($frame); + $frame.fadeOut('slow', function () { + $h.cleanZoomCache($preview.find('#zoom-' + id)); + self.updateStack(ind, undefined); + self._clearObjects($frame); + $frame.remove(); + if (id && hasError) { + self.$errorContainer.find('li[data-file-id="' + id + '"]').fadeOut('fast', function () { + $(this).remove(); + if (!self._errorsExist()) { + self._resetErrors(); + } + }); + } + self._clearFileInput(); + var filestack = self.getFileStack(true), chk = self.previewCache.count(), + len = filestack.length, hasThumb = self.showPreview && self.getFrames().length; + if (len === 0 && chk === 0 && !hasThumb) { + self.reset(); + } else { + n = chk + len; + cap = n > 1 ? self._getMsgSelected(n) : (filestack[0] ? self._getFileNames()[0] : ''); + self._setCaption(cap); + } + self._raise('fileremoved', [id, ind]); + }); + }); + }); + self.getFrames(' .kv-file-upload').each(function () { + var $el = $(this); + self._handler($el, 'click', function () { + var $frame = $el.closest($h.FRAMES), ind = $frame.attr('data-fileindex'); + self.$progress.hide(); + if ($frame.hasClass('file-preview-error') && !self.retryErrorUploads) { + return; + } + self._uploadSingle(ind, false); + }); + }); + }, + _initPreviewActions: function () { + var self = this, $preview = self.$preview, deleteExtraData = self.deleteExtraData || {}, + btnRemove = $h.FRAMES + ' .kv-file-remove', settings = self.fileActionSettings, + origClass = settings.removeClass, errClass = settings.removeErrorClass, + resetProgress = function () { + var hasFiles = self.isAjaxUpload ? self.previewCache.count() : self._inputFileCount(); + if (!$preview.find($h.FRAMES).length && !hasFiles) { + self._setCaption(''); + self.reset(); + self.initialCaption = ''; + } + }; + self._initZoomButton(); + $preview.find(btnRemove).each(function () { + var $el = $(this), vUrl = $el.data('url') || self.deleteUrl, vKey = $el.data('key'), + fnBefore, fnSuccess, fnError; + if ($h.isEmpty(vUrl) || vKey === undefined) { + return; + } + var $frame = $el.closest($h.FRAMES), cache = self.previewCache.data, + settings, params, index = $frame.attr('data-fileindex'), config, extraData; + index = parseInt(index.replace('init_', '')); + config = $h.isEmpty(cache.config) && $h.isEmpty(cache.config[index]) ? null : cache.config[index]; + extraData = $h.isEmpty(config) || $h.isEmpty(config.extra) ? deleteExtraData : config.extra; + if (typeof extraData === "function") { + extraData = extraData(); + } + params = {id: $el.attr('id'), key: vKey, extra: extraData}; + fnBefore = function (jqXHR) { + self.ajaxAborted = false; + self._raise('filepredelete', [vKey, jqXHR, extraData]); + if (self._abort()) { + jqXHR.abort(); + } else { + $el.removeClass(errClass); + $h.addCss($frame, 'file-uploading'); + $h.addCss($el, 'disabled ' + origClass); + } + }; + fnSuccess = function (data, textStatus, jqXHR) { + var n, cap; + if (!$h.isEmpty(data) && !$h.isEmpty(data.error)) { + params.jqXHR = jqXHR; + params.response = data; + self._showError(data.error, params, 'filedeleteerror'); + $frame.removeClass('file-uploading'); + $el.removeClass('disabled ' + origClass).addClass(errClass); + resetProgress(); + return; + } + $frame.removeClass('file-uploading').addClass('file-deleted'); + $frame.fadeOut('slow', function () { + index = parseInt(($frame.attr('data-fileindex')).replace('init_', '')); + self.previewCache.unset(index); + self._deleteFileIndex($frame); + n = self.previewCache.count(); + cap = n > 0 ? self._getMsgSelected(n) : ''; + self._setCaption(cap); + self._raise('filedeleted', [vKey, jqXHR, extraData]); + $h.cleanZoomCache($preview.find('#zoom-' + $frame.attr('id'))); + self._clearObjects($frame); + $frame.remove(); + resetProgress(); + }); + }; + fnError = function (jqXHR, textStatus, errorThrown) { + var op = self.ajaxOperations.deleteThumb, errMsg = self._parseError(op, jqXHR, errorThrown); + params.jqXHR = jqXHR; + params.response = {}; + self._showError(errMsg, params, 'filedeleteerror'); + $frame.removeClass('file-uploading'); + $el.removeClass('disabled ' + origClass).addClass(errClass); + resetProgress(); + }; + self._initAjaxSettings(); + self._mergeAjaxCallback('beforeSend', fnBefore, 'delete'); + self._mergeAjaxCallback('success', fnSuccess, 'delete'); + self._mergeAjaxCallback('error', fnError, 'delete'); + settings = $.extend(true, {}, { + url: vUrl, + type: 'POST', + dataType: 'json', + data: $.extend(true, {}, {key: vKey}, extraData) + }, self._ajaxDeleteSettings); + self._handler($el, 'click', function () { + if (!self._validateMinCount()) { + return false; + } + self.ajaxAborted = false; + self._raise('filebeforedelete', [vKey, extraData]); + //noinspection JSUnresolvedVariable,JSHint + if (self.ajaxAborted instanceof Promise) { + self.ajaxAborted.then(function (result) { + if (!result) { + $.ajax(settings); + } + }); + } else { + if (!self.ajaxAborted) { + $.ajax(settings); + } + } + }); + }); + }, + _hideFileIcon: function () { + var self = this; + if (self.overwriteInitial) { + self.$captionContainer.removeClass('icon-visible'); + } + }, + _showFileIcon: function () { + var self = this; + $h.addCss(self.$captionContainer, 'icon-visible'); + }, + _getSize: function (bytes) { + var self = this, size = parseFloat(bytes), i, func = self.fileSizeGetter, sizes, out; + if (!$.isNumeric(bytes) || !$.isNumeric(size)) { + return ''; + } + if (typeof func === 'function') { + out = func(size); + } else { + if (size === 0) { + out = '0.00 B'; + } else { + i = Math.floor(Math.log(size) / Math.log(1024)); + sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + out = (size / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + sizes[i]; + } + } + return self._getLayoutTemplate('size').replace('{sizeText}', out); + }, + _generatePreviewTemplate: function (cat, data, fname, ftype, previewId, isError, size, frameClass, foot, ind, templ) { + var self = this, caption = self.slug(fname), prevContent, zoomContent = '', styleAttribs = '', + screenW = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth, + config = screenW < 400 ? (self.previewSettingsSmall[cat] || self.defaults.previewSettingsSmall[cat]) : + (self.previewSettings[cat] || self.defaults.previewSettings[cat]), + footer = foot || self._renderFileFooter(caption, size, 'auto', isError), + hasIconSetting = self._getPreviewIcon(fname), typeCss = 'type-default', + forcePrevIcon = hasIconSetting && self.preferIconicPreview, + forceZoomIcon = hasIconSetting && self.preferIconicZoomPreview, getContent; + if (config) { + $.each(config, function (key, val) { + styleAttribs += key + ':' + val + ';'; + }); + } + getContent = function (c, d, zoom, frameCss) { + var id = zoom ? 'zoom-' + previewId : previewId, tmplt = self._getPreviewTemplate(c), + css = (frameClass || '') + ' ' + frameCss; + if (self.frameClass) { + css = self.frameClass + ' ' + css; + } + if (zoom) { + css = css.replace(' ' + $h.SORT_CSS, ''); + } + tmplt = self._parseFilePreviewIcon(tmplt, fname); + if (c === 'text') { + d = $h.htmlEncode(d); + } + if (cat === 'object' && !ftype) { + $.each(self.defaults.fileTypeSettings, function (key, func) { + if (key === 'object' || key === 'other') { + return; + } + if (func(fname, ftype)) { + typeCss = 'type-' + key; + } + }); + } + return tmplt.setTokens({ + 'previewId': id, + 'caption': caption, + 'frameClass': css, + 'type': ftype, + 'fileindex': ind, + 'typeCss': typeCss, + 'footer': footer, + 'data': d, + 'template': templ || cat, + 'style': styleAttribs ? 'style="' + styleAttribs + '"' : '' + }); + }; + ind = ind || previewId.slice(previewId.lastIndexOf('-') + 1); + if (self.fileActionSettings.showZoom) { + zoomContent = getContent((forceZoomIcon ? 'other' : cat), data, true, 'kv-zoom-thumb'); + } + zoomContent = '\n' + self._getLayoutTemplate('zoomCache').replace('{zoomContent}', zoomContent); + prevContent = getContent((forcePrevIcon ? 'other' : cat), data, false, 'kv-preview-thumb'); + return prevContent + zoomContent; + }, + _addToPreview: function ($preview, content) { + var self = this; + return self.reversePreviewOrder ? $preview.prepend(content) : $preview.append(content); + }, + _previewDefault: function (file, previewId, isDisabled) { + var self = this, $preview = self.$preview; + if (!self.showPreview) { + return; + } + var fname = file ? file.name : '', ftype = file ? file.type : '', content, size = file.size || 0, + caption = self.slug(fname), isError = isDisabled === true && !self.isAjaxUpload, + data = $h.objUrl.createObjectURL(file); + self._clearDefaultPreview(); + content = self._generatePreviewTemplate('other', data, fname, ftype, previewId, isError, size); + self._addToPreview($preview, content); + self._setThumbAttr(previewId, caption, size); + if (isDisabled === true && self.isAjaxUpload) { + self._setThumbStatus($('#' + previewId), 'Error'); + } + }, + _previewFile: function (i, file, theFile, previewId, data, fileInfo) { + if (!this.showPreview) { + return; + } + var self = this, fname = file ? file.name : '', ftype = fileInfo.type, caption = fileInfo.name, + cat = self._parseFileType(ftype, fname), types = self.allowedPreviewTypes, content, + mimes = self.allowedPreviewMimeTypes, $preview = self.$preview, fsize = file.size || 0, + chkTypes = types && types.indexOf(cat) >= 0, chkMimes = mimes && mimes.indexOf(ftype) !== -1, + iData = (cat === 'text' || cat === 'html' || cat === 'image') ? theFile.target.result : data; + /** @namespace window.DOMPurify */ + if (cat === 'html' && self.purifyHtml && window.DOMPurify) { + iData = window.DOMPurify.sanitize(iData); + } + if (chkTypes || chkMimes) { + content = self._generatePreviewTemplate(cat, iData, fname, ftype, previewId, false, fsize); + self._clearDefaultPreview(); + self._addToPreview($preview, content); + var $img = $preview.find('#' + previewId + ' img'); + if ($img.length && self.autoOrientImage) { + $h.validateOrientation(file, function (value) { + if (!value) { + self._validateImage(previewId, caption, ftype, fsize, iData); + return; + } + var $zoomImg = $preview.find('#zoom-' + previewId + ' img'), css = 'rotate-' + value; + if (value > 4) { + css += ($img.width() > $img.height() ? ' is-portrait-gt4' : ' is-landscape-gt4'); + } + $h.addCss($img, css); + $h.addCss($zoomImg, css); + self._raise('fileimageoriented', {'$img': $img, 'file': file}); + self._validateImage(previewId, caption, ftype, fsize, iData); + $h.adjustOrientedImage($img); + }); + } else { + self._validateImage(previewId, caption, ftype, fsize, iData); + } + } else { + self._previewDefault(file, previewId); + } + self._setThumbAttr(previewId, caption, fsize); + self._initSortable(); + }, + _setThumbAttr: function (id, caption, size) { + var self = this, $frame = $('#' + id); + if ($frame.length) { + size = size && size > 0 ? self._getSize(size) : ''; + $frame.data({'caption': caption, 'size': size}); + } + }, + _setInitThumbAttr: function () { + var self = this, data = self.previewCache.data, len = self.previewCache.count(), config, + caption, size, previewId; + if (len === 0) { + return; + } + for (var i = 0; i < len; i++) { + config = data.config[i]; + previewId = self.previewInitId + '-' + 'init_' + i; + caption = $h.ifSet('caption', config, $h.ifSet('filename', config)); + size = $h.ifSet('size', config); + self._setThumbAttr(previewId, caption, size); + } + }, + _slugDefault: function (text) { + return $h.isEmpty(text) ? '' : String(text).replace(/[\[\]\/\{}:;#%=\(\)\*\+\?\\\^\$\|<>&"']/g, '_'); + }, + _updateFileDetails: function (numFiles) { + var self = this, $el = self.$element, fileStack = self.getFileStack(), + name = ($h.isIE(9) && $h.findFileName($el.val())) || + ($el[0].files[0] && $el[0].files[0].name) || (fileStack.length && fileStack[0].name) || '', + label = self.slug(name), n = self.isAjaxUpload ? fileStack.length : numFiles, + nFiles = self.previewCache.count() + n, log = n === 1 ? label : self._getMsgSelected(nFiles); + if (self.isError) { + self.$previewContainer.removeClass('file-thumb-loading'); + self.$previewStatus.html(''); + self.$captionContainer.removeClass('icon-visible'); + } else { + self._showFileIcon(); + } + self._setCaption(log, self.isError); + self.$container.removeClass('file-input-new file-input-ajax-new'); + if (arguments.length === 1) { + self._raise('fileselect', [numFiles, label]); + } + if (self.previewCache.count()) { + self._initPreviewActions(); + } + }, + _setThumbStatus: function ($thumb, status) { + var self = this; + if (!self.showPreview) { + return; + } + var icon = 'indicator' + status, msg = icon + 'Title', + css = 'file-preview-' + status.toLowerCase(), + $indicator = $thumb.find('.file-upload-indicator'), + config = self.fileActionSettings; + $thumb.removeClass('file-preview-success file-preview-error file-preview-loading'); + if (status === 'Success') { + $thumb.find('.file-drag-handle').remove(); + } + $indicator.html(config[icon]); + $indicator.attr('title', config[msg]); + $thumb.addClass(css); + if (status === 'Error' && !self.retryErrorUploads) { + $thumb.find('.kv-file-upload').attr('disabled', true); + } + }, + _setProgressCancelled: function () { + var self = this; + self._setProgress(101, self.$progress, self.msgCancelled); + }, + _setProgress: function (p, $el, error) { + var self = this, pct = Math.min(p, 100), out, pctLimit = self.progressUploadThreshold, + t = p <= 100 ? self.progressTemplate : self.progressCompleteTemplate, + template = pct < 100 ? self.progressTemplate : (error ? self.progressErrorTemplate : t); + $el = $el || self.$progress; + if (!$h.isEmpty(template)) { + if (pctLimit && pct > pctLimit && p <= 100) { + out = template.setTokens({'percent': pctLimit, 'status': self.msgUploadThreshold}); + } else { + out = template.setTokens({'percent': pct, 'status': (p > 100 ? self.msgUploadEnd : pct + '%')}); + } + $el.html(out); + if (error) { + $el.find('[role="progressbar"]').html(error); + } + } + }, + _setFileDropZoneTitle: function () { + var self = this, $zone = self.$container.find('.file-drop-zone'), title = self.dropZoneTitle, strFiles; + if (self.isClickable) { + strFiles = $h.isEmpty(self.$element.attr('multiple')) ? self.fileSingle : self.filePlural; + title += self.dropZoneClickTitle.replace('{files}', strFiles); + } + $zone.find('.' + self.dropZoneTitleClass).remove(); + if (!self.showPreview || $zone.length === 0 || self.getFileStack().length > 0 || !self.dropZoneEnabled || + (!self.isAjaxUpload && self.$element.files)) { + return; + } + if ($zone.find($h.FRAMES).length === 0 && $h.isEmpty(self.defaultPreviewContent)) { + $zone.prepend('' + title + ''); + } + self.$container.removeClass('file-input-new'); + $h.addCss(self.$container, 'file-input-ajax-new'); + }, + _setAsyncUploadStatus: function (previewId, pct, total) { + var self = this, sum = 0; + self._setProgress(pct, $('#' + previewId).find('.file-thumb-progress')); + self.uploadStatus[previewId] = pct; + $.each(self.uploadStatus, function (key, value) { + sum += value; + }); + self._setProgress(Math.floor(sum / total)); + }, + _validateMinCount: function () { + var self = this, len = self.isAjaxUpload ? self.getFileStack().length : self._inputFileCount(); + if (self.validateInitialCount && self.minFileCount > 0 && self._getFileCount(len - 1) < self.minFileCount) { + self._noFilesError({}); + return false; + } + return true; + }, + _getFileCount: function (fileCount) { + var self = this, addCount = 0; + if (self.validateInitialCount && !self.overwriteInitial) { + addCount = self.previewCache.count(); + fileCount += addCount; + } + return fileCount; + }, + _getFileId: function (file) { + var self = this, custom = self.generateFileId, relativePath; + if (typeof custom === 'function') { + return custom(file, event); + } + if (!file) { + return null; + } + /** @namespace file.webkitRelativePath */ + relativePath = String(file.webkitRelativePath || file.fileName || file.name || null); + if (!relativePath) { + return null; + } + return (file.size + '-' + relativePath.replace(/[^0-9a-zA-Z_-]/img, '')); + }, + _getFileName: function (file) { + return file && file.name ? this.slug(file.name) : undefined; + }, + _getFileIds: function (skipNull) { + var self = this; + return self.fileids.filter(function (n) { + return (skipNull ? n !== undefined : n !== undefined && n !== null); + }); + }, + _getFileNames: function (skipNull) { + var self = this; + return self.filenames.filter(function (n) { + return (skipNull ? n !== undefined : n !== undefined && n !== null); + }); + }, + _setPreviewError: function ($thumb, i, val, repeat) { + var self = this; + if (i !== undefined) { + self.updateStack(i, val); + } + if (!self.showPreview) { + return; + } + if (self.removeFromPreviewOnError && !repeat) { + $thumb.remove(); + return; + } else { + self._setThumbStatus($thumb, 'Error'); + } + self._refreshUploadButton($thumb, repeat); + }, + _refreshUploadButton: function ($thumb, repeat) { + var self = this, $btn = $thumb.find('.kv-file-upload'), cfg = self.fileActionSettings, + icon = cfg.uploadIcon, title = cfg.uploadTitle; + if (!$btn.length) { + return; + } + if (repeat) { + icon = cfg.uploadRetryIcon; + title = cfg.uploadRetryTitle; + } + $btn.attr('title', title).html(icon); + }, + _checkDimensions: function (i, chk, $img, $thumb, fname, type, params) { + var self = this, msg, dim, tag = chk === 'Small' ? 'min' : 'max', limit = self[tag + 'Image' + type], + $imgEl, isValid; + if ($h.isEmpty(limit) || !$img.length) { + return; + } + $imgEl = $img[0]; + dim = (type === 'Width') ? $imgEl.naturalWidth || $imgEl.width : $imgEl.naturalHeight || $imgEl.height; + isValid = chk === 'Small' ? dim >= limit : dim <= limit; + if (isValid) { + return; + } + msg = self['msgImage' + type + chk].setTokens({'name': fname, 'size': limit}); + self._showUploadError(msg, params); + self._setPreviewError($thumb, i, null); + }, + _validateImage: function (previewId, fname, ftype, fsize, iData) { + var self = this, $preview = self.$preview, params, w1, w2, $thumb = $preview.find("#" + previewId), + i = $thumb.attr('data-fileindex'), $img = $thumb.find('img'), exifObject; + fname = fname || 'Untitled'; + $img.one('load', function () { + w1 = $thumb.width(); + w2 = $preview.width(); + if (w1 > w2) { + $img.css('width', '100%'); + } + params = {ind: i, id: previewId}; + self._checkDimensions(i, 'Small', $img, $thumb, fname, 'Width', params); + self._checkDimensions(i, 'Small', $img, $thumb, fname, 'Height', params); + if (!self.resizeImage) { + self._checkDimensions(i, 'Large', $img, $thumb, fname, 'Width', params); + self._checkDimensions(i, 'Large', $img, $thumb, fname, 'Height', params); + } + self._raise('fileimageloaded', [previewId]); + try { + exifObject = window.piexif ? window.piexif.load(iData) : null; + } catch (err) { + exifObject = null; + } + self.loadedImages.push({ + ind: i, + img: $img, + thumb: $thumb, + pid: previewId, + typ: ftype, + siz: fsize, + validated: false, + imgData: iData, + exifObj: exifObject + }); + $thumb.data('exif', exifObject); + self._validateAllImages(); + }).one('error', function () { + self._raise('fileimageloaderror', [previewId]); + }).each(function () { + if (this.complete) { + $(this).trigger('load'); + } else { + if (this.error) { + $(this).trigger('error'); + } + } + }); + }, + _validateAllImages: function () { + var self = this, i, counter = {val: 0}, numImgs = self.loadedImages.length, config, + fsize, minSize = self.resizeIfSizeMoreThan; + if (numImgs !== self.totalImagesCount) { + return; + } + self._raise('fileimagesloaded'); + if (!self.resizeImage) { + return; + } + for (i = 0; i < self.loadedImages.length; i++) { + config = self.loadedImages[i]; + if (config.validated) { + continue; + } + fsize = config.siz; + if (fsize && fsize > minSize * 1000) { + self._getResizedImage(config, counter, numImgs); + } + self.loadedImages[i].validated = true; + } + }, + _getResizedImage: function (config, counter, numImgs) { + var self = this, img = $(config.img)[0], width = img.naturalWidth, height = img.naturalHeight, blob, + ratio = 1, maxWidth = self.maxImageWidth || width, maxHeight = self.maxImageHeight || height, + isValidImage = !!(width && height), chkWidth, chkHeight, canvas = self.imageCanvas, dataURI, + context = self.imageCanvasContext, type = config.typ, pid = config.pid, ind = config.ind, + $thumb = config.thumb, throwError, msg, exifObj = config.exifObj, exifStr; + throwError = function (msg, params, ev) { + if (self.isAjaxUpload) { + self._showUploadError(msg, params, ev); + } else { + self._showError(msg, params, ev); + } + self._setPreviewError($thumb, ind); + }; + if (!self.filestack[ind] || !isValidImage || (width <= maxWidth && height <= maxHeight)) { + if (isValidImage && self.filestack[ind]) { + self._raise('fileimageresized', [pid, ind]); + } + counter.val++; + if (counter.val === numImgs) { + self._raise('fileimagesresized'); + } + if (!isValidImage) { + throwError(self.msgImageResizeError, {id: pid, 'index': ind}, 'fileimageresizeerror'); + return; + } + } + type = type || self.resizeDefaultImageType; + chkWidth = width > maxWidth; + chkHeight = height > maxHeight; + if (self.resizePreference === 'width') { + ratio = chkWidth ? maxWidth / width : (chkHeight ? maxHeight / height : 1); + } else { + ratio = chkHeight ? maxHeight / height : (chkWidth ? maxWidth / width : 1); + } + self._resetCanvas(); + width *= ratio; + height *= ratio; + canvas.width = width; + canvas.height = height; + try { + context.drawImage(img, 0, 0, width, height); + dataURI = canvas.toDataURL(type, self.resizeQuality); + if (exifObj) { + exifStr = window.piexif.dump(exifObj); + dataURI = window.piexif.insert(exifStr, dataURI); + } + blob = $h.dataURI2Blob(dataURI); + self.filestack[ind] = blob; + self._raise('fileimageresized', [pid, ind]); + counter.val++; + if (counter.val === numImgs) { + self._raise('fileimagesresized', [undefined, undefined]); + } + if (!(blob instanceof Blob)) { + throwError(self.msgImageResizeError, {id: pid, 'index': ind}, 'fileimageresizeerror'); + } + } + catch (err) { + counter.val++; + if (counter.val === numImgs) { + self._raise('fileimagesresized', [undefined, undefined]); + } + msg = self.msgImageResizeException.replace('{errors}', err.message); + throwError(msg, {id: pid, 'index': ind}, 'fileimageresizeexception'); + } + }, + _initBrowse: function ($container) { + var self = this, $el = self.$element; + if (self.showBrowse) { + self.$btnFile = $container.find('.btn-file').append($el); + } else { + $el.appendTo($container).attr('tabindex', -1); + $h.addCss($el, 'file-no-browse'); + } + }, + _initClickable: function () { + var self = this, $zone; + if (!self.isClickable) { + return; + } + $zone = self.isAjaxUpload ? self.$dropZone : self.$preview.find('.file-default-preview'); + $h.addCss($zone, 'clickable'); + $zone.attr('tabindex', -1); + self._handler($zone, 'click', function (e) { + var $tar = $(e.target), $el = self.$element; + if (!$(self.elErrorContainer + ':visible').length && + (!$tar.parents('.file-preview-thumbnails').length || $tar.parents('.file-default-preview').length)) { + self.$element.data('zoneClicked', true).trigger('click'); + $zone.blur(); + } + }); + }, + _initCaption: function () { + var self = this, cap = self.initialCaption || ''; + if (self.overwriteInitial || $h.isEmpty(cap)) { + self.$caption.val(''); + return false; + } + self._setCaption(cap); + return true; + }, + _setCaption: function (content, isError) { + var self = this, title, out, icon, n, cap, stack = self.getFileStack(); + if (!self.$caption.length) { + return; + } + self.$captionContainer.removeClass('icon-visible'); + if (isError) { + title = $('' + self.msgValidationError + '').text(); + n = stack.length; + if (n) { + cap = n === 1 && stack[0] ? self._getFileNames()[0] : self._getMsgSelected(n); + } else { + cap = self._getMsgSelected(self.msgNo); + } + out = $h.isEmpty(content) ? cap : content; + icon = '' + self.msgValidationErrorIcon + ''; + } else { + if ($h.isEmpty(content)) { + return; + } + title = $('' + content + '').text(); + out = title; + icon = self._getLayoutTemplate('fileIcon'); + } + self.$captionContainer.addClass('icon-visible'); + self.$caption.attr('title', title).val(out); + self.$captionIcon.html(icon); + }, + _createContainer: function () { + var self = this, attribs = {"class": 'file-input file-input-new' + (self.rtl ? ' kv-rtl' : '')}, + $container = $(document.createElement("div")).attr(attribs).html(self._renderMain()); + $container.insertBefore(self.$element); + self._initBrowse($container); + if (self.theme) { + $container.addClass('theme-' + self.theme); + } + return $container; + }, + _refreshContainer: function () { + var self = this, $container = self.$container, $el = self.$element; + $el.insertAfter($container); + $container.html(self._renderMain()); + self._initBrowse($container); + self._validateDisabled(); + }, + _validateDisabled: function () { + var self = this; + self.$caption.attr({readonly: self.isDisabled}); + }, + _renderMain: function () { + var self = this, + dropCss = self.dropZoneEnabled ? ' file-drop-zone' : 'file-drop-disabled', + close = !self.showClose ? '' : self._getLayoutTemplate('close'), + preview = !self.showPreview ? '' : self._getLayoutTemplate('preview') + .setTokens({'class': self.previewClass, 'dropClass': dropCss}), + css = self.isDisabled ? self.captionClass + ' file-caption-disabled' : self.captionClass, + caption = self.captionTemplate.setTokens({'class': css + ' kv-fileinput-caption'}); + return self.mainTemplate.setTokens({ + 'class': self.mainClass + (!self.showBrowse && self.showCaption ? ' no-browse' : ''), + 'preview': preview, + 'close': close, + 'caption': caption, + 'upload': self._renderButton('upload'), + 'remove': self._renderButton('remove'), + 'cancel': self._renderButton('cancel'), + 'browse': self._renderButton('browse') + }); + + }, + _renderButton: function (type) { + var self = this, tmplt = self._getLayoutTemplate('btnDefault'), css = self[type + 'Class'], + title = self[type + 'Title'], icon = self[type + 'Icon'], label = self[type + 'Label'], + status = self.isDisabled ? ' disabled' : '', btnType = 'button'; + switch (type) { + case 'remove': + if (!self.showRemove) { + return ''; + } + break; + case 'cancel': + if (!self.showCancel) { + return ''; + } + css += ' kv-hidden'; + break; + case 'upload': + if (!self.showUpload) { + return ''; + } + if (self.isAjaxUpload && !self.isDisabled) { + tmplt = self._getLayoutTemplate('btnLink').replace('{href}', self.uploadUrl); + } else { + btnType = 'submit'; + } + break; + case 'browse': + if (!self.showBrowse) { + return ''; + } + tmplt = self._getLayoutTemplate('btnBrowse'); + break; + default: + return ''; + } + + css += type === 'browse' ? ' btn-file' : ' fileinput-' + type + ' fileinput-' + type + '-button'; + if (!$h.isEmpty(label)) { + label = ' ' + label + ''; + } + return tmplt.setTokens({ + 'type': btnType, 'css': css, 'title': title, 'status': status, 'icon': icon, 'label': label + }); + }, + _renderThumbProgress: function () { + var self = this; + return '' + + self.progressTemplate.setTokens({'percent': '0', 'status': self.msgUploadBegin}) + + ''; + }, + _renderFileFooter: function (caption, size, width, isError) { + var self = this, config = self.fileActionSettings, rem = config.showRemove, drg = config.showDrag, + upl = config.showUpload, zoom = config.showZoom, out, + template = self._getLayoutTemplate('footer'), tInd = self._getLayoutTemplate('indicator'), + ind = isError ? config.indicatorError : config.indicatorNew, + title = isError ? config.indicatorErrorTitle : config.indicatorNewTitle, + indicator = tInd.setTokens({'indicator': ind, 'indicatorTitle': title}); + size = self._getSize(size); + if (self.isAjaxUpload) { + out = template.setTokens({ + 'actions': self._renderFileActions(upl, false, rem, zoom, drg, false, false, false), + 'caption': caption, + 'size': size, + 'width': width, + 'progress': self._renderThumbProgress(), + 'indicator': indicator + }); + } else { + out = template.setTokens({ + 'actions': self._renderFileActions(false, false, false, zoom, drg, false, false, false), + 'caption': caption, + 'size': size, + 'width': width, + 'progress': '', + 'indicator': indicator + }); + } + out = $h.replaceTags(out, self.previewThumbTags); + return out; + }, + _renderFileActions: function (showUpl, showDwn, showDel, showZoom, showDrag, disabled, url, key, isInit, dUrl, dFile) { + if (!showUpl && !showDwn && !showDel && !showZoom && !showDrag) { + return ''; + } + var self = this, vUrl = url === false ? '' : ' data-url="' + url + '"', + vKey = key === false ? '' : ' data-key="' + key + '"', btnDelete = '', btnUpload = '', btnDownload = '', + btnZoom = '', btnDrag = '', css, template = self._getLayoutTemplate('actions'), + config = self.fileActionSettings, + otherButtons = self.otherActionButtons.setTokens({'dataKey': vKey, 'key': key}), + removeClass = disabled ? config.removeClass + ' disabled' : config.removeClass; + if (showDel) { + btnDelete = self._getLayoutTemplate('actionDelete').setTokens({ + 'removeClass': removeClass, + 'removeIcon': config.removeIcon, + 'removeTitle': config.removeTitle, + 'dataUrl': vUrl, + 'dataKey': vKey, + 'key': key + }); + } + if (showUpl) { + btnUpload = self._getLayoutTemplate('actionUpload').setTokens({ + 'uploadClass': config.uploadClass, + 'uploadIcon': config.uploadIcon, + 'uploadTitle': config.uploadTitle + }); + } + if (showDwn) { + btnDownload = self._getLayoutTemplate('actionDownload').setTokens({ + 'downloadClass': config.downloadClass, + 'downloadIcon': config.downloadIcon, + 'downloadTitle': config.downloadTitle, + 'downloadUrl': dUrl || self.initialPreviewDownloadUrl + }); + btnDownload = btnDownload.setTokens({'filename': dFile, 'key': key}); + } + if (showZoom) { + btnZoom = self._getLayoutTemplate('actionZoom').setTokens({ + 'zoomClass': config.zoomClass, + 'zoomIcon': config.zoomIcon, + 'zoomTitle': config.zoomTitle + }); + } + if (showDrag && isInit) { + css = 'drag-handle-init ' + config.dragClass; + btnDrag = self._getLayoutTemplate('actionDrag').setTokens({ + 'dragClass': css, + 'dragTitle': config.dragTitle, + 'dragIcon': config.dragIcon + }); + } + return template.setTokens({ + 'delete': btnDelete, + 'upload': btnUpload, + 'download': btnDownload, + 'zoom': btnZoom, + 'drag': btnDrag, + 'other': otherButtons + }); + }, + _browse: function (e) { + var self = this; + self._raise('filebrowse'); + if (e && e.isDefaultPrevented()) { + return; + } + if (self.isError && !self.isAjaxUpload) { + self.clear(); + } + self.$captionContainer.focus(); + }, + _filterDuplicate: function (file, files, fileIds) { + var self = this, fileId = self._getFileId(file); + + if (fileId && fileIds && fileIds.indexOf(fileId) > -1) { + return; + } + if (!fileIds) { + fileIds = []; + } + files.push(file); + fileIds.push(fileId); + }, + _change: function (e) { + var self = this; + if (self.changeTriggered) { + return; + } + var $el = self.$element, isDragDrop = arguments.length > 1, isAjaxUpload = self.isAjaxUpload, + tfiles = [], files = isDragDrop ? arguments[1] : $el.get(0).files, total, + maxCount = !isAjaxUpload && $h.isEmpty($el.attr('multiple')) ? 1 : self.maxFileCount, + len, ctr = self.filestack.length, isSingleUpload = $h.isEmpty($el.attr('multiple')), + flagSingle = (isSingleUpload && ctr > 0), fileIds = self._getFileIds(), + throwError = function (mesg, file, previewId, index) { + var p1 = $.extend(true, {}, self._getOutData({}, {}, files), {id: previewId, index: index}), + p2 = {id: previewId, index: index, file: file, files: files}; + return isAjaxUpload ? self._showUploadError(mesg, p1) : self._showError(mesg, p2); + }, + maxCountCheck = function (n, m) { + var msg = self.msgFilesTooMany.replace('{m}', m).replace('{n}', n); + self.isError = throwError(msg, null, null, null); + self.$captionContainer.removeClass('icon-visible'); + self._setCaption('', true); + self.$container.removeClass('file-input-new file-input-ajax-new'); + }; + self.reader = null; + self._resetUpload(); + self._hideFileIcon(); + if (self.dropZoneEnabled) { + self.$container.find('.file-drop-zone .' + self.dropZoneTitleClass).remove(); + } + if (isAjaxUpload) { + $.each(files, function (vKey, vFile) { + self._filterDuplicate(vFile, tfiles, fileIds); + }); + } else { + if (e.target && e.target.files === undefined) { + files = e.target.value ? [{name: e.target.value.replace(/^.+\\/, '')}] : []; + } else { + files = e.target.files || {}; + } + tfiles = files; + } + if ($h.isEmpty(tfiles) || tfiles.length === 0) { + if (!isAjaxUpload) { + self.clear(); + } + self._raise('fileselectnone'); + return; + } + self._resetErrors(); + len = tfiles.length; + total = self._getFileCount(isAjaxUpload ? (self.getFileStack().length + len) : len); + if (maxCount > 0 && total > maxCount) { + if (!self.autoReplace || len > maxCount) { + maxCountCheck((self.autoReplace && len > maxCount ? len : total), maxCount); + return; + } + if (total > maxCount) { + self._resetPreviewThumbs(isAjaxUpload); + } + } else { + if (!isAjaxUpload || flagSingle) { + self._resetPreviewThumbs(false); + if (flagSingle) { + self.clearStack(); + } + } else { + if (isAjaxUpload && ctr === 0 && (!self.previewCache.count() || self.overwriteInitial)) { + self._resetPreviewThumbs(true); + } + } + } + if (self.isPreviewable) { + self.readFiles(tfiles); + } else { + self._updateFileDetails(1); + } + }, + _abort: function (params) { + var self = this, data; + if (self.ajaxAborted && typeof self.ajaxAborted === "object" && self.ajaxAborted.message !== undefined) { + data = $.extend(true, {}, self._getOutData(), params); + data.abortData = self.ajaxAborted.data || {}; + data.abortMessage = self.ajaxAborted.message; + self._setProgress(101, self.$progress, self.msgCancelled); + self._showUploadError(self.ajaxAborted.message, data, 'filecustomerror'); + self.cancel(); + return true; + } + return !!self.ajaxAborted; + }, + _resetFileStack: function () { + var self = this, i = 0, newstack = [], newnames = [], newids = []; + self._getThumbs().each(function () { + var $thumb = $(this), ind = $thumb.attr('data-fileindex'), file = self.filestack[ind], + pid = $thumb.attr('id'); + if (ind === '-1' || ind === -1) { + return; + } + if (file !== undefined) { + newstack[i] = file; + newnames[i] = self._getFileName(file); + newids[i] = self._getFileId(file); + $thumb.attr({'id': self.previewInitId + '-' + i, 'data-fileindex': i}); + i++; + } else { + $thumb.attr({'id': 'uploaded-' + $h.uniqId(), 'data-fileindex': '-1'}); + } + self.$preview.find('#zoom-' + pid).attr({ + 'id': 'zoom-' + $thumb.attr('id'), + 'data-fileindex': $thumb.attr('data-fileindex') + }); + }); + self.filestack = newstack; + self.filenames = newnames; + self.fileids = newids; + }, + _isFileSelectionValid: function (cnt) { + var self = this; + cnt = cnt || 0; + if (self.required && !self.getFilesCount()) { + self.$errorContainer.html(''); + self._showUploadError(self.msgFileRequired); + return false; + } + if (self.minFileCount > 0 && self._getFileCount(cnt) < self.minFileCount) { + self._noFilesError({}); + return false; + } + return true; + }, + clearStack: function () { + var self = this; + self.filestack = []; + self.filenames = []; + self.fileids = []; + return self.$element; + }, + updateStack: function (i, file) { + var self = this; + self.filestack[i] = file; + self.filenames[i] = self._getFileName(file); + self.fileids[i] = file && self._getFileId(file) || null; + return self.$element; + }, + addToStack: function (file) { + var self = this; + self.filestack.push(file); + self.filenames.push(self._getFileName(file)); + self.fileids.push(self._getFileId(file)); + return self.$element; + }, + getFileStack: function (skipNull) { + var self = this; + return self.filestack.filter(function (n) { + return (skipNull ? n !== undefined : n !== undefined && n !== null); + }); + }, + getFilesCount: function () { + var self = this, len = self.isAjaxUpload ? self.getFileStack().length : self._inputFileCount(); + return self._getFileCount(len); + }, + readFiles: function (files) { + this.reader = new FileReader(); + var self = this, $el = self.$element, $preview = self.$preview, reader = self.reader, + $container = self.$previewContainer, $status = self.$previewStatus, msgLoading = self.msgLoading, + msgProgress = self.msgProgress, previewInitId = self.previewInitId, numFiles = files.length, + settings = self.fileTypeSettings, ctr = self.filestack.length, readFile, + fileTypes = self.allowedFileTypes, typLen = fileTypes ? fileTypes.length : 0, + fileExt = self.allowedFileExtensions, strExt = $h.isEmpty(fileExt) ? '' : fileExt.join(', '), + maxPreviewSize = self.maxFilePreviewSize && parseFloat(self.maxFilePreviewSize), + canPreview = $preview.length && (!maxPreviewSize || isNaN(maxPreviewSize)), + throwError = function (msg, file, previewId, index) { + var p1 = $.extend(true, {}, self._getOutData({}, {}, files), {id: previewId, index: index}), + p2 = {id: previewId, index: index, file: file, files: files}, $thumb; + self._previewDefault(file, previewId, true); + if (self.isAjaxUpload) { + self.addToStack(undefined); + setTimeout(function () { + readFile(index + 1); + }, 100); + } else { + numFiles = 0; + } + self._initFileActions(); + $thumb = $('#' + previewId); + $thumb.find('.kv-file-upload').hide(); + if (self.removeFromPreviewOnError) { + $thumb.remove(); + } + self.isError = self.isAjaxUpload ? self._showUploadError(msg, p1) : self._showError(msg, p2); + self._updateFileDetails(numFiles); + }; + + self.loadedImages = []; + self.totalImagesCount = 0; + + $.each(files, function (key, file) { + var func = self.fileTypeSettings.image; + if (func && func(file.type)) { + self.totalImagesCount++; + } + }); + readFile = function (i) { + if ($h.isEmpty($el.attr('multiple'))) { + numFiles = 1; + } + if (i >= numFiles) { + if (self.isAjaxUpload && self.filestack.length > 0) { + self._raise('filebatchselected', [self.getFileStack()]); + } else { + self._raise('filebatchselected', [files]); + } + $container.removeClass('file-thumb-loading'); + $status.html(''); + return; + } + var node = ctr + i, previewId = previewInitId + "-" + node, file = files[i], fSizeKB, j, msg, + fnText = settings.text, fnImage = settings.image, fnHtml = settings.html, typ, chk, typ1, typ2, + caption = file && file.name ? self.slug(file.name) : '', fileSize = (file && file.size || 0) / 1000, + fileExtExpr = '', previewData = file ? $h.objUrl.createObjectURL(file) : null, fileCount = 0, strTypes = '', + func, knownTypes = 0, isText, isHtml, isImage, txtFlag, processFileLoaded = function () { + var msg = msgProgress.setTokens({ + 'index': i + 1, + 'files': numFiles, + 'percent': 50, + 'name': caption + }); + setTimeout(function () { + $status.html(msg); + self._updateFileDetails(numFiles); + readFile(i + 1); + }, 100); + self._raise('fileloaded', [file, previewId, i, reader]); + }; + if (!file) { + return; + } + if (typLen > 0) { + for (j = 0; j < typLen; j++) { + typ1 = fileTypes[j]; + typ2 = self.msgFileTypes[typ1] || typ1; + strTypes += j === 0 ? typ2 : ', ' + typ2; + } + } + if (caption === false) { + readFile(i + 1); + return; + } + if (caption.length === 0) { + msg = self.msgInvalidFileName.replace('{name}', $h.htmlEncode(file.name)); + throwError(msg, file, previewId, i); + return; + } + if (!$h.isEmpty(fileExt)) { + fileExtExpr = new RegExp('\\.(' + fileExt.join('|') + ')$', 'i'); + } + fSizeKB = fileSize.toFixed(2); + if (self.maxFileSize > 0 && fileSize > self.maxFileSize) { + msg = self.msgSizeTooLarge.setTokens({ + 'name': caption, + 'size': fSizeKB, + 'maxSize': self.maxFileSize + }); + throwError(msg, file, previewId, i); + return; + } + if (self.minFileSize !== null && fileSize <= $h.getNum(self.minFileSize)) { + msg = self.msgSizeTooSmall.setTokens({ + 'name': caption, + 'size': fSizeKB, + 'minSize': self.minFileSize + }); + throwError(msg, file, previewId, i); + return; + } + if (!$h.isEmpty(fileTypes) && $h.isArray(fileTypes)) { + for (j = 0; j < fileTypes.length; j += 1) { + typ = fileTypes[j]; + func = settings[typ]; + fileCount += !func || (typeof func !== 'function') ? 0 : (func(file.type, file.name) ? 1 : 0); + } + if (fileCount === 0) { + msg = self.msgInvalidFileType.setTokens({'name': caption, 'types': strTypes}); + throwError(msg, file, previewId, i); + return; + } + } + if (fileCount === 0 && !$h.isEmpty(fileExt) && $h.isArray(fileExt) && !$h.isEmpty(fileExtExpr)) { + chk = $h.compare(caption, fileExtExpr); + fileCount += $h.isEmpty(chk) ? 0 : chk.length; + if (fileCount === 0) { + msg = self.msgInvalidFileExtension.setTokens({'name': caption, 'extensions': strExt}); + throwError(msg, file, previewId, i); + return; + } + } + if (!self.showPreview) { + if (self.isAjaxUpload) { + self.addToStack(file); + } + setTimeout(function () { + readFile(i + 1); + self._updateFileDetails(numFiles); + }, 100); + self._raise('fileloaded', [file, previewId, i, reader]); + return; + } + if (!canPreview && fileSize > maxPreviewSize) { + self.addToStack(file); + $container.addClass('file-thumb-loading'); + self._previewDefault(file, previewId); + self._initFileActions(); + self._updateFileDetails(numFiles); + readFile(i + 1); + return; + } + if ($preview.length && FileReader !== undefined) { + isText = fnText(file.type, caption); + isHtml = fnHtml(file.type, caption); + isImage = fnImage(file.type, caption); + $status.html(msgLoading.replace('{index}', i + 1).replace('{files}', numFiles)); + $container.addClass('file-thumb-loading'); + reader.onerror = function (evt) { + self._errorHandler(evt, caption); + }; + reader.onload = function (theFile) { + var hex, fileInfo, uint, byte, bytes = [], contents, mime, readTextImage = function (textFlag) { + var newReader = new FileReader(); + newReader.onerror = function (theFileNew) { + self._errorHandler(theFileNew, caption); + }; + newReader.onload = function (theFileNew) { + self._previewFile(i, file, theFileNew, previewId, previewData, fileInfo); + self._initFileActions(); + processFileLoaded(); + }; + if (textFlag) { + newReader.readAsText(file, self.textEncoding); + } else { + newReader.readAsDataURL(file); + } + }; + fileInfo = {'name': caption, 'type': file.type}; + $.each(settings, function (key, func) { + if (key !== 'object' && key !== 'other' && func(file.type, caption)) { + knownTypes++; + } + }); + if (knownTypes === 0) {// auto detect mime types from content if no known file types detected + uint = new Uint8Array(theFile.target.result); + for (j = 0; j < uint.length; j++) { + byte = uint[j].toString(16); + bytes.push(byte); + } + hex = bytes.join('').toLowerCase().substring(0, 8); + mime = $h.getMimeType(hex, '', ''); + if ($h.isEmpty(mime)) { // look for ascii text content + contents = $h.arrayBuffer2String(reader.result); + mime = $h.isSvg(contents) ? 'image/svg+xml' : $h.getMimeType(hex, contents, file.type); + } + fileInfo = {'name': caption, 'type': mime}; + isText = fnText(mime, ''); + isHtml = fnHtml(mime, ''); + isImage = fnImage(mime, ''); + txtFlag = isText || isHtml; + if (txtFlag || isImage) { + readTextImage(txtFlag); + return; + } + } + self._previewFile(i, file, theFile, previewId, previewData, fileInfo); + self._initFileActions(); + processFileLoaded(); + }; + reader.onprogress = function (data) { + if (data.lengthComputable) { + var fact = (data.loaded / data.total) * 100, progress = Math.ceil(fact); + msg = msgProgress.setTokens({ + 'index': i + 1, + 'files': numFiles, + 'percent': progress, + 'name': caption + }); + setTimeout(function () { + $status.html(msg); + }, 100); + } + }; + + if (isText || isHtml) { + reader.readAsText(file, self.textEncoding); + } else { + if (isImage) { + reader.readAsDataURL(file); + } else { + reader.readAsArrayBuffer(file); + } + } + } else { + self._previewDefault(file, previewId); + setTimeout(function () { + readFile(i + 1); + self._updateFileDetails(numFiles); + }, 100); + self._raise('fileloaded', [file, previewId, i, reader]); + } + self.addToStack(file); + }; + + readFile(0); + self._updateFileDetails(numFiles, false); + }, + lock: function () { + var self = this; + self._resetErrors(); + self.disable(); + if (self.showRemove) { + self.$container.find('.fileinput-remove').hide(); + } + if (self.showCancel) { + self.$container.find('.fileinput-cancel').show(); + } + self._raise('filelock', [self.filestack, self._getExtraData()]); + return self.$element; + }, + unlock: function (reset) { + var self = this; + if (reset === undefined) { + reset = true; + } + self.enable(); + if (self.showCancel) { + self.$container.find('.fileinput-cancel').hide(); + } + if (self.showRemove) { + self.$container.find('.fileinput-remove').show(); + } + if (reset) { + self._resetFileStack(); + } + self._raise('fileunlock', [self.filestack, self._getExtraData()]); + return self.$element; + }, + cancel: function () { + var self = this, xhr = self.ajaxRequests, len = xhr.length, i; + if (len > 0) { + for (i = 0; i < len; i += 1) { + self.cancelling = true; + xhr[i].abort(); + } + } + self._setProgressCancelled(); + self._getThumbs().each(function () { + var $thumb = $(this), ind = $thumb.attr('data-fileindex'); + $thumb.removeClass('file-uploading'); + if (self.filestack[ind] !== undefined) { + $thumb.find('.kv-file-upload').removeClass('disabled').removeAttr('disabled'); + $thumb.find('.kv-file-remove').removeClass('disabled').removeAttr('disabled'); + } + self.unlock(); + }); + return self.$element; + }, + clear: function () { + var self = this, cap; + if (!self._raise('fileclear')) { + return; + } + self.$btnUpload.removeAttr('disabled'); + self._getThumbs().find('video,audio,img').each(function () { + $h.cleanMemory($(this)); + }); + self._clearFileInput(); + self._resetUpload(); + self.clearStack(); + self._resetErrors(true); + if (self._hasInitialPreview()) { + self._showFileIcon(); + self._resetPreview(); + self._initPreviewActions(); + self.$container.removeClass('file-input-new'); + } else { + self._getThumbs().each(function () { + self._clearObjects($(this)); + }); + if (self.isAjaxUpload) { + self.previewCache.data = {}; + } + self.$preview.html(''); + cap = (!self.overwriteInitial && self.initialCaption.length > 0) ? self.initialCaption : ''; + self.$caption.attr('title', '').val(cap); + $h.addCss(self.$container, 'file-input-new'); + self._validateDefaultPreview(); + } + if (self.$container.find($h.FRAMES).length === 0) { + if (!self._initCaption()) { + self.$captionContainer.removeClass('icon-visible'); + } + } + self._hideFileIcon(); + self._raise('filecleared'); + self.$captionContainer.focus(); + self._setFileDropZoneTitle(); + return self.$element; + }, + reset: function () { + var self = this; + if (!self._raise('filereset')) { + return; + } + self._resetPreview(); + self.$container.find('.fileinput-filename').text(''); + $h.addCss(self.$container, 'file-input-new'); + if (self.getFrames().length || self.dropZoneEnabled) { + self.$container.removeClass('file-input-new'); + } + self.clearStack(); + self.formdata = {}; + self._setFileDropZoneTitle(); + return self.$element; + }, + disable: function () { + var self = this; + self.isDisabled = true; + self._raise('filedisabled'); + self.$element.attr('disabled', 'disabled'); + self.$container.find(".kv-fileinput-caption").addClass("file-caption-disabled"); + self.$container.find(".fileinput-remove, .fileinput-upload, .file-preview-frame button") + .attr("disabled", true); + $h.addCss(self.$container.find('.btn-file'), 'disabled'); + self._initDragDrop(); + return self.$element; + }, + enable: function () { + var self = this; + self.isDisabled = false; + self._raise('fileenabled'); + self.$element.removeAttr('disabled'); + self.$container.find(".kv-fileinput-caption").removeClass("file-caption-disabled"); + self.$container.find(".fileinput-remove, .fileinput-upload, .file-preview-frame button") + .removeAttr("disabled"); + self.$container.find('.btn-file').removeClass('disabled'); + self._initDragDrop(); + return self.$element; + }, + upload: function () { + var self = this, totLen = self.getFileStack().length, i, outData, len, + hasExtraData = !$.isEmptyObject(self._getExtraData()); + if (!self.isAjaxUpload || self.isDisabled || !self._isFileSelectionValid(totLen)) { + return; + } + self._resetUpload(); + if (totLen === 0 && !hasExtraData) { + self._showUploadError(self.msgUploadEmpty); + return; + } + self.$progress.show(); + self.uploadCount = 0; + self.uploadStatus = {}; + self.uploadLog = []; + self.lock(); + self._setProgress(2); + if (totLen === 0 && hasExtraData) { + self._uploadExtraOnly(); + return; + } + len = self.filestack.length; + self.hasInitData = false; + if (self.uploadAsync) { + outData = self._getOutData(); + self._raise('filebatchpreupload', [outData]); + self.fileBatchCompleted = false; + self.uploadCache = {content: [], config: [], tags: [], append: true}; + self.uploadAsyncCount = self.getFileStack().length; + for (i = 0; i < len; i++) { + self.uploadCache.content[i] = null; + self.uploadCache.config[i] = null; + self.uploadCache.tags[i] = null; + } + self.$preview.find('.file-preview-initial').removeClass($h.SORT_CSS); + self._initSortable(); + self.cacheInitialPreview = self.getPreview(); + + for (i = 0; i < len; i++) { + if (self.filestack[i]) { + self._uploadSingle(i, true); + } + } + return; + } + self._uploadBatch(); + return self.$element; + }, + destroy: function () { + var self = this, $form = self.$form, $cont = self.$container, $el = self.$element, ns = self.namespace; + $(document).off(ns); + $(window).off(ns); + if ($form && $form.length) { + $form.off(ns); + } + if (self.isAjaxUpload) { + self._clearFileInput(); + } + self._cleanup(); + self._initPreviewCache(); + $el.insertBefore($cont).off(ns).removeData(); + $cont.off().remove(); + return $el; + }, + refresh: function (options) { + var self = this, $el = self.$element; + if (typeof options !== 'object' || $h.isEmpty(options)) { + options = self.options; + } else { + options = $.extend(true, {}, self.options, options); + } + self._init(options, true); + self._listen(); + return $el; + }, + zoom: function (frameId) { + var self = this, $frame = self._getFrame(frameId), $modal = self.$modal; + if (!$frame) { + return; + } + $h.initModal($modal); + $modal.html(self._getModalContent()); + self._setZoomContent($frame); + $modal.modal('show'); + self._initZoomButtons(); + }, + getExif: function (frameId) { + var self = this, $frame = self._getFrame(frameId); + return $frame && $frame.data('exif') || null; + }, + getFrames: function (cssFilter) { + var self = this, $frames; + cssFilter = cssFilter || ''; + $frames = self.$preview.find($h.FRAMES + cssFilter); + if (self.reversePreviewOrder) { + $frames = $($frames.get().reverse()); + } + return $frames; + }, + getPreview: function () { + var self = this; + return { + content: self.initialPreview, + config: self.initialPreviewConfig, + tags: self.initialPreviewThumbTags + }; + } + }; + + $.fn.fileinput = function (option) { + if (!$h.hasFileAPISupport() && !$h.isIE(9)) { + return; + } + var args = Array.apply(null, arguments), retvals = []; + args.shift(); + this.each(function () { + var self = $(this), data = self.data('fileinput'), options = typeof option === 'object' && option, + theme = options.theme || self.data('theme'), l = {}, t = {}, + lang = options.language || self.data('language') || $.fn.fileinput.defaults.language || 'en', opt; + if (!data) { + if (theme) { + t = $.fn.fileinputThemes[theme] || {}; + } + if (lang !== 'en' && !$h.isEmpty($.fn.fileinputLocales[lang])) { + l = $.fn.fileinputLocales[lang] || {}; + } + opt = $.extend(true, {}, $.fn.fileinput.defaults, t, $.fn.fileinputLocales.en, l, options, self.data()); + data = new FileInput(this, opt); + self.data('fileinput', data); + } + + if (typeof option === 'string') { + retvals.push(data[option].apply(data, args)); + } + }); + switch (retvals.length) { + case 0: + return this; + case 1: + return retvals[0]; + default: + return retvals; + } + }; + + $.fn.fileinput.defaults = { + language: 'en', + showCaption: true, + showBrowse: true, + showPreview: true, + showRemove: true, + showUpload: true, + showCancel: true, + showClose: true, + showUploadedThumbs: true, + browseOnZoneClick: false, + autoReplace: false, + autoOrientImage: true, // for JPEG images based on EXIF orientation tag + required: false, + rtl: false, + hideThumbnailContent: false, + generateFileId: null, + previewClass: '', + captionClass: '', + frameClass: 'krajee-default', + mainClass: 'file-caption-main', + mainTemplate: null, + purifyHtml: true, + fileSizeGetter: null, + initialCaption: '', + initialPreview: [], + initialPreviewDelimiter: '*$$*', + initialPreviewAsData: false, + initialPreviewFileType: 'image', + initialPreviewConfig: [], + initialPreviewThumbTags: [], + previewThumbTags: {}, + initialPreviewShowDelete: true, + initialPreviewDownloadUrl: '', + removeFromPreviewOnError: false, + deleteUrl: '', + deleteExtraData: {}, + overwriteInitial: true, + previewZoomButtonIcons: { + prev: '', + next: '', + toggleheader: '', + fullscreen: '', + borderless: '', + close: '' + }, + previewZoomButtonClasses: { + prev: 'btn btn-navigate', + next: 'btn btn-navigate', + toggleheader: 'btn btn-sm btn-kv btn-default btn-outline-secondary', + fullscreen: 'btn btn-sm btn-kv btn-default btn-outline-secondary', + borderless: 'btn btn-sm btn-kv btn-default btn-outline-secondary', + close: 'btn btn-sm btn-kv btn-default btn-outline-secondary' + }, + preferIconicPreview: false, + preferIconicZoomPreview: false, + allowedPreviewTypes: undefined, + allowedPreviewMimeTypes: null, + allowedFileTypes: null, + allowedFileExtensions: null, + defaultPreviewContent: null, + customLayoutTags: {}, + customPreviewTags: {}, + previewFileIcon: '', + previewFileIconClass: 'file-other-icon', + previewFileIconSettings: {}, + previewFileExtSettings: {}, + buttonLabelClass: 'hidden-xs', + browseIcon: ' ', + browseClass: 'btn btn-primary', + removeIcon: '', + removeClass: 'btn btn-default btn-secondary', + cancelIcon: '', + cancelClass: 'btn btn-default btn-secondary', + uploadIcon: '', + uploadClass: 'btn btn-default btn-secondary', + uploadUrl: null, + uploadUrlThumb: null, + uploadAsync: true, + uploadExtraData: {}, + zoomModalHeight: 480, + minImageWidth: null, + minImageHeight: null, + maxImageWidth: null, + maxImageHeight: null, + resizeImage: false, + resizePreference: 'width', + resizeQuality: 0.92, + resizeDefaultImageType: 'image/jpeg', + resizeIfSizeMoreThan: 0, // in KB + minFileSize: 0, + maxFileSize: 0, + maxFilePreviewSize: 25600, // 25 MB + minFileCount: 0, + maxFileCount: 0, + validateInitialCount: false, + msgValidationErrorClass: 'text-danger', + msgValidationErrorIcon: ' ', + msgErrorClass: 'file-error-message', + progressThumbClass: "progress-bar bg-success progress-bar-success progress-bar-striped active", + progressClass: "progress-bar bg-success progress-bar-success progress-bar-striped active", + progressCompleteClass: "progress-bar bg-success progress-bar-success", + progressErrorClass: "progress-bar bg-danger progress-bar-danger", + progressUploadThreshold: 99, + previewFileType: 'image', + elCaptionContainer: null, + elCaptionText: null, + elPreviewContainer: null, + elPreviewImage: null, + elPreviewStatus: null, + elErrorContainer: null, + errorCloseButton: $h.closeButton('kv-error-close'), + slugCallback: null, + dropZoneEnabled: true, + dropZoneTitleClass: 'file-drop-zone-title', + fileActionSettings: {}, + otherActionButtons: '', + textEncoding: 'UTF-8', + ajaxSettings: {}, + ajaxDeleteSettings: {}, + showAjaxErrorDetails: true, + mergeAjaxCallbacks: false, + mergeAjaxDeleteCallbacks: false, + retryErrorUploads: true, + reversePreviewOrder: false + }; + + $.fn.fileinputLocales.en = { + fileSingle: 'file', + filePlural: 'files', + browseLabel: 'Browse …', + removeLabel: 'Remove', + removeTitle: 'Clear selected files', + cancelLabel: 'Cancel', + cancelTitle: 'Abort ongoing upload', + uploadLabel: 'Upload', + uploadTitle: 'Upload selected files', + msgNo: 'No', + msgNoFilesSelected: 'No files selected', + msgCancelled: 'Cancelled', + msgPlaceholder: 'Select {files}...', + msgZoomModalHeading: 'Detailed Preview', + msgFileRequired: 'You must select a file to upload.', + msgSizeTooSmall: 'File "{name}" ({size} KB) is too small and must be larger than {minSize} KB.', + msgSizeTooLarge: 'File "{name}" ({size} KB) exceeds maximum allowed upload size of {maxSize} KB.', + msgFilesTooLess: 'You must select at least {n} {files} to upload.', + msgFilesTooMany: 'Number of files selected for upload ({n}) exceeds maximum allowed limit of {m}.', + msgFileNotFound: 'File "{name}" not found!', + msgFileSecured: 'Security restrictions prevent reading the file "{name}".', + msgFileNotReadable: 'File "{name}" is not readable.', + msgFilePreviewAborted: 'File preview aborted for "{name}".', + msgFilePreviewError: 'An error occurred while reading the file "{name}".', + msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".', + msgInvalidFileType: 'Invalid type for file "{name}". Only "{types}" files are supported.', + msgInvalidFileExtension: 'Invalid extension for file "{name}". Only "{extensions}" files are supported.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: 'The file upload was aborted', + msgUploadThreshold: 'Processing...', + msgUploadBegin: 'Initializing...', + msgUploadEnd: 'Done', + msgUploadEmpty: 'No valid data available for upload.', + msgUploadError: 'Error', + msgValidationError: 'Validation Error', + msgLoading: 'Loading file {index} of {files} …', + msgProgress: 'Loading file {index} of {files} - {name} - {percent}% completed.', + msgSelected: '{n} {files} selected', + msgFoldersNotAllowed: 'Drag & drop files only! {n} folder(s) dropped were skipped.', + msgImageWidthSmall: 'Width of image file "{name}" must be at least {size} px.', + msgImageHeightSmall: 'Height of image file "{name}" must be at least {size} px.', + msgImageWidthLarge: 'Width of image file "{name}" cannot exceed {size} px.', + msgImageHeightLarge: 'Height of image file "{name}" cannot exceed {size} px.', + msgImageResizeError: 'Could not get the image dimensions to resize.', + msgImageResizeException: 'Error while resizing the image.{errors}', + msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!', + msgAjaxProgressError: '{operation} failed', + ajaxOperations: { + deleteThumb: 'file delete', + uploadThumb: 'file upload', + uploadBatch: 'batch file upload', + uploadExtra: 'form data upload' + }, + dropZoneTitle: 'Drag & drop files here …', + dropZoneClickTitle: '(or click to select {files})', + previewZoomButtonTitles: { + prev: 'View previous file', + next: 'View next file', + toggleheader: 'Toggle header', + fullscreen: 'Toggle full screen', + borderless: 'Toggle borderless mode', + close: 'Close detailed preview' + } + }; + + $.fn.fileinput.Constructor = FileInput; + + /** + * Convert automatically file inputs with class 'file' into a bootstrap fileinput control. + */ + $(document).ready(function () { + var $input = $('input.file[type=file]'); + if ($input.length) { + $input.fileinput(); + } + }); +})); \ No newline at end of file diff --git a/src/main/resources/static/js/plugins/fileinput/fileinput.min.js b/src/main/resources/static/js/plugins/fileinput/fileinput.min.js new file mode 100644 index 000000000..03cc9cf2c --- /dev/null +++ b/src/main/resources/static/js/plugins/fileinput/fileinput.min.js @@ -0,0 +1,12 @@ +/*! + * bootstrap-fileinput v4.4.9 + * http://plugins.krajee.com/file-input + * + * Author: Kartik Visweswaran + * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com + * + * Licensed under the BSD 3-Clause + * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md + */!function(e){"use strict";"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof module&&module.exports?module.exports=e(require("jquery")):e(window.jQuery)}(function(e){"use strict";e.fn.fileinputLocales={},e.fn.fileinputThemes={},String.prototype.setTokens=function(e){var t,i,a=this.toString();for(t in e)e.hasOwnProperty(t)&&(i=new RegExp("{"+t+"}","g"),a=a.replace(i,e[t]));return a};var t,i;t={FRAMES:".kv-preview-thumb",SORT_CSS:"file-sortable",OBJECT_PARAMS:'\n\n\n\n\n\n',DEFAULT_PREVIEW:'\n{previewFileIcon}\n',MODAL_ID:"kvFileinputModal",MODAL_EVENTS:["show","shown","hide","hidden","loaded"],objUrl:window.URL||window.webkitURL,compare:function(e,t,i){return void 0!==e&&(i?e===t:e.match(t))},isIE:function(e){if("Microsoft Internet Explorer"!==navigator.appName)return!1;if(10===e)return new RegExp("msie\\s"+e,"i").test(navigator.userAgent);var t,i=document.createElement("div");return i.innerHTML="",t=i.getElementsByTagName("i").length,document.body.appendChild(i),i.parentNode.removeChild(i),t},canAssignFilesToInput:function(){var e=document.createElement("input");try{return e.type="file",e.files=null,!0}catch(t){return!1}},getDragDropFolders:function(e){var t,i,a=e.length,r=0;if(a>0&&e[0].webkitGetAsEntry())for(t=0;a>t;t++)i=e[t].webkitGetAsEntry(),i&&i.isDirectory&&r++;return r},initModal:function(t){var i=e("body");i.length&&t.appendTo(i)},isEmpty:function(t,i){return void 0===t||null===t||0===t.length||i&&""===e.trim(t)},isArray:function(e){return Array.isArray(e)||"[object Array]"===Object.prototype.toString.call(e)},ifSet:function(e,t,i){return i=i||"",t&&"object"==typeof t&&e in t?t[e]:i},cleanArray:function(e){return e instanceof Array||(e=[]),e.filter(function(e){return void 0!==e&&null!==e})},spliceArray:function(t,i,a){var r,n,o=0,l=[];if(!(t instanceof Array))return[];for(n=e.extend(!0,[],t),a&&n.reverse(),r=0;r=0?atob(e.split(",")[1]):decodeURIComponent(e.split(",")[1]),a=new ArrayBuffer(i.length),r=new Uint8Array(a),n=0;nl;)switch(i=n[l++],i>>4){case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:o+=String.fromCharCode(i);break;case 12:case 13:a=n[l++],o+=String.fromCharCode((31&i)<<6|63&a);break;case 14:a=n[l++],r=n[l++],o+=String.fromCharCode((15&i)<<12|(63&a)<<6|(63&r)<<0)}return o},isHtml:function(e){var t=document.createElement("div");t.innerHTML=e;for(var i=t.childNodes,a=i.length;a--;)if(1===i[a].nodeType)return!0;return!1},isSvg:function(e){return e.match(/^\s*<\?xml/i)&&(e.match(//g,">").replace(/"/g,""").replace(/'/g,"'")},replaceTags:function(t,i){var a=t;return i?(e.each(i,function(e,t){"function"==typeof t&&(t=t()),a=a.split(e).join(t)}),a):a},cleanMemory:function(e){var i=e.is("img")?e.attr("src"):e.find("source").attr("src");t.objUrl.revokeObjectURL(i)},findFileName:function(e){var t=e.lastIndexOf("/");return-1===t&&(t=e.lastIndexOf("\\")),e.split(e.substring(t,t+1)).pop()},checkFullScreen:function(){return document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement},toggleFullScreen:function(e){var i=document,a=i.documentElement;a&&e&&!t.checkFullScreen()?a.requestFullscreen?a.requestFullscreen():a.msRequestFullscreen?a.msRequestFullscreen():a.mozRequestFullScreen?a.mozRequestFullScreen():a.webkitRequestFullscreen&&a.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT):i.exitFullscreen?i.exitFullscreen():i.msExitFullscreen?i.msExitFullscreen():i.mozCancelFullScreen?i.mozCancelFullScreen():i.webkitExitFullscreen&&i.webkitExitFullscreen()},moveArray:function(t,i,a,r){var n=e.extend(!0,[],t);if(r&&n.reverse(),a>=n.length)for(var o=a-n.length;o--+1;)n.push(void 0);return n.splice(a,0,n.splice(i,1)[0]),r&&n.reverse(),n},cleanZoomCache:function(e){var t=e.closest(".kv-zoom-cache-theme");t.length||(t=e.closest(".kv-zoom-cache")),t.remove()},setOrientation:function(e,t){var i,a,r,n=new DataView(e),o=0,l=1;if(65496!==n.getUint16(o)||e.length<2)return void(t&&t());for(o+=2,i=n.byteLength;i-2>o;)switch(a=n.getUint16(o),o+=2,a){case 65505:r=n.getUint16(o),i=r-o,o+=2;break;case 274:l=n.getUint16(o+6,!1),i=0}t&&t(l)},validateOrientation:function(e,i){if(window.FileReader&&window.DataView){var a,r=new FileReader;r.onloadend=function(){a=r.result,t.setOrientation(a,i)},r.readAsArrayBuffer(e)}},adjustOrientedImage:function(e,t){var i,a,r;if(e.hasClass("is-portrait-gt4")){if(t)return void e.css({width:e.parent().height()});e.css({height:"auto",width:e.height()}),i=e.parent().offset().top,a=e.offset().top,r=i-a,e.css("margin-top",r)}},closeButton:function(e){return e=e?"close "+e:"close",'\n ×\n'}},i=function(i,a){var r=this;r.$element=e(i),r.$parent=r.$element.parent(),r._validate()&&(r.isPreviewable=t.hasFileAPISupport(),r.isIE9=t.isIE(9),r.isIE10=t.isIE(10),(r.isPreviewable||r.isIE9)&&(r._init(a),r._listen()),r.$element.removeClass("file-loading"))},i.prototype={constructor:i,_cleanup:function(){var e=this;e.reader=null,e.formdata={},e.uploadCount=0,e.uploadStatus={},e.uploadLog=[],e.uploadAsyncCount=0,e.loadedImages=[],e.totalImagesCount=0,e.ajaxRequests=[],e.clearStack(),e.fileBatchCompleted=!0,e.isPreviewable||(e.showPreview=!1),e.isError=!1,e.ajaxAborted=!1,e.cancelling=!1},_init:function(i,a){var r,n,o,l,s=this,d=s.$element;s.options=i,e.each(i,function(e,i){switch(e){case"minFileCount":case"maxFileCount":case"minFileSize":case"maxFileSize":case"maxFilePreviewSize":case"resizeImageQuality":case"resizeIfSizeMoreThan":case"progressUploadThreshold":case"initialPreviewCount":case"zoomModalHeight":case"minImageHeight":case"maxImageHeight":case"minImageWidth":case"maxImageWidth":s[e]=t.getNum(i);break;default:s[e]=i}}),s.rtl&&(l=s.previewZoomButtonIcons.prev,s.previewZoomButtonIcons.prev=s.previewZoomButtonIcons.next,s.previewZoomButtonIcons.next=l),a||s._cleanup(),s.$form=d.closest("form"),s._initTemplateDefaults(),s.uploadFileAttr=t.isEmpty(d.attr("name"))?"file_data":d.attr("name"),o=s._getLayoutTemplate("progress"),s.progressTemplate=o.replace("{class}",s.progressClass),s.progressCompleteTemplate=o.replace("{class}",s.progressCompleteClass),s.progressErrorTemplate=o.replace("{class}",s.progressErrorClass),s.isDisabled=d.attr("disabled")||d.attr("readonly"),s.isDisabled&&d.attr("disabled",!0),s.isAjaxUpload=t.hasFileUploadSupport()&&!t.isEmpty(s.uploadUrl),s.dropZoneEnabled=t.hasDragDropSupport()&&s.dropZoneEnabled,s.isAjaxUpload||(s.dropZoneEnabled=s.dropZoneEnabled&&t.canAssignFilesToInput()),s.isClickable=s.browseOnZoneClick&&s.showPreview&&(s.dropZoneEnabled||!t.isEmpty(s.defaultPreviewContent)),s.slug="function"==typeof i.slugCallback?i.slugCallback:s._slugDefault,s.mainTemplate=s.showCaption?s._getLayoutTemplate("main1"):s._getLayoutTemplate("main2"),s.captionTemplate=s._getLayoutTemplate("caption"),s.previewGenericTemplate=s._getPreviewTemplate("generic"),!s.imageCanvas&&s.resizeImage&&(s.maxImageWidth||s.maxImageHeight)&&(s.imageCanvas=document.createElement("canvas"),s.imageCanvasContext=s.imageCanvas.getContext("2d")),t.isEmpty(d.attr("id"))&&d.attr("id",t.uniqId()),s.namespace=".fileinput_"+d.attr("id").replace(/-/g,"_"),void 0===s.$container?s.$container=s._createContainer():s._refreshContainer(),n=s.$container,s.$dropZone=n.find(".file-drop-zone"),s.$progress=n.find(".kv-upload-progress"),s.$btnUpload=n.find(".fileinput-upload"),s.$captionContainer=t.getElement(i,"elCaptionContainer",n.find(".file-caption")),s.$caption=t.getElement(i,"elCaptionText",n.find(".file-caption-name")),t.isEmpty(s.msgPlaceholder)||(r=d.attr("multiple")?s.filePlural:s.fileSingle,s.$caption.attr("placeholder",s.msgPlaceholder.replace("{files}",r))),s.$captionIcon=s.$captionContainer.find(".file-caption-icon"),s.$previewContainer=t.getElement(i,"elPreviewContainer",n.find(".file-preview")),s.$preview=t.getElement(i,"elPreviewImage",n.find(".file-preview-thumbnails")),s.$previewStatus=t.getElement(i,"elPreviewStatus",n.find(".file-preview-status")),s.$errorContainer=t.getElement(i,"elErrorContainer",s.$previewContainer.find(".kv-fileinput-error")),s._validateDisabled(),t.isEmpty(s.msgErrorClass)||t.addCss(s.$errorContainer,s.msgErrorClass),a?s._errorsExist()||s.$errorContainer.hide():(s.$errorContainer.hide(),s.previewInitId="preview-"+t.uniqId(),s._initPreviewCache(),s._initPreview(!0),s._initPreviewActions(),s.$parent.hasClass("file-loading")&&(s.$container.insertBefore(s.$parent),s.$parent.remove())),s._setFileDropZoneTitle(),d.attr("disabled")&&s.disable(),s._initZoom(),s.hideThumbnailContent&&t.addCss(s.$preview,"hide-content")},_initTemplateDefaults:function(){var i,a,r,n,o,l,s,d,c,p,u,f,m,v,g,h,w,_,b,C,y,x,T,E,S,k,F,P,I,A,D,z,$,j,U,B,O,R,L,Z,M=this;i='{preview}\n\n\n {caption}\n\n {remove}\n {cancel}\n {upload}\n {browse}\n \n',a='{preview}\n\n\n{remove}\n{cancel}\n{upload}\n{browse}\n',r='\n {close} \n \n \n \n \n \n',o=t.closeButton("fileinput-remove"),n='',l='\n \n \n',s='{icon} {label}',d='{icon} {label}',c='{icon} {label}',p='',u='\n \n \n {heading}\n \n {toggleheader}{fullscreen}{borderless}{close}\n \n \n \n \n{prev} {next}\n \n \n\n',f='\n \n {status}\n \n',m=" ({sizeText})",v='',g='\n \n\n{drag}\n',h='{removeIcon}\n',w='{uploadIcon}',_='{downloadIcon}',b='{zoomIcon}',C='{dragIcon}',y='{indicator}',x='\n',E=x+' title="{caption}">\n',S="{footer}\n\n",k="{content}\n",R=" {style}",F='{data}\n",P='\n",I='{data}\n",A='",D='",z='\n\n'+t.DEFAULT_PREVIEW+"\n\n",$='\n\n'+t.DEFAULT_PREVIEW+"\n\n",j='\n",B='\n",U='\n\n'+t.OBJECT_PARAMS+" "+t.DEFAULT_PREVIEW+"\n\n",O='\n"+t.DEFAULT_PREVIEW+"\n\n",L='{zoomContent}',Z={width:"100%",height:"100%","min-height":"480px"},M.defaults={layoutTemplates:{main1:i,main2:a,preview:r,close:o,fileIcon:n,caption:l,modalMain:p,modal:u,progress:f,size:m,footer:v,indicator:y,actions:g,actionDelete:h,actionUpload:w,actionDownload:_,actionZoom:b,actionDrag:C,btnDefault:s,btnLink:d,btnBrowse:c,zoomCache:L},previewMarkupTags:{tagBefore1:T,tagBefore2:E,tagAfter:S},previewContentTemplates:{generic:k,html:F,image:P,text:I,office:A,gdocs:D,video:z,audio:$,flash:j,object:U,pdf:B,other:O},allowedPreviewTypes:["image","html","text","video","audio","flash","pdf","object"],previewTemplates:{},previewSettings:{image:{width:"auto",height:"auto","max-width":"100%","max-height":"100%"},html:{width:"213px",height:"160px"},text:{width:"213px",height:"160px"},office:{width:"213px",height:"160px"},gdocs:{width:"213px",height:"160px"},video:{width:"213px",height:"160px"},audio:{width:"100%",height:"30px"},flash:{width:"213px",height:"160px"},object:{width:"213px",height:"160px"},pdf:{width:"213px",height:"160px"},other:{width:"213px",height:"160px"}},previewSettingsSmall:{image:{width:"auto",height:"auto","max-width":"100%","max-height":"100%"},html:{width:"100%",height:"160px"},text:{width:"100%",height:"160px"},office:{width:"100%",height:"160px"},gdocs:{width:"100%",height:"160px"},video:{width:"100%",height:"auto"},audio:{width:"100%",height:"30px"},flash:{width:"100%",height:"auto"},object:{width:"100%",height:"auto"},pdf:{width:"100%",height:"160px"},other:{width:"100%",height:"160px"}},previewZoomSettings:{image:{width:"auto",height:"auto","max-width":"100%","max-height":"100%"},html:Z,text:Z,office:{width:"100%",height:"100%","max-width":"100%","min-height":"480px"},gdocs:{width:"100%",height:"100%","max-width":"100%","min-height":"480px"},video:{width:"auto",height:"100%","max-width":"100%"},audio:{width:"100%",height:"30px"},flash:{width:"auto",height:"480px"},object:{width:"auto",height:"100%","max-width":"100%","min-height":"480px"},pdf:Z,other:{width:"auto",height:"100%","min-height":"480px"}},fileTypeSettings:{image:function(e,i){return t.compare(e,"image.*")&&!t.compare(e,/(tiff?|wmf)$/i)||t.compare(i,/\.(gif|png|jpe?g)$/i)},html:function(e,i){return t.compare(e,"text/html")||t.compare(i,/\.(htm|html)$/i)},office:function(e,i){return t.compare(e,/(word|excel|powerpoint|office)$/i)||t.compare(i,/\.(docx?|xlsx?|pptx?|pps|potx?)$/i)},gdocs:function(e,i){return t.compare(e,/(word|excel|powerpoint|office|iwork-pages|tiff?)$/i)||t.compare(i,/\.(docx?|xlsx?|pptx?|pps|potx?|rtf|ods|odt|pages|ai|dxf|ttf|tiff?|wmf|e?ps)$/i)},text:function(e,i){return t.compare(e,"text.*")||t.compare(i,/\.(xml|javascript)$/i)||t.compare(i,/\.(txt|md|csv|nfo|ini|json|php|js|css)$/i)},video:function(e,i){return t.compare(e,"video.*")&&(t.compare(e,/(ogg|mp4|mp?g|mov|webm|3gp)$/i)||t.compare(i,/\.(og?|mp4|webm|mp?g|mov|3gp)$/i))},audio:function(e,i){return t.compare(e,"audio.*")&&(t.compare(i,/(ogg|mp3|mp?g|wav)$/i)||t.compare(i,/\.(og?|mp3|mp?g|wav)$/i))},flash:function(e,i){return t.compare(e,"application/x-shockwave-flash",!0)||t.compare(i,/\.(swf)$/i)},pdf:function(e,i){return t.compare(e,"application/pdf",!0)||t.compare(i,/\.(pdf)$/i)},object:function(){return!0},other:function(){return!0}},fileActionSettings:{showRemove:!0,showUpload:!0,showDownload:!0,showZoom:!0,showDrag:!0,removeIcon:'',removeClass:"btn btn-sm btn-kv btn-default btn-outline-secondary",removeErrorClass:"btn btn-sm btn-kv btn-danger",removeTitle:"Remove file",uploadIcon:'',uploadClass:"btn btn-sm btn-kv btn-default btn-outline-secondary",uploadTitle:"Upload file",uploadRetryIcon:'',uploadRetryTitle:"Retry upload",downloadIcon:'',downloadClass:"btn btn-sm btn-kv btn-default btn-outline-secondary",downloadTitle:"Download file",zoomIcon:'',zoomClass:"btn btn-sm btn-kv btn-default btn-outline-secondary",zoomTitle:"View Details",dragIcon:'',dragClass:"text-info",dragTitle:"Move / Rearrange",dragSettings:{},indicatorNew:'',indicatorSuccess:'',indicatorError:'',indicatorLoading:'',indicatorNewTitle:"Not uploaded yet",indicatorSuccessTitle:"Uploaded",indicatorErrorTitle:"Upload Error",indicatorLoadingTitle:"Uploading ..."}},e.each(M.defaults,function(t,i){return"allowedPreviewTypes"===t?void(void 0===M.allowedPreviewTypes&&(M.allowedPreviewTypes=i)):void(M[t]=e.extend(!0,{},i,M[t]))}),M._initPreviewTemplates()},_initPreviewTemplates:function(){var i,a=this,r=a.defaults,n=a.previewMarkupTags,o=n.tagAfter;e.each(r.previewContentTemplates,function(e,r){t.isEmpty(a.previewTemplates[e])&&(i=n.tagBefore2,"generic"!==e&&"image"!==e&&"html"!==e&&"text"!==e||(i=n.tagBefore1),a.previewTemplates[e]=i+r+o)})},_initPreviewCache:function(){var i=this;i.previewCache={data:{},init:function(){var e=i.initialPreview;e.length>0&&!t.isArray(e)&&(e=e.split(i.initialPreviewDelimiter)),i.previewCache.data={content:e,config:i.initialPreviewConfig,tags:i.initialPreviewThumbTags}},count:function(){return i.previewCache.data&&i.previewCache.data.content?i.previewCache.data.content.length:0},get:function(a,r){var n,o,l,s,d,c,p,u="init_"+a,f=i.previewCache.data,m=f.config[a],v=f.content[a],g=i.previewInitId+"-"+u,h=t.ifSet("previewAsData",m,i.initialPreviewAsData),w=function(e,a,r,n,o,l,s,d,c){return d=" file-preview-initial "+t.SORT_CSS+(d?" "+d:""),i._generatePreviewTemplate(e,a,r,n,o,!1,null,d,l,s,c)};return v?(r=void 0===r?!0:r,l=t.ifSet("type",m,i.initialPreviewFileType||"generic"),d=t.ifSet("filename",m,t.ifSet("caption",m)),c=t.ifSet("filetype",m,l),s=i.previewCache.footer(a,r,m&&m.size||null),p=t.ifSet("frameClass",m),n=h?w(l,v,d,c,g,s,u,p):w("generic",v,d,c,g,s,u,p,l).setTokens({content:f.content[a]}),f.tags.length&&f.tags[a]&&(n=t.replaceTags(n,f.tags[a])),t.isEmpty(m)||t.isEmpty(m.frameAttr)||(o=e(document.createElement("div")).html(n),o.find(".file-preview-initial").attr(m.frameAttr),n=o.html(),o.remove()),n):""},add:function(e,a,r,n){var o,l=i.previewCache.data;return t.isArray(e)||(e=e.split(i.initialPreviewDelimiter)),n?(o=l.content.push(e)-1,l.config[o]=a,l.tags[o]=r):(o=e.length-1,l.content=e,l.config=a,l.tags=r),i.previewCache.data=l,o},set:function(e,a,r,n){var o,l,s=i.previewCache.data;if(e&&e.length&&(t.isArray(e)||(e=e.split(i.initialPreviewDelimiter)),l=e.filter(function(e){return null!==e}),l.length)){if(void 0===s.content&&(s.content=[]),void 0===s.config&&(s.config=[]),void 0===s.tags&&(s.tags=[]),n){for(o=0;ot;t++)a=i.previewCache.get(t),r=i.reversePreviewOrder?a+r:r+a;return e=i._getMsgSelected(n),{content:r,caption:e}},footer:function(e,a,r){var n=i.previewCache.data||{};if(t.isEmpty(n.content))return"";(t.isEmpty(n.config)||t.isEmpty(n.config[e]))&&(n.config[e]={}),a=void 0===a?!0:a;var o,l=n.config[e],s=t.ifSet("caption",l),d=t.ifSet("width",l,"auto"),c=t.ifSet("url",l,!1),p=t.ifSet("key",l,null),u=i.fileActionSettings,f=i.initialPreviewShowDelete||!1,m=l.downloadUrl||i.initialPreviewDownloadUrl||"",v=l.filename||l.caption||"",g=!!m,h=t.ifSet("showRemove",l,t.ifSet("showRemove",u,f)),w=t.ifSet("showDownload",l,t.ifSet("showDownload",u,g)),_=t.ifSet("showZoom",l,t.ifSet("showZoom",u,!0)),b=t.ifSet("showDrag",l,t.ifSet("showDrag",u,!0)),C=c===!1&&a;return w=w&&l.downloadUrl!==!1&&!!m,o=i._renderFileActions(!1,w,h,_,b,C,c,p,!0,m,v),i._getLayoutTemplate("footer").setTokens({progress:i._renderThumbProgress(),actions:o,caption:s,size:i._getSize(r),width:d,indicator:""})}},i.previewCache.init()},_handler:function(e,t,i){var a=this,r=a.namespace,n=t.split(" ").join(r+" ")+r;e&&e.length&&e.off(n).on(n,i)},_log:function(e){var t=this,i=t.$element.attr("id");i&&(e='"'+i+'": '+e),"undefined"!=typeof window.console.log?window.console.log(e):window.alert(e)},_validate:function(){var e=this,t="file"===e.$element.attr("type");return t||e._log('The input "type" must be set to "file" for initializing the "bootstrap-fileinput" plugin.'),t},_errorsExist:function(){var t,i=this,a=i.$errorContainer.find("li");return a.length?!0:(t=e(document.createElement("div")).html(i.$errorContainer.html()),t.find(".kv-error-close").remove(),t.find("ul").remove(),!!e.trim(t.text()).length)},_errorHandler:function(e,t){var i=this,a=e.target.error,r=function(e){i._showError(e.replace("{name}",t))};r(a.code===a.NOT_FOUND_ERR?i.msgFileNotFound:a.code===a.SECURITY_ERR?i.msgFileSecured:a.code===a.NOT_READABLE_ERR?i.msgFileNotReadable:a.code===a.ABORT_ERR?i.msgFilePreviewAborted:i.msgFilePreviewError)},_addError:function(e){var t=this,i=t.$errorContainer;e&&i.length&&(i.html(t.errorCloseButton+e),t._handler(i.find(".kv-error-close"),"click",function(){setTimeout(function(){t.showPreview&&!t.getFrames().length&&t.clear(),i.fadeOut("slow")},10)}))},_setValidationError:function(e){var i=this;e=(e?e+" ":"")+"has-error",i.$container.removeClass(e).addClass("has-error"),t.addCss(i.$captionContainer,"is-invalid")},_resetErrors:function(e){var t=this,i=t.$errorContainer;t.isError=!1,t.$container.removeClass("has-error"),t.$captionContainer.removeClass("is-invalid"),i.html(""),e?i.fadeOut("slow"):i.hide()},_showFolderError:function(e){var t,i=this,a=i.$errorContainer;e&&(i.isAjaxUpload||i._clearFileInput(),t=i.msgFoldersNotAllowed.replace("{n}",e),i._addError(t),i._setValidationError(),a.fadeIn(800),i._raise("filefoldererror",[e,t]))},_showUploadError:function(e,t,i){var a=this,r=a.$errorContainer,n=i||"fileuploaderror",o=t&&t.id?''+e+"":""+e+"";return 0===r.find("ul").length?a._addError(""+o+""):r.find("ul").append(o),r.fadeIn(800),a._raise(n,[t,e]),a._setValidationError("file-input-new"),!0},_showError:function(e,t,i){var a=this,r=a.$errorContainer,n=i||"fileerror";return t=t||{},t.reader=a.reader,a._addError(e),r.fadeIn(800),a._raise(n,[t,e]),a.isAjaxUpload||a._clearFileInput(),a._setValidationError("file-input-new"),a.$btnUpload.attr("disabled",!0),!0},_noFilesError:function(e){var t=this,i=t.minFileCount>1?t.filePlural:t.fileSingle,a=t.msgFilesTooLess.replace("{n}",t.minFileCount).replace("{files}",i),r=t.$errorContainer;t._addError(a),t.isError=!0,t._updateFileDetails(0),r.fadeIn(800),t._raise("fileerror",[e,a]),t._clearFileInput(),t._setValidationError()},_parseError:function(t,i,a,r){var n,o=this,l=e.trim(a+""),s=void 0!==i.responseJSON&&void 0!==i.responseJSON.error?i.responseJSON.error:i.responseText;return o.cancelling&&o.msgUploadAborted&&(l=o.msgUploadAborted),o.showAjaxErrorDetails&&s&&(s=e.trim(s.replace(/\n\s*\n/g,"\n")),n=s.length?""+s+"":"",l+=l?n:s),l||(l=o.msgAjaxError.replace("{operation}",t)),o.cancelling=!1,r?""+r+": "+l:l},_parseFileType:function(e,i){var a,r,n,o,l=this,s=l.allowedPreviewTypes||[];if("application/text-plain"===e)return"text";for(o=0;o-1&&(i=t.split(".").pop(),a.previewFileIconSettings&&(r=a.previewFileIconSettings[i]||a.previewFileIconSettings[i.toLowerCase()]||null),a.previewFileExtSettings&&e.each(a.previewFileExtSettings,function(e,t){return a.previewFileIconSettings[e]&&t(i)?void(r=a.previewFileIconSettings[e]):void 0})),r},_parseFilePreviewIcon:function(e,t){var i=this,a=i._getPreviewIcon(t)||i.previewFileIcon,r=e;return r.indexOf("{previewFileIcon}")>-1&&(r=r.setTokens({previewFileIconClass:i.previewFileIconClass,previewFileIcon:a})),r},_raise:function(t,i){var a=this,r=e.Event(t);if(void 0!==i?a.$element.trigger(r,i):a.$element.trigger(r),r.isDefaultPrevented()||r.result===!1)return!1;switch(t){case"filebatchuploadcomplete":case"filebatchuploadsuccess":case"fileuploaded":case"fileclear":case"filecleared":case"filereset":case"fileerror":case"filefoldererror":case"fileuploaderror":case"filebatchuploaderror":case"filedeleteerror":case"filecustomerror":case"filesuccessremove":break;default:a.ajaxAborted||(a.ajaxAborted=r.result)}return!0},_listenFullScreen:function(e){var t,i,a=this,r=a.$modal;r&&r.length&&(t=r&&r.find(".btn-fullscreen"),i=r&&r.find(".btn-borderless"),t.length&&i.length&&(t.removeClass("active").attr("aria-pressed","false"),i.removeClass("active").attr("aria-pressed","false"),e?t.addClass("active").attr("aria-pressed","true"):i.addClass("active").attr("aria-pressed","true"),r.hasClass("file-zoom-fullscreen")?a._maximizeZoomDialog():e?a._maximizeZoomDialog():i.removeClass("active").attr("aria-pressed","false")))},_listen:function(){var i,a=this,r=a.$element,n=a.$form,o=a.$container;a._handler(r,"click",function(e){r.hasClass("file-no-browse")&&(r.data("zoneClicked")?r.data("zoneClicked",!1):e.preventDefault())}),a._handler(r,"change",e.proxy(a._change,a)),a.showBrowse&&a._handler(a.$btnFile,"click",e.proxy(a._browse,a)),a._handler(o.find(".fileinput-remove:not([disabled])"),"click",e.proxy(a.clear,a)),a._handler(o.find(".fileinput-cancel"),"click",e.proxy(a.cancel,a)),a._initDragDrop(),a._handler(n,"reset",e.proxy(a.clear,a)),a.isAjaxUpload||a._handler(n,"submit",e.proxy(a._submitForm,a)),a._handler(a.$container.find(".fileinput-upload"),"click",e.proxy(a._uploadClick,a)),a._handler(e(window),"resize",function(){a._listenFullScreen(screen.width===window.innerWidth&&screen.height===window.innerHeight)}),i="webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange",a._handler(e(document),i,function(){a._listenFullScreen(t.checkFullScreen())}),a._autoFitContent(),a._initClickable(),a._refreshPreview()},_autoFitContent:function(){var t,i=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth,a=this,r=400>i?a.previewSettingsSmall||a.defaults.previewSettingsSmall:a.previewSettings||a.defaults.previewSettings;e.each(r,function(e,i){t=".file-preview-frame .file-preview-"+e,a.$preview.find(t+".kv-preview-data,"+t+" .kv-preview-data").css(i)})},_scanDroppedItems:function(e,t,i){i=i||"";var a,r,n,o=this,l=function(e){o._log("Error scanning dropped files!"),o._log(e)};e.isFile?e.file(function(e){t.push(e)},l):e.isDirectory&&(r=e.createReader(), +(n=function(){r.readEntries(function(r){if(r&&r.length>0){for(a=0;a-1;return a._zoneDragDropInit(i),a.isDisabled||!r?(i.originalEvent.dataTransfer.effectAllowed="none",void(i.originalEvent.dataTransfer.dropEffect="none")):void t.addCss(a.$dropZone,"file-highlighted")},_zoneDragLeave:function(e){var t=this;t._zoneDragDropInit(e),t.isDisabled||t.$dropZone.removeClass("file-highlighted")},_zoneDrop:function(e){var i,a=this,r=a.$element,n=e.originalEvent.dataTransfer,o=n.files,l=n.items,s=t.getDragDropFolders(l),d=function(){a.isAjaxUpload?a._change(e,o):(a.changeTriggered=!0,r.get(0).files=o,setTimeout(function(){a.changeTriggered=!1,r.trigger("change"+a.namespace)},10)),a.$dropZone.removeClass("file-highlighted")};if(e.preventDefault(),!a.isDisabled&&!t.isEmpty(o))if(s>0){if(!a.isAjaxUpload)return void a._showFolderError(s);for(o=[],i=0;i"+i+""},_getModalContent:function(){var e=this;return e._getLayoutTemplate("modal").setTokens({rtl:e.rtl?" kv-rtl":"",zoomFrameClass:e.frameClass,heading:e.msgZoomModalHeading,prev:e._getZoomButton("prev"),next:e._getZoomButton("next"),toggleheader:e._getZoomButton("toggleheader"),fullscreen:e._getZoomButton("fullscreen"),borderless:e._getZoomButton("borderless"),close:e._getZoomButton("close")})},_listenModalEvent:function(e){var i=this,a=i.$modal,r=function(e){return{sourceEvent:e,previewId:a.data("previewId"),modal:a}};a.on(e+".bs.modal",function(n){var o=a.find(".btn-fullscreen"),l=a.find(".btn-borderless");i._raise("filezoom"+e,r(n)),"shown"===e&&(l.removeClass("active").attr("aria-pressed","false"),o.removeClass("active").attr("aria-pressed","false"),a.hasClass("file-zoom-fullscreen")&&(i._maximizeZoomDialog(),t.checkFullScreen()?o.addClass("active").attr("aria-pressed","true"):l.addClass("active").attr("aria-pressed","true")))})},_initZoom:function(){var i,a=this,r=a._getLayoutTemplate("modalMain"),n="#"+t.MODAL_ID;a.showPreview&&(a.$modal=e(n),a.$modal&&a.$modal.length||(i=e(document.createElement("div")).html(r).insertAfter(a.$container),a.$modal=e(n).insertBefore(i),i.remove()),t.initModal(a.$modal),a.$modal.html(a._getModalContent()),e.each(t.MODAL_EVENTS,function(e,t){a._listenModalEvent(t)}))},_initZoomButtons:function(){var t,i,a=this,r=a.$modal.data("previewId")||"",n=a.getFrames().toArray(),o=n.length,l=a.$modal.find(".btn-prev"),s=a.$modal.find(".btn-next");return n.length<2?(l.hide(),void s.hide()):(l.show(),s.show(),void(o&&(t=e(n[0]),i=e(n[o-1]),l.removeAttr("disabled"),s.removeAttr("disabled"),t.length&&t.attr("id")===r&&l.attr("disabled",!0),i.length&&i.attr("id")===r&&s.attr("disabled",!0))))},_maximizeZoomDialog:function(){var t=this,i=t.$modal,a=i.find(".modal-header:visible"),r=i.find(".modal-footer:visible"),n=i.find(".modal-body"),o=e(window).height(),l=0;i.addClass("file-zoom-fullscreen"),a&&a.length&&(o-=a.outerHeight(!0)),r&&r.length&&(o-=r.outerHeight(!0)),n&&n.length&&(l=n.outerHeight(!0)-n.height(),o-=l),i.find(".kv-zoom-body").height(o)},_resizeZoomDialog:function(e){var i=this,a=i.$modal,r=a.find(".btn-fullscreen"),n=a.find(".btn-borderless");if(a.hasClass("file-zoom-fullscreen"))t.toggleFullScreen(!1),e?r.hasClass("active")||(a.removeClass("file-zoom-fullscreen"),i._resizeZoomDialog(!0),n.hasClass("active")&&n.removeClass("active").attr("aria-pressed","false")):r.hasClass("active")?r.removeClass("active").attr("aria-pressed","false"):(a.removeClass("file-zoom-fullscreen"),i.$modal.find(".kv-zoom-body").css("height",i.zoomModalHeight));else{if(!e)return void i._maximizeZoomDialog();t.toggleFullScreen(!0)}a.focus()},_setZoomContent:function(i,a){var r,n,o,l,s,d,c,p,u,f,m=this,v=i.attr("id"),g=m.$modal,h=g.find(".btn-prev"),w=g.find(".btn-next"),_=g.find(".btn-fullscreen"),b=g.find(".btn-borderless"),C=g.find(".btn-toggleheader"),y=m.$preview.find("#zoom-"+v);n=y.attr("data-template")||"generic",r=y.find(".kv-file-content"),o=r.length?r.html():"",u=i.data("caption")||"",f=i.data("size")||"",l=u+" "+f,g.find(".kv-zoom-title").attr("title",e("").html(l).text()).html(l),s=g.find(".kv-zoom-body"),g.removeClass("kv-single-content"),a?(p=s.addClass("file-thumb-loading").clone().insertAfter(s),s.html(o).hide(),p.fadeOut("fast",function(){s.fadeIn("fast",function(){s.removeClass("file-thumb-loading")}),p.remove()})):s.html(o),c=m.previewZoomSettings[n],c&&(d=s.find(".kv-preview-data"),t.addCss(d,"file-zoom-detail"),e.each(c,function(e,t){d.css(e,t),(d.attr("width")&&"width"===e||d.attr("height")&&"height"===e)&&d.removeAttr(e)})),g.data("previewId",v);var x=s.find("img");x.length&&t.adjustOrientedImage(x,!0),m._handler(h,"click",function(){m._zoomSlideShow("prev",v)}),m._handler(w,"click",function(){m._zoomSlideShow("next",v)}),m._handler(_,"click",function(){m._resizeZoomDialog(!0)}),m._handler(b,"click",function(){m._resizeZoomDialog(!1)}),m._handler(C,"click",function(){var e,t=g.find(".modal-header"),i=g.find(".modal-body .floating-buttons"),a=t.find(".kv-zoom-actions"),r=function(e){var i=m.$modal.find(".kv-zoom-body"),a=m.zoomModalHeight;g.hasClass("file-zoom-fullscreen")&&(a=i.outerHeight(!0),e||(a-=t.outerHeight(!0))),i.css("height",e?a+e:a)};t.is(":visible")?(e=t.outerHeight(!0),t.slideUp("slow",function(){a.find(".btn").appendTo(i),r(e)})):(i.find(".btn").appendTo(a),t.slideDown("slow",function(){r()})),g.focus()}),m._handler(g,"keydown",function(e){var t=e.which||e.keyCode;37!==t||h.attr("disabled")||m._zoomSlideShow("prev",v),39!==t||w.attr("disabled")||m._zoomSlideShow("next",v)})},_zoomPreview:function(e){var i,a=this,r=a.$modal;if(!e.length)throw"Cannot zoom to detailed preview!";t.initModal(r),r.html(a._getModalContent()),i=e.closest(t.FRAMES),a._setZoomContent(i),r.modal("show"),a._initZoomButtons()},_zoomSlideShow:function(t,i){var a,r,n,o=this,l=o.$modal.find(".kv-zoom-actions .btn-"+t),s=o.getFrames().toArray(),d=s.length;if(!l.attr("disabled")){for(r=0;d>r;r++)if(e(s[r]).attr("id")===i){n="prev"===t?r-1:r+1;break}0>n||n>=d||!s[n]||(a=e(s[n]),a.length&&o._setZoomContent(a,!0),o._initZoomButtons(),o._raise("filezoom"+t,{previewId:i,modal:o.$modal}))}},_initZoomButton:function(){var t=this;t.$preview.find(".kv-file-zoom").each(function(){var i=e(this);t._handler(i,"click",function(){t._zoomPreview(i)})})},_inputFileCount:function(){return this.$element.get(0).files.length},_refreshPreview:function(){var e,t=this;t._inputFileCount()&&t.showPreview&&t.isPreviewable&&(t.isAjaxUpload?(e=t.getFileStack(),t.filestack=[],e.length?t._clearFileInput():e=t.$element.get(0).files):e=t.$element.get(0).files,e&&e.length&&(t.readFiles(e),t._setFileDropZoneTitle()))},_clearObjects:function(t){t.find("video audio").each(function(){this.pause(),e(this).remove()}),t.find("img object div").each(function(){e(this).remove()})},_clearFileInput:function(){var t,i,a,r=this,n=r.$element;r._inputFileCount()&&(t=n.closest("form"),i=e(document.createElement("form")),a=e(document.createElement("div")),n.before(a),t.length?t.after(i):a.after(i),i.append(n).trigger("reset"),a.before(n).remove(),i.remove())},_resetUpload:function(){var e=this;e.uploadCache={content:[],config:[],tags:[],append:!0},e.uploadCount=0,e.uploadStatus={},e.uploadLog=[],e.uploadAsyncCount=0,e.loadedImages=[],e.totalImagesCount=0,e.$btnUpload.removeAttr("disabled"),e._setProgress(0),e.$progress.hide(),e._resetErrors(!1),e.ajaxAborted=!1,e.ajaxRequests=[],e._resetCanvas(),e.cacheInitialPreview={},e.overwriteInitial&&(e.initialPreview=[],e.initialPreviewConfig=[],e.initialPreviewThumbTags=[],e.previewCache.data={content:[],config:[],tags:[]})},_resetCanvas:function(){var e=this;e.canvas&&e.imageCanvasContext&&e.imageCanvasContext.clearRect(0,0,e.canvas.width,e.canvas.height)},_hasInitialPreview:function(){var e=this;return!e.overwriteInitial&&e.previewCache.count()},_resetPreview:function(){var e,t,i=this;i.previewCache.count()?(e=i.previewCache.out(),i._setPreviewContent(e.content),i._setInitThumbAttr(),t=i.initialCaption?i.initialCaption:e.caption,i._setCaption(t)):(i._clearPreview(),i._initCaption()),i.showPreview&&(i._initZoom(),i._initSortable())},_clearDefaultPreview:function(){var e=this;e.$preview.find(".file-default-preview").remove()},_validateDefaultPreview:function(){var e=this;e.showPreview&&!t.isEmpty(e.defaultPreviewContent)&&(e._setPreviewContent(''+e.defaultPreviewContent+""),e.$container.removeClass("file-input-new"),e._initClickable())},_resetPreviewThumbs:function(e){var t,i=this;return e?(i._clearPreview(),void i.clearStack()):void(i._hasInitialPreview()?(t=i.previewCache.out(),i._setPreviewContent(t.content),i._setInitThumbAttr(),i._setCaption(t.caption),i._initPreviewActions()):i._clearPreview())},_getLayoutTemplate:function(e){var i=this,a=i.layoutTemplates[e];return t.isEmpty(i.customLayoutTags)?a:t.replaceTags(a,i.customLayoutTags)},_getPreviewTemplate:function(e){var i=this,a=i.previewTemplates[e];return t.isEmpty(i.customPreviewTags)?a:t.replaceTags(a,i.customPreviewTags)},_getOutData:function(e,t,i){var a=this;return e=e||{},t=t||{},i=i||a.filestack.slice(0)||{},{form:a.formdata,files:i,filenames:a.filenames,filescount:a.getFilesCount(),extra:a._getExtraData(),response:t,reader:a.reader,jqXHR:e}},_getMsgSelected:function(e){var t=this,i=1===e?t.fileSingle:t.filePlural;return e>0?t.msgSelected.replace("{n}",e).replace("{files}",i):t.msgNoFilesSelected},_getFrame:function(t){var i=this,a=e("#"+t);return a.length?a:(i._log('Invalid thumb frame with id: "'+t+'".'),null)},_getThumbs:function(e){return e=e||"",this.getFrames(":not(.file-preview-initial)"+e)},_getExtraData:function(e,t){var i=this,a=i.uploadExtraData;return"function"==typeof i.uploadExtraData&&(a=i.uploadExtraData(e,t)),a},_initXhr:function(e,t,i){var a=this;return e.upload&&e.upload.addEventListener("progress",function(e){var r=0,n=e.total,o=e.loaded||e.position;e.lengthComputable&&(r=Math.floor(o/n*100)),t?a._setAsyncUploadStatus(t,r,i):a._setProgress(r)},!1),e},_initAjaxSettings:function(){var t=this;t._ajaxSettings=e.extend(!0,{},t.ajaxSettings),t._ajaxDeleteSettings=e.extend(!0,{},t.ajaxDeleteSettings)},_mergeAjaxCallback:function(e,t,i){var a,r=this,n=r._ajaxSettings,o=r.mergeAjaxCallbacks;"delete"===i&&(n=r._ajaxDeleteSettings,o=r.mergeAjaxDeleteCallbacks),a=n[e],o&&"function"==typeof a?"before"===o?n[e]=function(){a.apply(this,arguments),t.apply(this,arguments)}:n[e]=function(){t.apply(this,arguments),a.apply(this,arguments)}:n[e]=t},_ajaxSubmit:function(t,i,a,r,n,o){var l,s=this;s._raise("filepreajax",[n,o])&&(s._uploadExtra(n,o),s._initAjaxSettings(),s._mergeAjaxCallback("beforeSend",t),s._mergeAjaxCallback("success",i),s._mergeAjaxCallback("complete",a),s._mergeAjaxCallback("error",r),l=e.extend(!0,{},{xhr:function(){var t=e.ajaxSettings.xhr();return s._initXhr(t,n,s.getFileStack().length)},url:o&&s.uploadUrlThumb?s.uploadUrlThumb:s.uploadUrl,type:"POST",dataType:"json",data:s.formdata,cache:!1,processData:!1,contentType:!1},s._ajaxSettings),s.ajaxRequests.push(e.ajax(l)))},_mergeArray:function(e,i){var a=this,r=t.cleanArray(a[e]),n=t.cleanArray(i);a[e]=r.concat(n)},_initUploadSuccess:function(i,a,r){var n,o,l,s,d,c,p,u,f,m=this;m.showPreview&&"object"==typeof i&&!e.isEmptyObject(i)&&void 0!==i.initialPreview&&i.initialPreview.length>0&&(m.hasInitData=!0,c=i.initialPreview||[],p=i.initialPreviewConfig||[],u=i.initialPreviewThumbTags||[],n=void 0===i.append||i.append,c.length>0&&!t.isArray(c)&&(c=c.split(m.initialPreviewDelimiter)),m._mergeArray("initialPreview",c),m._mergeArray("initialPreviewConfig",p),m._mergeArray("initialPreviewThumbTags",u),void 0!==a?r?(f=a.attr("data-fileindex"),m.uploadCache.content[f]=c[0],m.uploadCache.config[f]=p[0]||[],m.uploadCache.tags[f]=u[0]||[],m.uploadCache.append=n):(l=m.previewCache.add(c,p[0],u[0],n),o=m.previewCache.get(l,!1),s=e(document.createElement("div")).html(o).hide().insertAfter(a),d=s.find(".kv-zoom-cache"),d&&d.length&&d.insertAfter(a),a.fadeOut("slow",function(){var e=s.find(".file-preview-frame");e&&e.length&&e.insertBefore(a).fadeIn("slow").css("display:inline-block"),m._initPreviewActions(),m._clearFileInput(),t.cleanZoomCache(m.$preview.find("#zoom-"+a.attr("id"))),a.remove(),s.remove(),m._initSortable()})):(m.previewCache.set(c,p,u,n),m._initPreview(),m._initPreviewActions()))},_initSuccessThumbs:function(){var i=this;i.showPreview&&i._getThumbs(t.FRAMES+".file-preview-success").each(function(){var a=e(this),r=i.$preview,n=a.find(".kv-file-remove");n.removeAttr("disabled"),i._handler(n,"click",function(){var e=a.attr("id"),n=i._raise("filesuccessremove",[e,a.attr("data-fileindex")]);t.cleanMemory(a),n!==!1&&a.fadeOut("slow",function(){t.cleanZoomCache(r.find("#zoom-"+e)),a.remove(),i.getFrames().length||i.reset()})})})},_checkAsyncComplete:function(){var t,i,a=this;for(i=0;i0||!e.isEmptyObject(v.uploadExtraData),b=e("#"+w).find(".file-thumb-progress"),C={id:w,index:i};v.formdata=h,v.showPreview&&(n=e("#"+w+":not(.file-preview-initial)"),l=n.find(".kv-file-upload"),s=n.find(".kv-file-remove"),b.show()),0===g||!_||l&&l.hasClass("disabled")||v._abort(C)||(m=function(e,t){d||v.updateStack(e,void 0),v.uploadLog.push(t),v._checkAsyncComplete()&&(v.fileBatchCompleted=!0)},o=function(){var e,i,a,r=v.uploadCache,n=0,o=v.cacheInitialPreview;v.fileBatchCompleted&&(o&&o.content&&(n=o.content.length),setTimeout(function(){var l=0===v.getFileStack(!0).length;if(v.showPreview){if(v.previewCache.set(r.content,r.config,r.tags,r.append),n){for(i=0;i0||!e.isEmptyObject(l.uploadExtraData);l.formdata=new FormData,0!==d&&p&&!l._abort(c)&&(o=function(){e.each(s,function(e){l.updateStack(e,void 0)}),l._clearFileInput()},i=function(i){l.lock();var a=l._getOutData(i);l.ajaxAborted=!1,l.showPreview&&l._getThumbs().each(function(){var i=e(this),a=i.find(".kv-file-upload"),r=i.find(".kv-file-remove");i.hasClass("file-preview-success")||(l._setThumbStatus(i,"Loading"),t.addCss(i,"file-uploading")),a.attr("disabled",!0),r.attr("disabled",!0)}),l._raise("filebatchpreupload",[a]),l._abort(a)&&(i.abort(),l._getThumbs().each(function(){var t=e(this),i=t.find(".kv-file-upload"),a=t.find(".kv-file-remove");t.hasClass("file-preview-loading")&&(l._setThumbStatus(t,"New"),t.removeClass("file-uploading")),i.removeAttr("disabled"),a.removeAttr("disabled")}),l._setProgressCancelled())},a=function(i,a,r){var n=l._getOutData(r,i),s=0,d=l._getThumbs(":not(.file-preview-success)"),c=t.isEmpty(i)||t.isEmpty(i.errorkeys)?[]:i.errorkeys;t.isEmpty(i)||t.isEmpty(i.error)?(l._raise("filebatchuploadsuccess",[n]),o(),l.showPreview?(d.each(function(){var t=e(this);l._setThumbStatus(t,"Success"),t.removeClass("file-uploading"),t.find(".kv-file-upload").hide().removeAttr("disabled")}),l._initUploadSuccess(i)):l.reset(),l._setProgress(101)):(l.showPreview&&(d.each(function(){var t=e(this),i=t.attr("data-fileindex");t.removeClass("file-uploading"),t.find(".kv-file-upload").removeAttr("disabled"),t.find(".kv-file-remove").removeAttr("disabled"),0===c.length||-1!==e.inArray(s,c)?(l._setPreviewError(t,i,l.filestack[i],l.retryErrorUploads),l.retryErrorUploads||(t.find(".kv-file-upload").hide(),l.updateStack(i,void 0))):(t.find(".kv-file-upload").hide(),l._setThumbStatus(t,"Success"),l.updateStack(i,void 0)),t.hasClass("file-preview-error")&&!l.retryErrorUploads||s++}),l._initUploadSuccess(i)),l._showUploadError(i.error,n,"filebatchuploaderror"),l._setProgress(101,l.$progress,l.msgUploadError))},n=function(){l.unlock(),l._initSuccessThumbs(),l._clearFileInput(),l._raise("filebatchuploadcomplete",[l.filestack,l._getExtraData()])},r=function(t,i,a){var r=l._getOutData(t),n=l.ajaxOperations.uploadBatch,o=l._parseError(n,t,a);l._showUploadError(o,r,"filebatchuploaderror"),l.uploadFileCount=d-1,l.showPreview&&(l._getThumbs().each(function(){var t=e(this),i=t.attr("data-fileindex");t.removeClass("file-uploading"),void 0!==l.filestack[i]&&l._setPreviewError(t)}),l._getThumbs().removeClass("file-uploading"),l._getThumbs(" .kv-file-upload").removeAttr("disabled"),l._getThumbs(" .kv-file-delete").removeAttr("disabled"),l._setProgress(101,l.$progress,l.msgAjaxProgressError.replace("{operation}",n)))},e.each(s,function(e,i){t.isEmpty(s[e])||l.formdata.append(l.uploadFileAttr,i,l.filenames[e])}),l._ajaxSubmit(i,a,n,r))},_uploadExtraOnly:function(){var e,i,a,r,n=this,o={};n.formdata=new FormData,n._abort(o)||(e=function(e){n.lock();var t=n._getOutData(e);n._raise("filebatchpreupload",[t]),n._setProgress(50),o.data=t,o.xhr=e,n._abort(o)&&(e.abort(),n._setProgressCancelled())},i=function(e,i,a){var r=n._getOutData(a,e);t.isEmpty(e)||t.isEmpty(e.error)?(n._raise("filebatchuploadsuccess",[r]),n._clearFileInput(),n._initUploadSuccess(e),n._setProgress(101)):n._showUploadError(e.error,r,"filebatchuploaderror")},a=function(){n.unlock(),n._clearFileInput(),n._raise("filebatchuploadcomplete",[n.filestack,n._getExtraData()])},r=function(e,t,i){var a=n._getOutData(e),r=n.ajaxOperations.uploadExtra,l=n._parseError(r,e,i);o.data=a,n._showUploadError(l,a,"filebatchuploaderror"),n._setProgress(101,n.$progress,n.msgAjaxProgressError.replace("{operation}",r))},n._ajaxSubmit(e,i,a,r))},_deleteFileIndex:function(i){var a=this,r=i.attr("data-fileindex"),n=a.reversePreviewOrder;"init_"===r.substring(0,5)&&(r=parseInt(r.replace("init_","")),a.initialPreview=t.spliceArray(a.initialPreview,r,n),a.initialPreviewConfig=t.spliceArray(a.initialPreviewConfig,r,n),a.initialPreviewThumbTags=t.spliceArray(a.initialPreviewThumbTags,r,n),a.getFrames().each(function(){var t=e(this),i=t.attr("data-fileindex");"init_"===i.substring(0,5)&&(i=parseInt(i.replace("init_","")),i>r&&(i--,t.attr("data-fileindex","init_"+i)))}),a.uploadAsync&&(a.cacheInitialPreview=a.getPreview()))},_initFileActions:function(){var i=this,a=i.$preview;i.showPreview&&(i._initZoomButton(),i.getFrames(" .kv-file-remove").each(function(){var r,n,o,l,s=e(this),d=s.closest(t.FRAMES),c=d.attr("id"),p=d.attr("data-fileindex");i._handler(s,"click",function(){return l=i._raise("filepreremove",[c,p]),l!==!1&&i._validateMinCount()?(r=d.hasClass("file-preview-error"),t.cleanMemory(d),void d.fadeOut("slow",function(){t.cleanZoomCache(a.find("#zoom-"+c)),i.updateStack(p,void 0),i._clearObjects(d),d.remove(),c&&r&&i.$errorContainer.find('li[data-file-id="'+c+'"]').fadeOut("fast",function(){e(this).remove(),i._errorsExist()||i._resetErrors()}),i._clearFileInput();var l=i.getFileStack(!0),s=i.previewCache.count(),u=l.length,f=i.showPreview&&i.getFrames().length;0!==u||0!==s||f?(n=s+u,o=n>1?i._getMsgSelected(n):l[0]?i._getFileNames()[0]:"",i._setCaption(o)):i.reset(),i._raise("fileremoved",[c,p])})):!1})}),i.getFrames(" .kv-file-upload").each(function(){var a=e(this);i._handler(a,"click",function(){var e=a.closest(t.FRAMES),r=e.attr("data-fileindex");i.$progress.hide(),e.hasClass("file-preview-error")&&!i.retryErrorUploads||i._uploadSingle(r,!1)})}))},_initPreviewActions:function(){var i=this,a=i.$preview,r=i.deleteExtraData||{},n=t.FRAMES+" .kv-file-remove",o=i.fileActionSettings,l=o.removeClass,s=o.removeErrorClass,d=function(){var e=i.isAjaxUpload?i.previewCache.count():i._inputFileCount();a.find(t.FRAMES).length||e||(i._setCaption(""),i.reset(),i.initialCaption="")};i._initZoomButton(),a.find(n).each(function(){var n,o,c,p=e(this),u=p.data("url")||i.deleteUrl,f=p.data("key");if(!t.isEmpty(u)&&void 0!==f){var m,v,g,h,w=p.closest(t.FRAMES),_=i.previewCache.data,b=w.attr("data-fileindex");b=parseInt(b.replace("init_","")),g=t.isEmpty(_.config)&&t.isEmpty(_.config[b])?null:_.config[b],h=t.isEmpty(g)||t.isEmpty(g.extra)?r:g.extra,"function"==typeof h&&(h=h()),v={id:p.attr("id"),key:f,extra:h},n=function(e){i.ajaxAborted=!1,i._raise("filepredelete",[f,e,h]),i._abort()?e.abort():(p.removeClass(s),t.addCss(w,"file-uploading"),t.addCss(p,"disabled "+l))},o=function(e,r,n){var o,c;return t.isEmpty(e)||t.isEmpty(e.error)?(w.removeClass("file-uploading").addClass("file-deleted"),void w.fadeOut("slow",function(){b=parseInt(w.attr("data-fileindex").replace("init_","")),i.previewCache.unset(b),i._deleteFileIndex(w),o=i.previewCache.count(),c=o>0?i._getMsgSelected(o):"",i._setCaption(c),i._raise("filedeleted",[f,n,h]),t.cleanZoomCache(a.find("#zoom-"+w.attr("id"))),i._clearObjects(w),w.remove(),d()})):(v.jqXHR=n,v.response=e,i._showError(e.error,v,"filedeleteerror"),w.removeClass("file-uploading"),p.removeClass("disabled "+l).addClass(s),void d())},c=function(e,t,a){var r=i.ajaxOperations.deleteThumb,n=i._parseError(r,e,a);v.jqXHR=e,v.response={},i._showError(n,v,"filedeleteerror"),w.removeClass("file-uploading"),p.removeClass("disabled "+l).addClass(s),d()},i._initAjaxSettings(),i._mergeAjaxCallback("beforeSend",n,"delete"),i._mergeAjaxCallback("success",o,"delete"),i._mergeAjaxCallback("error",c,"delete"),m=e.extend(!0,{},{url:u,type:"POST",dataType:"json",data:e.extend(!0,{},{key:f},h)},i._ajaxDeleteSettings),i._handler(p,"click",function(){return i._validateMinCount()?(i.ajaxAborted=!1,i._raise("filebeforedelete",[f,h]),void(i.ajaxAborted instanceof Promise?i.ajaxAborted.then(function(t){t||e.ajax(m)}):i.ajaxAborted||e.ajax(m))):!1})}})},_hideFileIcon:function(){var e=this;e.overwriteInitial&&e.$captionContainer.removeClass("icon-visible")},_showFileIcon:function(){var e=this;t.addCss(e.$captionContainer,"icon-visible")},_getSize:function(t){var i,a,r,n=this,o=parseFloat(t),l=n.fileSizeGetter;return e.isNumeric(t)&&e.isNumeric(o)?("function"==typeof l?r=l(o):0===o?r="0.00 B":(i=Math.floor(Math.log(o)/Math.log(1024)),a=["B","KB","MB","GB","TB","PB","EB","ZB","YB"],r=1*(o/Math.pow(1024,i)).toFixed(2)+" "+a[i]),n._getLayoutTemplate("size").replace("{sizeText}",r)):""},_generatePreviewTemplate:function(i,a,r,n,o,l,s,d,c,p,u){var f,m,v=this,g=v.slug(r),h="",w="",_=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth,b=400>_?v.previewSettingsSmall[i]||v.defaults.previewSettingsSmall[i]:v.previewSettings[i]||v.defaults.previewSettings[i],C=c||v._renderFileFooter(g,s,"auto",l),y=v._getPreviewIcon(r),x="type-default",T=y&&v.preferIconicPreview,E=y&&v.preferIconicZoomPreview;return b&&e.each(b,function(e,t){w+=e+":"+t+";"}),m=function(a,l,s,c){var f=s?"zoom-"+o:o,m=v._getPreviewTemplate(a),h=(d||"")+" "+c;return v.frameClass&&(h=v.frameClass+" "+h),s&&(h=h.replace(" "+t.SORT_CSS,"")),m=v._parseFilePreviewIcon(m,r),"text"===a&&(l=t.htmlEncode(l)),"object"!==i||n||e.each(v.defaults.fileTypeSettings,function(e,t){"object"!==e&&"other"!==e&&t(r,n)&&(x="type-"+e)}),m.setTokens({previewId:f,caption:g,frameClass:h,type:n,fileindex:p,typeCss:x,footer:C,data:l,template:u||i,style:w?'style="'+w+'"':""})},p=p||o.slice(o.lastIndexOf("-")+1),v.fileActionSettings.showZoom&&(h=m(E?"other":i,a,!0,"kv-zoom-thumb")),h="\n"+v._getLayoutTemplate("zoomCache").replace("{zoomContent}",h),f=m(T?"other":i,a,!1,"kv-preview-thumb"),f+h},_addToPreview:function(e,t){var i=this;return i.reversePreviewOrder?e.prepend(t):e.append(t)},_previewDefault:function(i,a,r){var n=this,o=n.$preview;if(n.showPreview){var l,s=i?i.name:"",d=i?i.type:"",c=i.size||0,p=n.slug(s),u=r===!0&&!n.isAjaxUpload,f=t.objUrl.createObjectURL(i);n._clearDefaultPreview(),l=n._generatePreviewTemplate("other",f,s,d,a,u,c),n._addToPreview(o,l),n._setThumbAttr(a,p,c),r===!0&&n.isAjaxUpload&&n._setThumbStatus(e("#"+a),"Error")}},_previewFile:function(e,i,a,r,n,o){if(this.showPreview){var l,s=this,d=i?i.name:"",c=o.type,p=o.name,u=s._parseFileType(c,d),f=s.allowedPreviewTypes,m=s.allowedPreviewMimeTypes,v=s.$preview,g=i.size||0,h=f&&f.indexOf(u)>=0,w=m&&-1!==m.indexOf(c),_="text"===u||"html"===u||"image"===u?a.target.result:n;if("html"===u&&s.purifyHtml&&window.DOMPurify&&(_=window.DOMPurify.sanitize(_)),h||w){l=s._generatePreviewTemplate(u,_,d,c,r,!1,g),s._clearDefaultPreview(),s._addToPreview(v,l);var b=v.find("#"+r+" img");b.length&&s.autoOrientImage?t.validateOrientation(i,function(e){if(!e)return void s._validateImage(r,p,c,g,_);var a=v.find("#zoom-"+r+" img"),n="rotate-"+e;e>4&&(n+=b.width()>b.height()?" is-portrait-gt4":" is-landscape-gt4"),t.addCss(b,n),t.addCss(a,n),s._raise("fileimageoriented",{$img:b,file:i}),s._validateImage(r,p,c,g,_),t.adjustOrientedImage(b)}):s._validateImage(r,p,c,g,_)}else s._previewDefault(i,r);s._setThumbAttr(r,p,g),s._initSortable()}},_setThumbAttr:function(t,i,a){var r=this,n=e("#"+t);n.length&&(a=a&&a>0?r._getSize(a):"",n.data({caption:i,size:a}))},_setInitThumbAttr:function(){var e,i,a,r,n=this,o=n.previewCache.data,l=n.previewCache.count();if(0!==l)for(var s=0;l>s;s++)e=o.config[s],r=n.previewInitId+"-init_"+s,i=t.ifSet("caption",e,t.ifSet("filename",e)),a=t.ifSet("size",e),n._setThumbAttr(r,i,a)},_slugDefault:function(e){return t.isEmpty(e)?"":String(e).replace(/[\[\]\/\{}:;#%=\(\)\*\+\?\\\^\$\|<>&"']/g,"_")},_updateFileDetails:function(e){var i=this,a=i.$element,r=i.getFileStack(),n=t.isIE(9)&&t.findFileName(a.val())||a[0].files[0]&&a[0].files[0].name||r.length&&r[0].name||"",o=i.slug(n),l=i.isAjaxUpload?r.length:e,s=i.previewCache.count()+l,d=1===l?o:i._getMsgSelected(s);i.isError?(i.$previewContainer.removeClass("file-thumb-loading"),i.$previewStatus.html(""),i.$captionContainer.removeClass("icon-visible")):i._showFileIcon(),i._setCaption(d,i.isError),i.$container.removeClass("file-input-new file-input-ajax-new"),1===arguments.length&&i._raise("fileselect",[e,o]),i.previewCache.count()&&i._initPreviewActions()},_setThumbStatus:function(e,t){var i=this;if(i.showPreview){var a="indicator"+t,r=a+"Title",n="file-preview-"+t.toLowerCase(),o=e.find(".file-upload-indicator"),l=i.fileActionSettings;e.removeClass("file-preview-success file-preview-error file-preview-loading"),"Success"===t&&e.find(".file-drag-handle").remove(),o.html(l[a]),o.attr("title",l[r]),e.addClass(n),"Error"!==t||i.retryErrorUploads||e.find(".kv-file-upload").attr("disabled",!0)}},_setProgressCancelled:function(){var e=this;e._setProgress(101,e.$progress,e.msgCancelled)},_setProgress:function(e,i,a){var r,n=this,o=Math.min(e,100),l=n.progressUploadThreshold,s=100>=e?n.progressTemplate:n.progressCompleteTemplate,d=100>o?n.progressTemplate:a?n.progressErrorTemplate:s; +i=i||n.$progress,t.isEmpty(d)||(r=l&&o>l&&100>=e?d.setTokens({percent:l,status:n.msgUploadThreshold}):d.setTokens({percent:o,status:e>100?n.msgUploadEnd:o+"%"}),i.html(r),a&&i.find('[role="progressbar"]').html(a))},_setFileDropZoneTitle:function(){var e,i=this,a=i.$container.find(".file-drop-zone"),r=i.dropZoneTitle;i.isClickable&&(e=t.isEmpty(i.$element.attr("multiple"))?i.fileSingle:i.filePlural,r+=i.dropZoneClickTitle.replace("{files}",e)),a.find("."+i.dropZoneTitleClass).remove(),!i.showPreview||0===a.length||i.getFileStack().length>0||!i.dropZoneEnabled||!i.isAjaxUpload&&i.$element.files||(0===a.find(t.FRAMES).length&&t.isEmpty(i.defaultPreviewContent)&&a.prepend(''+r+""),i.$container.removeClass("file-input-new"),t.addCss(i.$container,"file-input-ajax-new"))},_setAsyncUploadStatus:function(t,i,a){var r=this,n=0;r._setProgress(i,e("#"+t).find(".file-thumb-progress")),r.uploadStatus[t]=i,e.each(r.uploadStatus,function(e,t){n+=t}),r._setProgress(Math.floor(n/a))},_validateMinCount:function(){var e=this,t=e.isAjaxUpload?e.getFileStack().length:e._inputFileCount();return e.validateInitialCount&&e.minFileCount>0&&e._getFileCount(t-1)=m:m>=d,p||(s=u["msgImage"+o+i].setTokens({name:n,size:m}),u._showUploadError(s,l),u._setPreviewError(r,e,null)))},_validateImage:function(t,i,a,r,n){var o,l,s,d,c=this,p=c.$preview,u=p.find("#"+t),f=u.attr("data-fileindex"),m=u.find("img");i=i||"Untitled",m.one("load",function(){l=u.width(),s=p.width(),l>s&&m.css("width","100%"),o={ind:f,id:t},c._checkDimensions(f,"Small",m,u,i,"Width",o),c._checkDimensions(f,"Small",m,u,i,"Height",o),c.resizeImage||(c._checkDimensions(f,"Large",m,u,i,"Width",o),c._checkDimensions(f,"Large",m,u,i,"Height",o)),c._raise("fileimageloaded",[t]);try{d=window.piexif?window.piexif.load(n):null}catch(e){d=null}c.loadedImages.push({ind:f,img:m,thumb:u,pid:t,typ:a,siz:r,validated:!1,imgData:n,exifObj:d}),u.data("exif",d),c._validateAllImages()}).one("error",function(){c._raise("fileimageloaderror",[t])}).each(function(){this.complete?e(this).trigger("load"):this.error&&e(this).trigger("error")})},_validateAllImages:function(){var e,t,i,a=this,r={val:0},n=a.loadedImages.length,o=a.resizeIfSizeMoreThan;if(n===a.totalImagesCount&&(a._raise("fileimagesloaded"),a.resizeImage))for(e=0;e1e3*o&&a._getResizedImage(t,r,n),a.loadedImages[e].validated=!0)},_getResizedImage:function(i,a,r){var n,o,l,s,d,c,p,u=this,f=e(i.img)[0],m=f.naturalWidth,v=f.naturalHeight,g=1,h=u.maxImageWidth||m,w=u.maxImageHeight||v,_=!(!m||!v),b=u.imageCanvas,C=u.imageCanvasContext,y=i.typ,x=i.pid,T=i.ind,E=i.thumb,S=i.exifObj;if(d=function(e,t,i){u.isAjaxUpload?u._showUploadError(e,t,i):u._showError(e,t,i),u._setPreviewError(E,T)},(!u.filestack[T]||!_||h>=m&&w>=v)&&(_&&u.filestack[T]&&u._raise("fileimageresized",[x,T]),a.val++,a.val===r&&u._raise("fileimagesresized"),!_))return void d(u.msgImageResizeError,{id:x,index:T},"fileimageresizeerror");y=y||u.resizeDefaultImageType,o=m>h,l=v>w,g="width"===u.resizePreference?o?h/m:l?w/v:1:l?w/v:o?h/m:1,u._resetCanvas(),m*=g,v*=g,b.width=m,b.height=v;try{C.drawImage(f,0,0,m,v),s=b.toDataURL(y,u.resizeQuality),S&&(p=window.piexif.dump(S),s=window.piexif.insert(p,s)),n=t.dataURI2Blob(s),u.filestack[T]=n,u._raise("fileimageresized",[x,T]),a.val++,a.val===r&&u._raise("fileimagesresized",[void 0,void 0]),n instanceof Blob||d(u.msgImageResizeError,{id:x,index:T},"fileimageresizeerror")}catch(k){a.val++,a.val===r&&u._raise("fileimagesresized",[void 0,void 0]),c=u.msgImageResizeException.replace("{errors}",k.message),d(c,{id:x,index:T},"fileimageresizeexception")}},_initBrowse:function(e){var i=this,a=i.$element;i.showBrowse?i.$btnFile=e.find(".btn-file").append(a):(a.appendTo(e).attr("tabindex",-1),t.addCss(a,"file-no-browse"))},_initClickable:function(){var i,a=this;a.isClickable&&(i=a.isAjaxUpload?a.$dropZone:a.$preview.find(".file-default-preview"),t.addCss(i,"clickable"),i.attr("tabindex",-1),a._handler(i,"click",function(t){var r=e(t.target);a.$element;e(a.elErrorContainer+":visible").length||r.parents(".file-preview-thumbnails").length&&!r.parents(".file-default-preview").length||(a.$element.data("zoneClicked",!0).trigger("click"),i.blur())}))},_initCaption:function(){var e=this,i=e.initialCaption||"";return e.overwriteInitial||t.isEmpty(i)?(e.$caption.val(""),!1):(e._setCaption(i),!0)},_setCaption:function(i,a){var r,n,o,l,s,d=this,c=d.getFileStack();if(d.$caption.length){if(d.$captionContainer.removeClass("icon-visible"),a)r=e(""+d.msgValidationError+"").text(),l=c.length,s=l?1===l&&c[0]?d._getFileNames()[0]:d._getMsgSelected(l):d._getMsgSelected(d.msgNo),n=t.isEmpty(i)?s:i,o=''+d.msgValidationErrorIcon+"";else{if(t.isEmpty(i))return;r=e(""+i+"").text(),n=r,o=d._getLayoutTemplate("fileIcon")}d.$captionContainer.addClass("icon-visible"),d.$caption.attr("title",r).val(n),d.$captionIcon.html(o)}},_createContainer:function(){var t=this,i={"class":"file-input file-input-new"+(t.rtl?" kv-rtl":"")},a=e(document.createElement("div")).attr(i).html(t._renderMain());return a.insertBefore(t.$element),t._initBrowse(a),t.theme&&a.addClass("theme-"+t.theme),a},_refreshContainer:function(){var e=this,t=e.$container,i=e.$element;i.insertAfter(t),t.html(e._renderMain()),e._initBrowse(t),e._validateDisabled()},_validateDisabled:function(){var e=this;e.$caption.attr({readonly:e.isDisabled})},_renderMain:function(){var e=this,t=e.dropZoneEnabled?" file-drop-zone":"file-drop-disabled",i=e.showClose?e._getLayoutTemplate("close"):"",a=e.showPreview?e._getLayoutTemplate("preview").setTokens({"class":e.previewClass,dropClass:t}):"",r=e.isDisabled?e.captionClass+" file-caption-disabled":e.captionClass,n=e.captionTemplate.setTokens({"class":r+" kv-fileinput-caption"});return e.mainTemplate.setTokens({"class":e.mainClass+(!e.showBrowse&&e.showCaption?" no-browse":""),preview:a,close:i,caption:n,upload:e._renderButton("upload"),remove:e._renderButton("remove"),cancel:e._renderButton("cancel"),browse:e._renderButton("browse")})},_renderButton:function(e){var i=this,a=i._getLayoutTemplate("btnDefault"),r=i[e+"Class"],n=i[e+"Title"],o=i[e+"Icon"],l=i[e+"Label"],s=i.isDisabled?" disabled":"",d="button";switch(e){case"remove":if(!i.showRemove)return"";break;case"cancel":if(!i.showCancel)return"";r+=" kv-hidden";break;case"upload":if(!i.showUpload)return"";i.isAjaxUpload&&!i.isDisabled?a=i._getLayoutTemplate("btnLink").replace("{href}",i.uploadUrl):d="submit";break;case"browse":if(!i.showBrowse)return"";a=i._getLayoutTemplate("btnBrowse");break;default:return""}return r+="browse"===e?" btn-file":" fileinput-"+e+" fileinput-"+e+"-button",t.isEmpty(l)||(l=' '+l+""),a.setTokens({type:d,css:r,title:n,status:s,icon:o,label:l})},_renderThumbProgress:function(){var e=this;return''+e.progressTemplate.setTokens({percent:"0",status:e.msgUploadBegin})+""},_renderFileFooter:function(e,i,a,r){var n,o=this,l=o.fileActionSettings,s=l.showRemove,d=l.showDrag,c=l.showUpload,p=l.showZoom,u=o._getLayoutTemplate("footer"),f=o._getLayoutTemplate("indicator"),m=r?l.indicatorError:l.indicatorNew,v=r?l.indicatorErrorTitle:l.indicatorNewTitle,g=f.setTokens({indicator:m,indicatorTitle:v});return i=o._getSize(i),n=o.isAjaxUpload?u.setTokens({actions:o._renderFileActions(c,!1,s,p,d,!1,!1,!1),caption:e,size:i,width:a,progress:o._renderThumbProgress(),indicator:g}):u.setTokens({actions:o._renderFileActions(!1,!1,!1,p,d,!1,!1,!1),caption:e,size:i,width:a,progress:"",indicator:g}),n=t.replaceTags(n,o.previewThumbTags)},_renderFileActions:function(e,t,i,a,r,n,o,l,s,d,c){if(!(e||t||i||a||r))return"";var p,u=this,f=o===!1?"":' data-url="'+o+'"',m=l===!1?"":' data-key="'+l+'"',v="",g="",h="",w="",_="",b=u._getLayoutTemplate("actions"),C=u.fileActionSettings,y=u.otherActionButtons.setTokens({dataKey:m,key:l}),x=n?C.removeClass+" disabled":C.removeClass;return i&&(v=u._getLayoutTemplate("actionDelete").setTokens({removeClass:x,removeIcon:C.removeIcon,removeTitle:C.removeTitle,dataUrl:f,dataKey:m,key:l})),e&&(g=u._getLayoutTemplate("actionUpload").setTokens({uploadClass:C.uploadClass,uploadIcon:C.uploadIcon,uploadTitle:C.uploadTitle})),t&&(h=u._getLayoutTemplate("actionDownload").setTokens({downloadClass:C.downloadClass,downloadIcon:C.downloadIcon,downloadTitle:C.downloadTitle,downloadUrl:d||u.initialPreviewDownloadUrl}),h=h.setTokens({filename:c,key:l})),a&&(w=u._getLayoutTemplate("actionZoom").setTokens({zoomClass:C.zoomClass,zoomIcon:C.zoomIcon,zoomTitle:C.zoomTitle})),r&&s&&(p="drag-handle-init "+C.dragClass,_=u._getLayoutTemplate("actionDrag").setTokens({dragClass:p,dragTitle:C.dragTitle,dragIcon:C.dragIcon})),b.setTokens({"delete":v,upload:g,download:h,zoom:w,drag:_,other:y})},_browse:function(e){var t=this;t._raise("filebrowse"),e&&e.isDefaultPrevented()||(t.isError&&!t.isAjaxUpload&&t.clear(),t.$captionContainer.focus())},_filterDuplicate:function(e,t,i){var a=this,r=a._getFileId(e);r&&i&&i.indexOf(r)>-1||(i||(i=[]),t.push(e),i.push(r))},_change:function(i){var a=this;if(!a.changeTriggered){var r,n,o=a.$element,l=arguments.length>1,s=a.isAjaxUpload,d=[],c=l?arguments[1]:o.get(0).files,p=!s&&t.isEmpty(o.attr("multiple"))?1:a.maxFileCount,u=a.filestack.length,f=t.isEmpty(o.attr("multiple")),m=f&&u>0,v=a._getFileIds(),g=function(t,i,r,n){var o=e.extend(!0,{},a._getOutData({},{},c),{id:r,index:n}),l={id:r,index:n,file:i,files:c};return s?a._showUploadError(t,o):a._showError(t,l)},h=function(e,t){var i=a.msgFilesTooMany.replace("{m}",t).replace("{n}",e);a.isError=g(i,null,null,null),a.$captionContainer.removeClass("icon-visible"),a._setCaption("",!0),a.$container.removeClass("file-input-new file-input-ajax-new")};if(a.reader=null,a._resetUpload(),a._hideFileIcon(),a.dropZoneEnabled&&a.$container.find(".file-drop-zone ."+a.dropZoneTitleClass).remove(),s?e.each(c,function(e,t){a._filterDuplicate(t,d,v)}):(c=i.target&&void 0===i.target.files?i.target.value?[{name:i.target.value.replace(/^.+\\/,"")}]:[]:i.target.files||{},d=c),t.isEmpty(d)||0===d.length)return s||a.clear(),void a._raise("fileselectnone");if(a._resetErrors(),n=d.length,r=a._getFileCount(s?a.getFileStack().length+n:n),p>0&&r>p){if(!a.autoReplace||n>p)return void h(a.autoReplace&&n>p?n:r,p);r>p&&a._resetPreviewThumbs(s)}else!s||m?(a._resetPreviewThumbs(!1),m&&a.clearStack()):!s||0!==u||a.previewCache.count()&&!a.overwriteInitial||a._resetPreviewThumbs(!0);a.isPreviewable?a.readFiles(d):a._updateFileDetails(1)}},_abort:function(t){var i,a=this;return a.ajaxAborted&&"object"==typeof a.ajaxAborted&&void 0!==a.ajaxAborted.message?(i=e.extend(!0,{},a._getOutData(),t),i.abortData=a.ajaxAborted.data||{},i.abortMessage=a.ajaxAborted.message,a._setProgress(101,a.$progress,a.msgCancelled),a._showUploadError(a.ajaxAborted.message,i,"filecustomerror"),a.cancel(),!0):!!a.ajaxAborted},_resetFileStack:function(){var i=this,a=0,r=[],n=[],o=[];i._getThumbs().each(function(){var l=e(this),s=l.attr("data-fileindex"),d=i.filestack[s],c=l.attr("id");"-1"!==s&&-1!==s&&(void 0!==d?(r[a]=d,n[a]=i._getFileName(d),o[a]=i._getFileId(d),l.attr({id:i.previewInitId+"-"+a,"data-fileindex":a}),a++):l.attr({id:"uploaded-"+t.uniqId(),"data-fileindex":"-1"}),i.$preview.find("#zoom-"+c).attr({id:"zoom-"+l.attr("id"),"data-fileindex":l.attr("data-fileindex")}))}),i.filestack=r,i.filenames=n,i.fileids=o},_isFileSelectionValid:function(e){var t=this;return e=e||0,t.required&&!t.getFilesCount()?(t.$errorContainer.html(""),t._showUploadError(t.msgFileRequired),!1):t.minFileCount>0&&t._getFileCount(e)=f)return r.isAjaxUpload&&r.filestack.length>0?r._raise("filebatchselected",[r.getFileStack()]):r._raise("filebatchselected",[i]),s.removeClass("file-thumb-loading"),void d.html("");var T,E,S,k,F,P,I,A,D,z,$,j,U=v+x,B=u+"-"+U,O=i[x],R=m.text,L=m.image,Z=m.html,M=O&&O.name?r.slug(O.name):"",N=(O&&O.size||0)/1e3,H="",V=O?t.objUrl.createObjectURL(O):null,W=0,q="",K=0,G=function(){var e=p.setTokens({index:x+1,files:f,percent:50,name:M});setTimeout(function(){d.html(e),r._updateFileDetails(f),a(x+1)},100),r._raise("fileloaded",[O,B,x,l])};if(O){if(h>0)for(E=0;h>E;E++)P=g[E],I=r.msgFileTypes[P]||P,q+=0===E?I:", "+I;if(M===!1)return void a(x+1);if(0===M.length)return S=r.msgInvalidFileName.replace("{name}",t.htmlEncode(O.name)),void y(S,O,B,x);if(t.isEmpty(w)||(H=new RegExp("\\.("+w.join("|")+")$","i")),T=N.toFixed(2),r.maxFileSize>0&&N>r.maxFileSize)return S=r.msgSizeTooLarge.setTokens({name:M,size:T,maxSize:r.maxFileSize}),void y(S,O,B,x);if(null!==r.minFileSize&&N<=t.getNum(r.minFileSize))return S=r.msgSizeTooSmall.setTokens({name:M,size:T,minSize:r.minFileSize}),void y(S,O,B,x);if(!t.isEmpty(g)&&t.isArray(g)){for(E=0;Eb)return r.addToStack(O),s.addClass("file-thumb-loading"),r._previewDefault(O,B),r._initFileActions(),r._updateFileDetails(f),void a(x+1);o.length&&void 0!==FileReader?(D=R(O.type,M),z=Z(O.type,M),$=L(O.type,M),d.html(c.replace("{index}",x+1).replace("{files}",f)),s.addClass("file-thumb-loading"),l.onerror=function(e){r._errorHandler(e,M)},l.onload=function(i){var a,n,o,s,d,c,p=[],u=function(e){var t=new FileReader;t.onerror=function(e){r._errorHandler(e,M)},t.onload=function(e){r._previewFile(x,O,e,B,V,n),r._initFileActions(),G()},e?t.readAsText(O,r.textEncoding):t.readAsDataURL(O)};if(n={name:M,type:O.type},e.each(m,function(e,t){"object"!==e&&"other"!==e&&t(O.type,M)&&K++}),0===K){for(o=new Uint8Array(i.target.result),E=0;E0)for(t=0;r>t;t+=1)i.cancelling=!0,a[t].abort();return i._setProgressCancelled(),i._getThumbs().each(function(){var t=e(this),a=t.attr("data-fileindex");t.removeClass("file-uploading"),void 0!==i.filestack[a]&&(t.find(".kv-file-upload").removeClass("disabled").removeAttr("disabled"),t.find(".kv-file-remove").removeClass("disabled").removeAttr("disabled")),i.unlock()}),i.$element},clear:function(){var i,a=this;if(a._raise("fileclear"))return a.$btnUpload.removeAttr("disabled"),a._getThumbs().find("video,audio,img").each(function(){t.cleanMemory(e(this))}),a._clearFileInput(),a._resetUpload(),a.clearStack(),a._resetErrors(!0),a._hasInitialPreview()?(a._showFileIcon(),a._resetPreview(),a._initPreviewActions(),a.$container.removeClass("file-input-new")):(a._getThumbs().each(function(){a._clearObjects(e(this))}),a.isAjaxUpload&&(a.previewCache.data={}),a.$preview.html(""),i=!a.overwriteInitial&&a.initialCaption.length>0?a.initialCaption:"",a.$caption.attr("title","").val(i),t.addCss(a.$container,"file-input-new"),a._validateDefaultPreview()),0===a.$container.find(t.FRAMES).length&&(a._initCaption()||a.$captionContainer.removeClass("icon-visible")),a._hideFileIcon(),a._raise("filecleared"),a.$captionContainer.focus(),a._setFileDropZoneTitle(),a.$element},reset:function(){var e=this;if(e._raise("filereset"))return e._resetPreview(),e.$container.find(".fileinput-filename").text(""),t.addCss(e.$container,"file-input-new"),(e.getFrames().length||e.dropZoneEnabled)&&e.$container.removeClass("file-input-new"),e.clearStack(),e.formdata={},e._setFileDropZoneTitle(),e.$element},disable:function(){var e=this;return e.isDisabled=!0,e._raise("filedisabled"),e.$element.attr("disabled","disabled"),e.$container.find(".kv-fileinput-caption").addClass("file-caption-disabled"),e.$container.find(".fileinput-remove, .fileinput-upload, .file-preview-frame button").attr("disabled",!0),t.addCss(e.$container.find(".btn-file"),"disabled"),e._initDragDrop(),e.$element},enable:function(){var e=this;return e.isDisabled=!1,e._raise("fileenabled"),e.$element.removeAttr("disabled"),e.$container.find(".kv-fileinput-caption").removeClass("file-caption-disabled"),e.$container.find(".fileinput-remove, .fileinput-upload, .file-preview-frame button").removeAttr("disabled"),e.$container.find(".btn-file").removeClass("disabled"),e._initDragDrop(),e.$element},upload:function(){var i,a,r,n=this,o=n.getFileStack().length,l=!e.isEmptyObject(n._getExtraData());if(n.isAjaxUpload&&!n.isDisabled&&n._isFileSelectionValid(o)){if(n._resetUpload(),0===o&&!l)return void n._showUploadError(n.msgUploadEmpty);if(n.$progress.show(),n.uploadCount=0,n.uploadStatus={},n.uploadLog=[],n.lock(),n._setProgress(2),0===o&&l)return void n._uploadExtraOnly();if(r=n.filestack.length,n.hasInitData=!1,!n.uploadAsync)return n._uploadBatch(),n.$element;for(a=n._getOutData(),n._raise("filebatchpreupload",[a]),n.fileBatchCompleted=!1,n.uploadCache={content:[],config:[],tags:[],append:!0},n.uploadAsyncCount=n.getFileStack().length,i=0;r>i;i++)n.uploadCache.content[i]=null,n.uploadCache.config[i]=null,n.uploadCache.tags[i]=null;for(n.$preview.find(".file-preview-initial").removeClass(t.SORT_CSS),n._initSortable(),n.cacheInitialPreview=n.getPreview(),i=0;r>i;i++)n.filestack[i]&&n._uploadSingle(i,!0)}},destroy:function(){var t=this,i=t.$form,a=t.$container,r=t.$element,n=t.namespace;return e(document).off(n),e(window).off(n),i&&i.length&&i.off(n),t.isAjaxUpload&&t._clearFileInput(),t._cleanup(),t._initPreviewCache(),r.insertBefore(a).off(n).removeData(),a.off().remove(),r},refresh:function(i){var a=this,r=a.$element;return i="object"!=typeof i||t.isEmpty(i)?a.options:e.extend(!0,{},a.options,i),a._init(i,!0),a._listen(),r},zoom:function(e){var i=this,a=i._getFrame(e),r=i.$modal;a&&(t.initModal(r),r.html(i._getModalContent()),i._setZoomContent(a),r.modal("show"),i._initZoomButtons())},getExif:function(e){var t=this,i=t._getFrame(e);return i&&i.data("exif")||null},getFrames:function(i){var a,r=this;return i=i||"",a=r.$preview.find(t.FRAMES+i),r.reversePreviewOrder&&(a=e(a.get().reverse())),a},getPreview:function(){var e=this;return{content:e.initialPreview,config:e.initialPreviewConfig,tags:e.initialPreviewThumbTags}}},e.fn.fileinput=function(a){if(t.hasFileAPISupport()||t.isIE(9)){var r=Array.apply(null,arguments),n=[];switch(r.shift(),this.each(function(){var o,l=e(this),s=l.data("fileinput"),d="object"==typeof a&&a,c=d.theme||l.data("theme"),p={},u={},f=d.language||l.data("language")||e.fn.fileinput.defaults.language||"en";s||(c&&(u=e.fn.fileinputThemes[c]||{}),"en"===f||t.isEmpty(e.fn.fileinputLocales[f])||(p=e.fn.fileinputLocales[f]||{}),o=e.extend(!0,{},e.fn.fileinput.defaults,u,e.fn.fileinputLocales.en,p,d,l.data()),s=new i(this,o),l.data("fileinput",s)),"string"==typeof a&&n.push(s[a].apply(s,r))}),n.length){case 0:return this;case 1:return n[0];default:return n}}},e.fn.fileinput.defaults={language:"en",showCaption:!0,showBrowse:!0,showPreview:!0,showRemove:!0,showUpload:!0,showCancel:!0,showClose:!0,showUploadedThumbs:!0,browseOnZoneClick:!1,autoReplace:!1,autoOrientImage:!0,required:!1,rtl:!1,hideThumbnailContent:!1,generateFileId:null,previewClass:"",captionClass:"",frameClass:"krajee-default",mainClass:"file-caption-main",mainTemplate:null,purifyHtml:!0,fileSizeGetter:null,initialCaption:"",initialPreview:[],initialPreviewDelimiter:"*$$*",initialPreviewAsData:!1,initialPreviewFileType:"image",initialPreviewConfig:[],initialPreviewThumbTags:[],previewThumbTags:{},initialPreviewShowDelete:!0,initialPreviewDownloadUrl:"",removeFromPreviewOnError:!1,deleteUrl:"",deleteExtraData:{},overwriteInitial:!0,previewZoomButtonIcons:{prev:'',next:'',toggleheader:'',fullscreen:'',borderless:'',close:''},previewZoomButtonClasses:{prev:"btn btn-navigate",next:"btn btn-navigate",toggleheader:"btn btn-sm btn-kv btn-default btn-outline-secondary",fullscreen:"btn btn-sm btn-kv btn-default btn-outline-secondary",borderless:"btn btn-sm btn-kv btn-default btn-outline-secondary",close:"btn btn-sm btn-kv btn-default btn-outline-secondary"},preferIconicPreview:!1,preferIconicZoomPreview:!1,allowedPreviewTypes:void 0,allowedPreviewMimeTypes:null,allowedFileTypes:null,allowedFileExtensions:null,defaultPreviewContent:null,customLayoutTags:{},customPreviewTags:{},previewFileIcon:'',previewFileIconClass:"file-other-icon",previewFileIconSettings:{},previewFileExtSettings:{},buttonLabelClass:"hidden-xs",browseIcon:' ',browseClass:"btn btn-primary",removeIcon:'',removeClass:"btn btn-default btn-secondary",cancelIcon:'',cancelClass:"btn btn-default btn-secondary",uploadIcon:'',uploadClass:"btn btn-default btn-secondary",uploadUrl:null,uploadUrlThumb:null,uploadAsync:!0,uploadExtraData:{},zoomModalHeight:480,minImageWidth:null,minImageHeight:null,maxImageWidth:null,maxImageHeight:null,resizeImage:!1,resizePreference:"width",resizeQuality:.92,resizeDefaultImageType:"image/jpeg",resizeIfSizeMoreThan:0,minFileSize:0,maxFileSize:0,maxFilePreviewSize:25600,minFileCount:0,maxFileCount:0,validateInitialCount:!1,msgValidationErrorClass:"text-danger",msgValidationErrorIcon:' ',msgErrorClass:"file-error-message",progressThumbClass:"progress-bar bg-success progress-bar-success progress-bar-striped active",progressClass:"progress-bar bg-success progress-bar-success progress-bar-striped active",progressCompleteClass:"progress-bar bg-success progress-bar-success",progressErrorClass:"progress-bar bg-danger progress-bar-danger",progressUploadThreshold:99,previewFileType:"image",elCaptionContainer:null,elCaptionText:null,elPreviewContainer:null,elPreviewImage:null,elPreviewStatus:null,elErrorContainer:null,errorCloseButton:t.closeButton("kv-error-close"),slugCallback:null,dropZoneEnabled:!0,dropZoneTitleClass:"file-drop-zone-title",fileActionSettings:{},otherActionButtons:"",textEncoding:"UTF-8",ajaxSettings:{},ajaxDeleteSettings:{},showAjaxErrorDetails:!0,mergeAjaxCallbacks:!1,mergeAjaxDeleteCallbacks:!1,retryErrorUploads:!0,reversePreviewOrder:!1},e.fn.fileinputLocales.en={fileSingle:"file",filePlural:"files",browseLabel:"Browse …",removeLabel:"Remove",removeTitle:"Clear selected files",cancelLabel:"Cancel",cancelTitle:"Abort ongoing upload",uploadLabel:"Upload",uploadTitle:"Upload selected files",msgNo:"No",msgNoFilesSelected:"No files selected",msgCancelled:"Cancelled",msgPlaceholder:"Select {files}...",msgZoomModalHeading:"Detailed Preview",msgFileRequired:"You must select a file to upload.",msgSizeTooSmall:'File "{name}" ({size} KB) is too small and must be larger than {minSize} KB.',msgSizeTooLarge:'File "{name}" ({size} KB) exceeds maximum allowed upload size of {maxSize} KB.',msgFilesTooLess:"You must select at least {n} {files} to upload.",msgFilesTooMany:"Number of files selected for upload ({n}) exceeds maximum allowed limit of {m}.",msgFileNotFound:'File "{name}" not found!',msgFileSecured:'Security restrictions prevent reading the file "{name}".',msgFileNotReadable:'File "{name}" is not readable.',msgFilePreviewAborted:'File preview aborted for "{name}".',msgFilePreviewError:'An error occurred while reading the file "{name}".',msgInvalidFileName:'Invalid or unsupported characters in file name "{name}".',msgInvalidFileType:'Invalid type for file "{name}". Only "{types}" files are supported.',msgInvalidFileExtension:'Invalid extension for file "{name}". Only "{extensions}" files are supported.',msgFileTypes:{image:"image",html:"HTML",text:"text",video:"video",audio:"audio",flash:"flash",pdf:"PDF",object:"object"},msgUploadAborted:"The file upload was aborted",msgUploadThreshold:"Processing...",msgUploadBegin:"Initializing...",msgUploadEnd:"Done",msgUploadEmpty:"No valid data available for upload.",msgUploadError:"Error",msgValidationError:"Validation Error",msgLoading:"Loading file {index} of {files} …",msgProgress:"Loading file {index} of {files} - {name} - {percent}% completed.",msgSelected:"{n} {files} selected",msgFoldersNotAllowed:"Drag & drop files only! {n} folder(s) dropped were skipped.",msgImageWidthSmall:'Width of image file "{name}" must be at least {size} px.',msgImageHeightSmall:'Height of image file "{name}" must be at least {size} px.',msgImageWidthLarge:'Width of image file "{name}" cannot exceed {size} px.',msgImageHeightLarge:'Height of image file "{name}" cannot exceed {size} px.',msgImageResizeError:"Could not get the image dimensions to resize.",msgImageResizeException:"Error while resizing the image.{errors}",msgAjaxError:"Something went wrong with the {operation} operation. Please try again later!",msgAjaxProgressError:"{operation} failed",ajaxOperations:{deleteThumb:"file delete",uploadThumb:"file upload",uploadBatch:"batch file upload",uploadExtra:"form data upload"},dropZoneTitle:"Drag & drop files here …",dropZoneClickTitle:"(or click to select {files})",previewZoomButtonTitles:{prev:"View previous file",next:"View next file",toggleheader:"Toggle header",fullscreen:"Toggle full screen",borderless:"Toggle borderless mode",close:"Close detailed preview"}},e.fn.fileinput.Constructor=i,e(document).ready(function(){var t=e("input.file[type=file]");t.length&&t.fileinput()})}); \ No newline at end of file diff --git a/src/main/resources/static/js/plugins/fileinput/locales/zh.js b/src/main/resources/static/js/plugins/fileinput/locales/zh.js new file mode 100644 index 000000000..32f405744 --- /dev/null +++ b/src/main/resources/static/js/plugins/fileinput/locales/zh.js @@ -0,0 +1,100 @@ +/*! + * FileInput Chinese Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * @author kangqf + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['zh'] = { + fileSingle: '文件', + filePlural: '个文件', + browseLabel: '选择 …', + removeLabel: '移除', + removeTitle: '清除选中文件', + cancelLabel: '取消', + cancelTitle: '取消进行中的上传', + uploadLabel: '上传', + uploadTitle: '上传选中文件', + msgNo: '没有', + msgNoFilesSelected: '未选择文件', + msgCancelled: '取消', + msgPlaceholder: '选择 {files}...', + msgZoomModalHeading: '详细预览', + msgFileRequired: '必须选择一个文件上传.', + msgSizeTooSmall: '文件 "{name}" ({size} KB) 必须大于限定大小 {minSize} KB.', + msgSizeTooLarge: '文件 "{name}" ({size} KB) 超过了允许大小 {maxSize} KB.', + msgFilesTooLess: '你必须选择最少 {n} {files} 来上传. ', + msgFilesTooMany: '选择的上传文件个数 ({n}) 超出最大文件的限制个数 {m}.', + msgFileNotFound: '文件 "{name}" 未找到!', + msgFileSecured: '安全限制,为了防止读取文件 "{name}".', + msgFileNotReadable: '文件 "{name}" 不可读.', + msgFilePreviewAborted: '取消 "{name}" 的预览.', + msgFilePreviewError: '读取 "{name}" 时出现了一个错误.', + msgInvalidFileName: '文件名 "{name}" 包含非法字符.', + msgInvalidFileType: '不正确的类型 "{name}". 只支持 "{types}" 类型的文件.', + msgInvalidFileExtension: '不正确的文件扩展名 "{name}". 只支持 "{extensions}" 的文件扩展名.', + msgFileTypes: { + 'image': 'image', + 'html': 'HTML', + 'text': 'text', + 'video': 'video', + 'audio': 'audio', + 'flash': 'flash', + 'pdf': 'PDF', + 'object': 'object' + }, + msgUploadAborted: '该文件上传被中止', + msgUploadThreshold: '处理中...', + msgUploadBegin: '正在初始化...', + msgUploadEnd: '完成', + msgUploadEmpty: '无效的文件上传.', + msgUploadError: '上传出错', + msgValidationError: '验证错误', + msgLoading: '加载第 {index} 文件 共 {files} …', + msgProgress: '加载第 {index} 文件 共 {files} - {name} - {percent}% 完成.', + msgSelected: '{n} {files} 选中', + msgFoldersNotAllowed: '只支持拖拽文件! 跳过 {n} 拖拽的文件夹.', + msgImageWidthSmall: '图像文件的"{name}"的宽度必须是至少{size}像素.', + msgImageHeightSmall: '图像文件的"{name}"的高度必须至少为{size}像素.', + msgImageWidthLarge: '图像文件"{name}"的宽度不能超过{size}像素.', + msgImageHeightLarge: '图像文件"{name}"的高度不能超过{size}像素.', + msgImageResizeError: '无法获取的图像尺寸调整。', + msgImageResizeException: '调整图像大小时发生错误。{errors}', + msgAjaxError: '{operation} 发生错误. 请重试!', + msgAjaxProgressError: '{operation} 失败', + ajaxOperations: { + deleteThumb: '删除文件', + uploadThumb: '上传文件', + uploadBatch: '批量上传', + uploadExtra: '表单数据上传' + }, + dropZoneTitle: '拖拽文件到这里 …支持多文件同时上传', + dropZoneClickTitle: '(或点击{files}按钮选择文件)', + fileActionSettings: { + removeTitle: '删除文件', + uploadTitle: '上传文件', + uploadRetryTitle: '重试', + zoomTitle: '查看详情', + dragTitle: '移动 / 重置', + indicatorNewTitle: '没有上传', + indicatorSuccessTitle: '上传', + indicatorErrorTitle: '上传错误', + indicatorLoadingTitle: '上传 ...' + }, + previewZoomButtonTitles: { + prev: '预览上一个文件', + next: '预览下一个文件', + toggleheader: '缩放', + fullscreen: '全屏', + borderless: '无边界模式', + close: '关闭当前预览' + } + }; +})(window.jQuery); diff --git a/src/main/resources/static/js/plugins/fileinput/plugins/piexif.js b/src/main/resources/static/js/plugins/fileinput/plugins/piexif.js new file mode 100644 index 000000000..343bf3914 --- /dev/null +++ b/src/main/resources/static/js/plugins/fileinput/plugins/piexif.js @@ -0,0 +1,2471 @@ +/* piexifjs + +The MIT License (MIT) + +Copyright (c) 2014, 2015 hMatoba(https://github.com/hMatoba) + +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. +*/ + +(function () { + "use strict"; + var that = {}; + that.version = "1.03"; + + that.remove = function (jpeg) { + var b64 = false; + if (jpeg.slice(0, 2) == "\xff\xd8") { + } else if (jpeg.slice(0, 23) == "data:image/jpeg;base64," || jpeg.slice(0, 22) == "data:image/jpg;base64,") { + jpeg = atob(jpeg.split(",")[1]); + b64 = true; + } else { + throw ("Given data is not jpeg."); + } + + var segments = splitIntoSegments(jpeg); + if (segments[1].slice(0, 2) == "\xff\xe1" && + segments[1].slice(4, 10) == "Exif\x00\x00") { + segments = [segments[0]].concat(segments.slice(2)); + } else if (segments[2].slice(0, 2) == "\xff\xe1" && + segments[2].slice(4, 10) == "Exif\x00\x00") { + segments = segments.slice(0, 2).concat(segments.slice(3)); + } else { + throw("Exif not found."); + } + + var new_data = segments.join(""); + if (b64) { + new_data = "data:image/jpeg;base64," + btoa(new_data); + } + + return new_data; + }; + + + that.insert = function (exif, jpeg) { + var b64 = false; + if (exif.slice(0, 6) != "\x45\x78\x69\x66\x00\x00") { + throw ("Given data is not exif."); + } + if (jpeg.slice(0, 2) == "\xff\xd8") { + } else if (jpeg.slice(0, 23) == "data:image/jpeg;base64," || jpeg.slice(0, 22) == "data:image/jpg;base64,") { + jpeg = atob(jpeg.split(",")[1]); + b64 = true; + } else { + throw ("Given data is not jpeg."); + } + + var exifStr = "\xff\xe1" + pack(">H", [exif.length + 2]) + exif; + var segments = splitIntoSegments(jpeg); + var new_data = mergeSegments(segments, exifStr); + if (b64) { + new_data = "data:image/jpeg;base64," + btoa(new_data); + } + + return new_data; + }; + + + that.load = function (data) { + var input_data; + if (typeof (data) == "string") { + if (data.slice(0, 2) == "\xff\xd8") { + input_data = data; + } else if (data.slice(0, 23) == "data:image/jpeg;base64," || data.slice(0, 22) == "data:image/jpg;base64,") { + input_data = atob(data.split(",")[1]); + } else if (data.slice(0, 4) == "Exif") { + input_data = data.slice(6); + } else { + throw ("'load' gots invalid file data."); + } + } else { + throw ("'load' gots invalid type argument."); + } + + var exifDict = {}; + var exif_dict = { + "0th": {}, + "Exif": {}, + "GPS": {}, + "Interop": {}, + "1st": {}, + "thumbnail": null + }; + var exifReader = new ExifReader(input_data); + if (exifReader.tiftag === null) { + return exif_dict; + } + + if (exifReader.tiftag.slice(0, 2) == "\x49\x49") { + exifReader.endian_mark = "<"; + } else { + exifReader.endian_mark = ">"; + } + + var pointer = unpack(exifReader.endian_mark + "L", + exifReader.tiftag.slice(4, 8))[0]; + exif_dict["0th"] = exifReader.get_ifd(pointer, "0th"); + + var first_ifd_pointer = exif_dict["0th"]["first_ifd_pointer"]; + delete exif_dict["0th"]["first_ifd_pointer"]; + + if (34665 in exif_dict["0th"]) { + pointer = exif_dict["0th"][34665]; + exif_dict["Exif"] = exifReader.get_ifd(pointer, "Exif"); + } + if (34853 in exif_dict["0th"]) { + pointer = exif_dict["0th"][34853]; + exif_dict["GPS"] = exifReader.get_ifd(pointer, "GPS"); + } + if (40965 in exif_dict["Exif"]) { + pointer = exif_dict["Exif"][40965]; + exif_dict["Interop"] = exifReader.get_ifd(pointer, "Interop"); + } + if (first_ifd_pointer != "\x00\x00\x00\x00") { + pointer = unpack(exifReader.endian_mark + "L", + first_ifd_pointer)[0]; + exif_dict["1st"] = exifReader.get_ifd(pointer, "1st"); + if ((513 in exif_dict["1st"]) && (514 in exif_dict["1st"])) { + var end = exif_dict["1st"][513] + exif_dict["1st"][514]; + var thumb = exifReader.tiftag.slice(exif_dict["1st"][513], end); + exif_dict["thumbnail"] = thumb; + } + } + + return exif_dict; + }; + + + that.dump = function (exif_dict_original) { + var TIFF_HEADER_LENGTH = 8; + + var exif_dict = copy(exif_dict_original); + var header = "Exif\x00\x00\x4d\x4d\x00\x2a\x00\x00\x00\x08"; + var exif_is = false; + var gps_is = false; + var interop_is = false; + var first_is = false; + + var zeroth_ifd, + exif_ifd, + interop_ifd, + gps_ifd, + first_ifd; + + if ("0th" in exif_dict) { + zeroth_ifd = exif_dict["0th"]; + } else { + zeroth_ifd = {}; + } + + if ((("Exif" in exif_dict) && (Object.keys(exif_dict["Exif"]).length)) || + (("Interop" in exif_dict) && (Object.keys(exif_dict["Interop"]).length))) { + zeroth_ifd[34665] = 1; + exif_is = true; + exif_ifd = exif_dict["Exif"]; + if (("Interop" in exif_dict) && Object.keys(exif_dict["Interop"]).length) { + exif_ifd[40965] = 1; + interop_is = true; + interop_ifd = exif_dict["Interop"]; + } else if (Object.keys(exif_ifd).indexOf(that.ExifIFD.InteroperabilityTag.toString()) > -1) { + delete exif_ifd[40965]; + } + } else if (Object.keys(zeroth_ifd).indexOf(that.ImageIFD.ExifTag.toString()) > -1) { + delete zeroth_ifd[34665]; + } + + if (("GPS" in exif_dict) && (Object.keys(exif_dict["GPS"]).length)) { + zeroth_ifd[that.ImageIFD.GPSTag] = 1; + gps_is = true; + gps_ifd = exif_dict["GPS"]; + } else if (Object.keys(zeroth_ifd).indexOf(that.ImageIFD.GPSTag.toString()) > -1) { + delete zeroth_ifd[that.ImageIFD.GPSTag]; + } + + if (("1st" in exif_dict) && + ("thumbnail" in exif_dict) && + (exif_dict["thumbnail"] != null)) { + first_is = true; + exif_dict["1st"][513] = 1; + exif_dict["1st"][514] = 1; + first_ifd = exif_dict["1st"]; + } + + var zeroth_set = _dict_to_bytes(zeroth_ifd, "0th", 0); + var zeroth_length = (zeroth_set[0].length + exif_is * 12 + gps_is * 12 + 4 + + zeroth_set[1].length); + + var exif_set, + exif_bytes = "", + exif_length = 0, + gps_set, + gps_bytes = "", + gps_length = 0, + interop_set, + interop_bytes = "", + interop_length = 0, + first_set, + first_bytes = "", + thumbnail; + if (exif_is) { + exif_set = _dict_to_bytes(exif_ifd, "Exif", zeroth_length); + exif_length = exif_set[0].length + interop_is * 12 + exif_set[1].length; + } + if (gps_is) { + gps_set = _dict_to_bytes(gps_ifd, "GPS", zeroth_length + exif_length); + gps_bytes = gps_set.join(""); + gps_length = gps_bytes.length; + } + if (interop_is) { + var offset = zeroth_length + exif_length + gps_length; + interop_set = _dict_to_bytes(interop_ifd, "Interop", offset); + interop_bytes = interop_set.join(""); + interop_length = interop_bytes.length; + } + if (first_is) { + var offset = zeroth_length + exif_length + gps_length + interop_length; + first_set = _dict_to_bytes(first_ifd, "1st", offset); + thumbnail = _get_thumbnail(exif_dict["thumbnail"]); + if (thumbnail.length > 64000) { + throw ("Given thumbnail is too large. max 64kB"); + } + } + + var exif_pointer = "", + gps_pointer = "", + interop_pointer = "", + first_ifd_pointer = "\x00\x00\x00\x00"; + if (exif_is) { + var pointer_value = TIFF_HEADER_LENGTH + zeroth_length; + var pointer_str = pack(">L", [pointer_value]); + var key = 34665; + var key_str = pack(">H", [key]); + var type_str = pack(">H", [TYPES["Long"]]); + var length_str = pack(">L", [1]); + exif_pointer = key_str + type_str + length_str + pointer_str; + } + if (gps_is) { + var pointer_value = TIFF_HEADER_LENGTH + zeroth_length + exif_length; + var pointer_str = pack(">L", [pointer_value]); + var key = 34853; + var key_str = pack(">H", [key]); + var type_str = pack(">H", [TYPES["Long"]]); + var length_str = pack(">L", [1]); + gps_pointer = key_str + type_str + length_str + pointer_str; + } + if (interop_is) { + var pointer_value = (TIFF_HEADER_LENGTH + + zeroth_length + exif_length + gps_length); + var pointer_str = pack(">L", [pointer_value]); + var key = 40965; + var key_str = pack(">H", [key]); + var type_str = pack(">H", [TYPES["Long"]]); + var length_str = pack(">L", [1]); + interop_pointer = key_str + type_str + length_str + pointer_str; + } + if (first_is) { + var pointer_value = (TIFF_HEADER_LENGTH + zeroth_length + + exif_length + gps_length + interop_length); + first_ifd_pointer = pack(">L", [pointer_value]); + var thumbnail_pointer = (pointer_value + first_set[0].length + 24 + + 4 + first_set[1].length); + var thumbnail_p_bytes = ("\x02\x01\x00\x04\x00\x00\x00\x01" + + pack(">L", [thumbnail_pointer])); + var thumbnail_length_bytes = ("\x02\x02\x00\x04\x00\x00\x00\x01" + + pack(">L", [thumbnail.length])); + first_bytes = (first_set[0] + thumbnail_p_bytes + + thumbnail_length_bytes + "\x00\x00\x00\x00" + + first_set[1] + thumbnail); + } + + var zeroth_bytes = (zeroth_set[0] + exif_pointer + gps_pointer + + first_ifd_pointer + zeroth_set[1]); + if (exif_is) { + exif_bytes = exif_set[0] + interop_pointer + exif_set[1]; + } + + return (header + zeroth_bytes + exif_bytes + gps_bytes + + interop_bytes + first_bytes); + }; + + + function copy(obj) { + return JSON.parse(JSON.stringify(obj)); + } + + + function _get_thumbnail(jpeg) { + var segments = splitIntoSegments(jpeg); + while (("\xff\xe0" <= segments[1].slice(0, 2)) && (segments[1].slice(0, 2) <= "\xff\xef")) { + segments = [segments[0]].concat(segments.slice(2)); + } + return segments.join(""); + } + + + function _pack_byte(array) { + return pack(">" + nStr("B", array.length), array); + } + + + function _pack_short(array) { + return pack(">" + nStr("H", array.length), array); + } + + + function _pack_long(array) { + return pack(">" + nStr("L", array.length), array); + } + + + function _value_to_bytes(raw_value, value_type, offset) { + var four_bytes_over = ""; + var value_str = ""; + var length, + new_value, + num, + den; + + if (value_type == "Byte") { + length = raw_value.length; + if (length <= 4) { + value_str = (_pack_byte(raw_value) + + nStr("\x00", 4 - length)); + } else { + value_str = pack(">L", [offset]); + four_bytes_over = _pack_byte(raw_value); + } + } else if (value_type == "Short") { + length = raw_value.length; + if (length <= 2) { + value_str = (_pack_short(raw_value) + + nStr("\x00\x00", 2 - length)); + } else { + value_str = pack(">L", [offset]); + four_bytes_over = _pack_short(raw_value); + } + } else if (value_type == "Long") { + length = raw_value.length; + if (length <= 1) { + value_str = _pack_long(raw_value); + } else { + value_str = pack(">L", [offset]); + four_bytes_over = _pack_long(raw_value); + } + } else if (value_type == "Ascii") { + new_value = raw_value + "\x00"; + length = new_value.length; + if (length > 4) { + value_str = pack(">L", [offset]); + four_bytes_over = new_value; + } else { + value_str = new_value + nStr("\x00", 4 - length); + } + } else if (value_type == "Rational") { + if (typeof (raw_value[0]) == "number") { + length = 1; + num = raw_value[0]; + den = raw_value[1]; + new_value = pack(">L", [num]) + pack(">L", [den]); + } else { + length = raw_value.length; + new_value = ""; + for (var n = 0; n < length; n++) { + num = raw_value[n][0]; + den = raw_value[n][1]; + new_value += (pack(">L", [num]) + + pack(">L", [den])); + } + } + value_str = pack(">L", [offset]); + four_bytes_over = new_value; + } else if (value_type == "SRational") { + if (typeof (raw_value[0]) == "number") { + length = 1; + num = raw_value[0]; + den = raw_value[1]; + new_value = pack(">l", [num]) + pack(">l", [den]); + } else { + length = raw_value.length; + new_value = ""; + for (var n = 0; n < length; n++) { + num = raw_value[n][0]; + den = raw_value[n][1]; + new_value += (pack(">l", [num]) + + pack(">l", [den])); + } + } + value_str = pack(">L", [offset]); + four_bytes_over = new_value; + } else if (value_type == "Undefined") { + length = raw_value.length; + if (length > 4) { + value_str = pack(">L", [offset]); + four_bytes_over = raw_value; + } else { + value_str = raw_value + nStr("\x00", 4 - length); + } + } + + var length_str = pack(">L", [length]); + + return [length_str, value_str, four_bytes_over]; + } + + function _dict_to_bytes(ifd_dict, ifd, ifd_offset) { + var TIFF_HEADER_LENGTH = 8; + var tag_count = Object.keys(ifd_dict).length; + var entry_header = pack(">H", [tag_count]); + var entries_length; + if (["0th", "1st"].indexOf(ifd) > -1) { + entries_length = 2 + tag_count * 12 + 4; + } else { + entries_length = 2 + tag_count * 12; + } + var entries = ""; + var values = ""; + var key; + + for (var key in ifd_dict) { + if (typeof (key) == "string") { + key = parseInt(key); + } + if ((ifd == "0th") && ([34665, 34853].indexOf(key) > -1)) { + continue; + } else if ((ifd == "Exif") && (key == 40965)) { + continue; + } else if ((ifd == "1st") && ([513, 514].indexOf(key) > -1)) { + continue; + } + + var raw_value = ifd_dict[key]; + var key_str = pack(">H", [key]); + var value_type = TAGS[ifd][key]["type"]; + var type_str = pack(">H", [TYPES[value_type]]); + + if (typeof (raw_value) == "number") { + raw_value = [raw_value]; + } + var offset = TIFF_HEADER_LENGTH + entries_length + ifd_offset + values.length; + var b = _value_to_bytes(raw_value, value_type, offset); + var length_str = b[0]; + var value_str = b[1]; + var four_bytes_over = b[2]; + + entries += key_str + type_str + length_str + value_str; + values += four_bytes_over; + } + + return [entry_header + entries, values]; + } + + + + function ExifReader(data) { + var segments, + app1; + if (data.slice(0, 2) == "\xff\xd8") { // JPEG + segments = splitIntoSegments(data); + app1 = getExifSeg(segments); + if (app1) { + this.tiftag = app1.slice(10); + } else { + this.tiftag = null; + } + } else if (["\x49\x49", "\x4d\x4d"].indexOf(data.slice(0, 2)) > -1) { // TIFF + this.tiftag = data; + } else if (data.slice(0, 4) == "Exif") { // Exif + this.tiftag = data.slice(6); + } else { + throw ("Given file is neither JPEG nor TIFF."); + } + } + + ExifReader.prototype = { + get_ifd: function (pointer, ifd_name) { + var ifd_dict = {}; + var tag_count = unpack(this.endian_mark + "H", + this.tiftag.slice(pointer, pointer + 2))[0]; + var offset = pointer + 2; + var t; + if (["0th", "1st"].indexOf(ifd_name) > -1) { + t = "Image"; + } else { + t = ifd_name; + } + + for (var x = 0; x < tag_count; x++) { + pointer = offset + 12 * x; + var tag = unpack(this.endian_mark + "H", + this.tiftag.slice(pointer, pointer + 2))[0]; + var value_type = unpack(this.endian_mark + "H", + this.tiftag.slice(pointer + 2, pointer + 4))[0]; + var value_num = unpack(this.endian_mark + "L", + this.tiftag.slice(pointer + 4, pointer + 8))[0]; + var value = this.tiftag.slice(pointer + 8, pointer + 12); + + var v_set = [value_type, value_num, value]; + if (tag in TAGS[t]) { + ifd_dict[tag] = this.convert_value(v_set); + } + } + + if (ifd_name == "0th") { + pointer = offset + 12 * tag_count; + ifd_dict["first_ifd_pointer"] = this.tiftag.slice(pointer, pointer + 4); + } + + return ifd_dict; + }, + + convert_value: function (val) { + var data = null; + var t = val[0]; + var length = val[1]; + var value = val[2]; + var pointer; + + if (t == 1) { // BYTE + if (length > 4) { + pointer = unpack(this.endian_mark + "L", value)[0]; + data = unpack(this.endian_mark + nStr("B", length), + this.tiftag.slice(pointer, pointer + length)); + } else { + data = unpack(this.endian_mark + nStr("B", length), value.slice(0, length)); + } + } else if (t == 2) { // ASCII + if (length > 4) { + pointer = unpack(this.endian_mark + "L", value)[0]; + data = this.tiftag.slice(pointer, pointer + length - 1); + } else { + data = value.slice(0, length - 1); + } + } else if (t == 3) { // SHORT + if (length > 2) { + pointer = unpack(this.endian_mark + "L", value)[0]; + data = unpack(this.endian_mark + nStr("H", length), + this.tiftag.slice(pointer, pointer + length * 2)); + } else { + data = unpack(this.endian_mark + nStr("H", length), + value.slice(0, length * 2)); + } + } else if (t == 4) { // LONG + if (length > 1) { + pointer = unpack(this.endian_mark + "L", value)[0]; + data = unpack(this.endian_mark + nStr("L", length), + this.tiftag.slice(pointer, pointer + length * 4)); + } else { + data = unpack(this.endian_mark + nStr("L", length), + value); + } + } else if (t == 5) { // RATIONAL + pointer = unpack(this.endian_mark + "L", value)[0]; + if (length > 1) { + data = []; + for (var x = 0; x < length; x++) { + data.push([unpack(this.endian_mark + "L", + this.tiftag.slice(pointer + x * 8, pointer + 4 + x * 8))[0], + unpack(this.endian_mark + "L", + this.tiftag.slice(pointer + 4 + x * 8, pointer + 8 + x * 8))[0] + ]); + } + } else { + data = [unpack(this.endian_mark + "L", + this.tiftag.slice(pointer, pointer + 4))[0], + unpack(this.endian_mark + "L", + this.tiftag.slice(pointer + 4, pointer + 8))[0] + ]; + } + } else if (t == 7) { // UNDEFINED BYTES + if (length > 4) { + pointer = unpack(this.endian_mark + "L", value)[0]; + data = this.tiftag.slice(pointer, pointer + length); + } else { + data = value.slice(0, length); + } + } else if (t == 10) { // SRATIONAL + pointer = unpack(this.endian_mark + "L", value)[0]; + if (length > 1) { + data = []; + for (var x = 0; x < length; x++) { + data.push([unpack(this.endian_mark + "l", + this.tiftag.slice(pointer + x * 8, pointer + 4 + x * 8))[0], + unpack(this.endian_mark + "l", + this.tiftag.slice(pointer + 4 + x * 8, pointer + 8 + x * 8))[0] + ]); + } + } else { + data = [unpack(this.endian_mark + "l", + this.tiftag.slice(pointer, pointer + 4))[0], + unpack(this.endian_mark + "l", + this.tiftag.slice(pointer + 4, pointer + 8))[0] + ]; + } + } else { + throw ("Exif might be wrong. Got incorrect value " + + "type to decode. type:" + t); + } + + if ((data instanceof Array) && (data.length == 1)) { + return data[0]; + } else { + return data; + } + }, + }; + + + if (typeof window !== "undefined" && typeof window.btoa === "function") { + var btoa = window.btoa; + } + if (typeof btoa === "undefined") { + var btoa = function (input) { var output = ""; + var chr1, chr2, chr3, enc1, enc2, enc3, enc4; + var i = 0; + var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + while (i < input.length) { + + chr1 = input.charCodeAt(i++); + chr2 = input.charCodeAt(i++); + chr3 = input.charCodeAt(i++); + + enc1 = chr1 >> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } + + output = output + + keyStr.charAt(enc1) + keyStr.charAt(enc2) + + keyStr.charAt(enc3) + keyStr.charAt(enc4); + + } + + return output; + }; + } + + + if (typeof window !== "undefined" && typeof window.atob === "function") { + var atob = window.atob; + } + if (typeof atob === "undefined") { + var atob = function (input) { + var output = ""; + var chr1, chr2, chr3; + var enc1, enc2, enc3, enc4; + var i = 0; + var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); + + while (i < input.length) { + + enc1 = keyStr.indexOf(input.charAt(i++)); + enc2 = keyStr.indexOf(input.charAt(i++)); + enc3 = keyStr.indexOf(input.charAt(i++)); + enc4 = keyStr.indexOf(input.charAt(i++)); + + chr1 = (enc1 << 2) | (enc2 >> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + + output = output + String.fromCharCode(chr1); + + if (enc3 != 64) { + output = output + String.fromCharCode(chr2); + } + if (enc4 != 64) { + output = output + String.fromCharCode(chr3); + } + + } + + return output; + }; + } + + + function getImageSize(imageArray) { + var segments = slice2Segments(imageArray); + var seg, + width, + height, + SOF = [192, 193, 194, 195, 197, 198, 199, 201, 202, 203, 205, 206, 207]; + + for (var x = 0; x < segments.length; x++) { + seg = segments[x]; + if (SOF.indexOf(seg[1]) >= 0) { + height = seg[5] * 256 + seg[6]; + width = seg[7] * 256 + seg[8]; + break; + } + } + return [width, height]; + } + + + function pack(mark, array) { + if (!(array instanceof Array)) { + throw ("'pack' error. Got invalid type argument."); + } + if ((mark.length - 1) != array.length) { + throw ("'pack' error. " + (mark.length - 1) + " marks, " + array.length + " elements."); + } + + var littleEndian; + if (mark[0] == "<") { + littleEndian = true; + } else if (mark[0] == ">") { + littleEndian = false; + } else { + throw (""); + } + var packed = ""; + var p = 1; + var val = null; + var c = null; + var valStr = null; + + while (c = mark[p]) { + if (c.toLowerCase() == "b") { + val = array[p - 1]; + if ((c == "b") && (val < 0)) { + val += 0x100; + } + if ((val > 0xff) || (val < 0)) { + throw ("'pack' error."); + } else { + valStr = String.fromCharCode(val); + } + } else if (c == "H") { + val = array[p - 1]; + if ((val > 0xffff) || (val < 0)) { + throw ("'pack' error."); + } else { + valStr = String.fromCharCode(Math.floor((val % 0x10000) / 0x100)) + + String.fromCharCode(val % 0x100); + if (littleEndian) { + valStr = valStr.split("").reverse().join(""); + } + } + } else if (c.toLowerCase() == "l") { + val = array[p - 1]; + if ((c == "l") && (val < 0)) { + val += 0x100000000; + } + if ((val > 0xffffffff) || (val < 0)) { + throw ("'pack' error."); + } else { + valStr = String.fromCharCode(Math.floor(val / 0x1000000)) + + String.fromCharCode(Math.floor((val % 0x1000000) / 0x10000)) + + String.fromCharCode(Math.floor((val % 0x10000) / 0x100)) + + String.fromCharCode(val % 0x100); + if (littleEndian) { + valStr = valStr.split("").reverse().join(""); + } + } + } else { + throw ("'pack' error."); + } + + packed += valStr; + p += 1; + } + + return packed; + } + + function unpack(mark, str) { + if (typeof (str) != "string") { + throw ("'unpack' error. Got invalid type argument."); + } + var l = 0; + for (var markPointer = 1; markPointer < mark.length; markPointer++) { + if (mark[markPointer].toLowerCase() == "b") { + l += 1; + } else if (mark[markPointer].toLowerCase() == "h") { + l += 2; + } else if (mark[markPointer].toLowerCase() == "l") { + l += 4; + } else { + throw ("'unpack' error. Got invalid mark."); + } + } + + if (l != str.length) { + throw ("'unpack' error. Mismatch between symbol and string length. " + l + ":" + str.length); + } + + var littleEndian; + if (mark[0] == "<") { + littleEndian = true; + } else if (mark[0] == ">") { + littleEndian = false; + } else { + throw ("'unpack' error."); + } + var unpacked = []; + var strPointer = 0; + var p = 1; + var val = null; + var c = null; + var length = null; + var sliced = ""; + + while (c = mark[p]) { + if (c.toLowerCase() == "b") { + length = 1; + sliced = str.slice(strPointer, strPointer + length); + val = sliced.charCodeAt(0); + if ((c == "b") && (val >= 0x80)) { + val -= 0x100; + } + } else if (c == "H") { + length = 2; + sliced = str.slice(strPointer, strPointer + length); + if (littleEndian) { + sliced = sliced.split("").reverse().join(""); + } + val = sliced.charCodeAt(0) * 0x100 + + sliced.charCodeAt(1); + } else if (c.toLowerCase() == "l") { + length = 4; + sliced = str.slice(strPointer, strPointer + length); + if (littleEndian) { + sliced = sliced.split("").reverse().join(""); + } + val = sliced.charCodeAt(0) * 0x1000000 + + sliced.charCodeAt(1) * 0x10000 + + sliced.charCodeAt(2) * 0x100 + + sliced.charCodeAt(3); + if ((c == "l") && (val >= 0x80000000)) { + val -= 0x100000000; + } + } else { + throw ("'unpack' error. " + c); + } + + unpacked.push(val); + strPointer += length; + p += 1; + } + + return unpacked; + } + + function nStr(ch, num) { + var str = ""; + for (var i = 0; i < num; i++) { + str += ch; + } + return str; + } + + function splitIntoSegments(data) { + if (data.slice(0, 2) != "\xff\xd8") { + throw ("Given data isn't JPEG."); + } + + var head = 2; + var segments = ["\xff\xd8"]; + while (true) { + if (data.slice(head, head + 2) == "\xff\xda") { + segments.push(data.slice(head)); + break; + } else { + var length = unpack(">H", data.slice(head + 2, head + 4))[0]; + var endPoint = head + length + 2; + segments.push(data.slice(head, endPoint)); + head = endPoint; + } + + if (head >= data.length) { + throw ("Wrong JPEG data."); + } + } + return segments; + } + + + function getExifSeg(segments) { + var seg; + for (var i = 0; i < segments.length; i++) { + seg = segments[i]; + if (seg.slice(0, 2) == "\xff\xe1" && + seg.slice(4, 10) == "Exif\x00\x00") { + return seg; + } + } + return null; + } + + + function mergeSegments(segments, exif) { + + if (segments[1].slice(0, 2) == "\xff\xe0" && + (segments[2].slice(0, 2) == "\xff\xe1" && + segments[2].slice(4, 10) == "Exif\x00\x00")) { + if (exif) { + segments[2] = exif; + segments = ["\xff\xd8"].concat(segments.slice(2)); + } else if (exif == null) { + segments = segments.slice(0, 2).concat(segments.slice(3)); + } else { + segments = segments.slice(0).concat(segments.slice(2)); + } + } else if (segments[1].slice(0, 2) == "\xff\xe0") { + if (exif) { + segments[1] = exif; + } + } else if (segments[1].slice(0, 2) == "\xff\xe1" && + segments[1].slice(4, 10) == "Exif\x00\x00") { + if (exif) { + segments[1] = exif; + } else if (exif == null) { + segments = segments.slice(0).concat(segments.slice(2)); + } + } else { + if (exif) { + segments = [segments[0], exif].concat(segments.slice(1)); + } + } + + return segments.join(""); + } + + + function toHex(str) { + var hexStr = ""; + for (var i = 0; i < str.length; i++) { + var h = str.charCodeAt(i); + var hex = ((h < 10) ? "0" : "") + h.toString(16); + hexStr += hex + " "; + } + return hexStr; + } + + + var TYPES = { + "Byte": 1, + "Ascii": 2, + "Short": 3, + "Long": 4, + "Rational": 5, + "Undefined": 7, + "SLong": 9, + "SRational": 10 + }; + + + var TAGS = { + 'Image': { + 11: { + 'name': 'ProcessingSoftware', + 'type': 'Ascii' + }, + 254: { + 'name': 'NewSubfileType', + 'type': 'Long' + }, + 255: { + 'name': 'SubfileType', + 'type': 'Short' + }, + 256: { + 'name': 'ImageWidth', + 'type': 'Long' + }, + 257: { + 'name': 'ImageLength', + 'type': 'Long' + }, + 258: { + 'name': 'BitsPerSample', + 'type': 'Short' + }, + 259: { + 'name': 'Compression', + 'type': 'Short' + }, + 262: { + 'name': 'PhotometricInterpretation', + 'type': 'Short' + }, + 263: { + 'name': 'Threshholding', + 'type': 'Short' + }, + 264: { + 'name': 'CellWidth', + 'type': 'Short' + }, + 265: { + 'name': 'CellLength', + 'type': 'Short' + }, + 266: { + 'name': 'FillOrder', + 'type': 'Short' + }, + 269: { + 'name': 'DocumentName', + 'type': 'Ascii' + }, + 270: { + 'name': 'ImageDescription', + 'type': 'Ascii' + }, + 271: { + 'name': 'Make', + 'type': 'Ascii' + }, + 272: { + 'name': 'Model', + 'type': 'Ascii' + }, + 273: { + 'name': 'StripOffsets', + 'type': 'Long' + }, + 274: { + 'name': 'Orientation', + 'type': 'Short' + }, + 277: { + 'name': 'SamplesPerPixel', + 'type': 'Short' + }, + 278: { + 'name': 'RowsPerStrip', + 'type': 'Long' + }, + 279: { + 'name': 'StripByteCounts', + 'type': 'Long' + }, + 282: { + 'name': 'XResolution', + 'type': 'Rational' + }, + 283: { + 'name': 'YResolution', + 'type': 'Rational' + }, + 284: { + 'name': 'PlanarConfiguration', + 'type': 'Short' + }, + 290: { + 'name': 'GrayResponseUnit', + 'type': 'Short' + }, + 291: { + 'name': 'GrayResponseCurve', + 'type': 'Short' + }, + 292: { + 'name': 'T4Options', + 'type': 'Long' + }, + 293: { + 'name': 'T6Options', + 'type': 'Long' + }, + 296: { + 'name': 'ResolutionUnit', + 'type': 'Short' + }, + 301: { + 'name': 'TransferFunction', + 'type': 'Short' + }, + 305: { + 'name': 'Software', + 'type': 'Ascii' + }, + 306: { + 'name': 'DateTime', + 'type': 'Ascii' + }, + 315: { + 'name': 'Artist', + 'type': 'Ascii' + }, + 316: { + 'name': 'HostComputer', + 'type': 'Ascii' + }, + 317: { + 'name': 'Predictor', + 'type': 'Short' + }, + 318: { + 'name': 'WhitePoint', + 'type': 'Rational' + }, + 319: { + 'name': 'PrimaryChromaticities', + 'type': 'Rational' + }, + 320: { + 'name': 'ColorMap', + 'type': 'Short' + }, + 321: { + 'name': 'HalftoneHints', + 'type': 'Short' + }, + 322: { + 'name': 'TileWidth', + 'type': 'Short' + }, + 323: { + 'name': 'TileLength', + 'type': 'Short' + }, + 324: { + 'name': 'TileOffsets', + 'type': 'Short' + }, + 325: { + 'name': 'TileByteCounts', + 'type': 'Short' + }, + 330: { + 'name': 'SubIFDs', + 'type': 'Long' + }, + 332: { + 'name': 'InkSet', + 'type': 'Short' + }, + 333: { + 'name': 'InkNames', + 'type': 'Ascii' + }, + 334: { + 'name': 'NumberOfInks', + 'type': 'Short' + }, + 336: { + 'name': 'DotRange', + 'type': 'Byte' + }, + 337: { + 'name': 'TargetPrinter', + 'type': 'Ascii' + }, + 338: { + 'name': 'ExtraSamples', + 'type': 'Short' + }, + 339: { + 'name': 'SampleFormat', + 'type': 'Short' + }, + 340: { + 'name': 'SMinSampleValue', + 'type': 'Short' + }, + 341: { + 'name': 'SMaxSampleValue', + 'type': 'Short' + }, + 342: { + 'name': 'TransferRange', + 'type': 'Short' + }, + 343: { + 'name': 'ClipPath', + 'type': 'Byte' + }, + 344: { + 'name': 'XClipPathUnits', + 'type': 'Long' + }, + 345: { + 'name': 'YClipPathUnits', + 'type': 'Long' + }, + 346: { + 'name': 'Indexed', + 'type': 'Short' + }, + 347: { + 'name': 'JPEGTables', + 'type': 'Undefined' + }, + 351: { + 'name': 'OPIProxy', + 'type': 'Short' + }, + 512: { + 'name': 'JPEGProc', + 'type': 'Long' + }, + 513: { + 'name': 'JPEGInterchangeFormat', + 'type': 'Long' + }, + 514: { + 'name': 'JPEGInterchangeFormatLength', + 'type': 'Long' + }, + 515: { + 'name': 'JPEGRestartInterval', + 'type': 'Short' + }, + 517: { + 'name': 'JPEGLosslessPredictors', + 'type': 'Short' + }, + 518: { + 'name': 'JPEGPointTransforms', + 'type': 'Short' + }, + 519: { + 'name': 'JPEGQTables', + 'type': 'Long' + }, + 520: { + 'name': 'JPEGDCTables', + 'type': 'Long' + }, + 521: { + 'name': 'JPEGACTables', + 'type': 'Long' + }, + 529: { + 'name': 'YCbCrCoefficients', + 'type': 'Rational' + }, + 530: { + 'name': 'YCbCrSubSampling', + 'type': 'Short' + }, + 531: { + 'name': 'YCbCrPositioning', + 'type': 'Short' + }, + 532: { + 'name': 'ReferenceBlackWhite', + 'type': 'Rational' + }, + 700: { + 'name': 'XMLPacket', + 'type': 'Byte' + }, + 18246: { + 'name': 'Rating', + 'type': 'Short' + }, + 18249: { + 'name': 'RatingPercent', + 'type': 'Short' + }, + 32781: { + 'name': 'ImageID', + 'type': 'Ascii' + }, + 33421: { + 'name': 'CFARepeatPatternDim', + 'type': 'Short' + }, + 33422: { + 'name': 'CFAPattern', + 'type': 'Byte' + }, + 33423: { + 'name': 'BatteryLevel', + 'type': 'Rational' + }, + 33432: { + 'name': 'Copyright', + 'type': 'Ascii' + }, + 33434: { + 'name': 'ExposureTime', + 'type': 'Rational' + }, + 34377: { + 'name': 'ImageResources', + 'type': 'Byte' + }, + 34665: { + 'name': 'ExifTag', + 'type': 'Long' + }, + 34675: { + 'name': 'InterColorProfile', + 'type': 'Undefined' + }, + 34853: { + 'name': 'GPSTag', + 'type': 'Long' + }, + 34857: { + 'name': 'Interlace', + 'type': 'Short' + }, + 34858: { + 'name': 'TimeZoneOffset', + 'type': 'Long' + }, + 34859: { + 'name': 'SelfTimerMode', + 'type': 'Short' + }, + 37387: { + 'name': 'FlashEnergy', + 'type': 'Rational' + }, + 37388: { + 'name': 'SpatialFrequencyResponse', + 'type': 'Undefined' + }, + 37389: { + 'name': 'Noise', + 'type': 'Undefined' + }, + 37390: { + 'name': 'FocalPlaneXResolution', + 'type': 'Rational' + }, + 37391: { + 'name': 'FocalPlaneYResolution', + 'type': 'Rational' + }, + 37392: { + 'name': 'FocalPlaneResolutionUnit', + 'type': 'Short' + }, + 37393: { + 'name': 'ImageNumber', + 'type': 'Long' + }, + 37394: { + 'name': 'SecurityClassification', + 'type': 'Ascii' + }, + 37395: { + 'name': 'ImageHistory', + 'type': 'Ascii' + }, + 37397: { + 'name': 'ExposureIndex', + 'type': 'Rational' + }, + 37398: { + 'name': 'TIFFEPStandardID', + 'type': 'Byte' + }, + 37399: { + 'name': 'SensingMethod', + 'type': 'Short' + }, + 40091: { + 'name': 'XPTitle', + 'type': 'Byte' + }, + 40092: { + 'name': 'XPComment', + 'type': 'Byte' + }, + 40093: { + 'name': 'XPAuthor', + 'type': 'Byte' + }, + 40094: { + 'name': 'XPKeywords', + 'type': 'Byte' + }, + 40095: { + 'name': 'XPSubject', + 'type': 'Byte' + }, + 50341: { + 'name': 'PrintImageMatching', + 'type': 'Undefined' + }, + 50706: { + 'name': 'DNGVersion', + 'type': 'Byte' + }, + 50707: { + 'name': 'DNGBackwardVersion', + 'type': 'Byte' + }, + 50708: { + 'name': 'UniqueCameraModel', + 'type': 'Ascii' + }, + 50709: { + 'name': 'LocalizedCameraModel', + 'type': 'Byte' + }, + 50710: { + 'name': 'CFAPlaneColor', + 'type': 'Byte' + }, + 50711: { + 'name': 'CFALayout', + 'type': 'Short' + }, + 50712: { + 'name': 'LinearizationTable', + 'type': 'Short' + }, + 50713: { + 'name': 'BlackLevelRepeatDim', + 'type': 'Short' + }, + 50714: { + 'name': 'BlackLevel', + 'type': 'Rational' + }, + 50715: { + 'name': 'BlackLevelDeltaH', + 'type': 'SRational' + }, + 50716: { + 'name': 'BlackLevelDeltaV', + 'type': 'SRational' + }, + 50717: { + 'name': 'WhiteLevel', + 'type': 'Short' + }, + 50718: { + 'name': 'DefaultScale', + 'type': 'Rational' + }, + 50719: { + 'name': 'DefaultCropOrigin', + 'type': 'Short' + }, + 50720: { + 'name': 'DefaultCropSize', + 'type': 'Short' + }, + 50721: { + 'name': 'ColorMatrix1', + 'type': 'SRational' + }, + 50722: { + 'name': 'ColorMatrix2', + 'type': 'SRational' + }, + 50723: { + 'name': 'CameraCalibration1', + 'type': 'SRational' + }, + 50724: { + 'name': 'CameraCalibration2', + 'type': 'SRational' + }, + 50725: { + 'name': 'ReductionMatrix1', + 'type': 'SRational' + }, + 50726: { + 'name': 'ReductionMatrix2', + 'type': 'SRational' + }, + 50727: { + 'name': 'AnalogBalance', + 'type': 'Rational' + }, + 50728: { + 'name': 'AsShotNeutral', + 'type': 'Short' + }, + 50729: { + 'name': 'AsShotWhiteXY', + 'type': 'Rational' + }, + 50730: { + 'name': 'BaselineExposure', + 'type': 'SRational' + }, + 50731: { + 'name': 'BaselineNoise', + 'type': 'Rational' + }, + 50732: { + 'name': 'BaselineSharpness', + 'type': 'Rational' + }, + 50733: { + 'name': 'BayerGreenSplit', + 'type': 'Long' + }, + 50734: { + 'name': 'LinearResponseLimit', + 'type': 'Rational' + }, + 50735: { + 'name': 'CameraSerialNumber', + 'type': 'Ascii' + }, + 50736: { + 'name': 'LensInfo', + 'type': 'Rational' + }, + 50737: { + 'name': 'ChromaBlurRadius', + 'type': 'Rational' + }, + 50738: { + 'name': 'AntiAliasStrength', + 'type': 'Rational' + }, + 50739: { + 'name': 'ShadowScale', + 'type': 'SRational' + }, + 50740: { + 'name': 'DNGPrivateData', + 'type': 'Byte' + }, + 50741: { + 'name': 'MakerNoteSafety', + 'type': 'Short' + }, + 50778: { + 'name': 'CalibrationIlluminant1', + 'type': 'Short' + }, + 50779: { + 'name': 'CalibrationIlluminant2', + 'type': 'Short' + }, + 50780: { + 'name': 'BestQualityScale', + 'type': 'Rational' + }, + 50781: { + 'name': 'RawDataUniqueID', + 'type': 'Byte' + }, + 50827: { + 'name': 'OriginalRawFileName', + 'type': 'Byte' + }, + 50828: { + 'name': 'OriginalRawFileData', + 'type': 'Undefined' + }, + 50829: { + 'name': 'ActiveArea', + 'type': 'Short' + }, + 50830: { + 'name': 'MaskedAreas', + 'type': 'Short' + }, + 50831: { + 'name': 'AsShotICCProfile', + 'type': 'Undefined' + }, + 50832: { + 'name': 'AsShotPreProfileMatrix', + 'type': 'SRational' + }, + 50833: { + 'name': 'CurrentICCProfile', + 'type': 'Undefined' + }, + 50834: { + 'name': 'CurrentPreProfileMatrix', + 'type': 'SRational' + }, + 50879: { + 'name': 'ColorimetricReference', + 'type': 'Short' + }, + 50931: { + 'name': 'CameraCalibrationSignature', + 'type': 'Byte' + }, + 50932: { + 'name': 'ProfileCalibrationSignature', + 'type': 'Byte' + }, + 50934: { + 'name': 'AsShotProfileName', + 'type': 'Byte' + }, + 50935: { + 'name': 'NoiseReductionApplied', + 'type': 'Rational' + }, + 50936: { + 'name': 'ProfileName', + 'type': 'Byte' + }, + 50937: { + 'name': 'ProfileHueSatMapDims', + 'type': 'Long' + }, + 50938: { + 'name': 'ProfileHueSatMapData1', + 'type': 'Float' + }, + 50939: { + 'name': 'ProfileHueSatMapData2', + 'type': 'Float' + }, + 50940: { + 'name': 'ProfileToneCurve', + 'type': 'Float' + }, + 50941: { + 'name': 'ProfileEmbedPolicy', + 'type': 'Long' + }, + 50942: { + 'name': 'ProfileCopyright', + 'type': 'Byte' + }, + 50964: { + 'name': 'ForwardMatrix1', + 'type': 'SRational' + }, + 50965: { + 'name': 'ForwardMatrix2', + 'type': 'SRational' + }, + 50966: { + 'name': 'PreviewApplicationName', + 'type': 'Byte' + }, + 50967: { + 'name': 'PreviewApplicationVersion', + 'type': 'Byte' + }, + 50968: { + 'name': 'PreviewSettingsName', + 'type': 'Byte' + }, + 50969: { + 'name': 'PreviewSettingsDigest', + 'type': 'Byte' + }, + 50970: { + 'name': 'PreviewColorSpace', + 'type': 'Long' + }, + 50971: { + 'name': 'PreviewDateTime', + 'type': 'Ascii' + }, + 50972: { + 'name': 'RawImageDigest', + 'type': 'Undefined' + }, + 50973: { + 'name': 'OriginalRawFileDigest', + 'type': 'Undefined' + }, + 50974: { + 'name': 'SubTileBlockSize', + 'type': 'Long' + }, + 50975: { + 'name': 'RowInterleaveFactor', + 'type': 'Long' + }, + 50981: { + 'name': 'ProfileLookTableDims', + 'type': 'Long' + }, + 50982: { + 'name': 'ProfileLookTableData', + 'type': 'Float' + }, + 51008: { + 'name': 'OpcodeList1', + 'type': 'Undefined' + }, + 51009: { + 'name': 'OpcodeList2', + 'type': 'Undefined' + }, + 51022: { + 'name': 'OpcodeList3', + 'type': 'Undefined' + } + }, + 'Exif': { + 33434: { + 'name': 'ExposureTime', + 'type': 'Rational' + }, + 33437: { + 'name': 'FNumber', + 'type': 'Rational' + }, + 34850: { + 'name': 'ExposureProgram', + 'type': 'Short' + }, + 34852: { + 'name': 'SpectralSensitivity', + 'type': 'Ascii' + }, + 34855: { + 'name': 'ISOSpeedRatings', + 'type': 'Short' + }, + 34856: { + 'name': 'OECF', + 'type': 'Undefined' + }, + 34864: { + 'name': 'SensitivityType', + 'type': 'Short' + }, + 34865: { + 'name': 'StandardOutputSensitivity', + 'type': 'Long' + }, + 34866: { + 'name': 'RecommendedExposureIndex', + 'type': 'Long' + }, + 34867: { + 'name': 'ISOSpeed', + 'type': 'Long' + }, + 34868: { + 'name': 'ISOSpeedLatitudeyyy', + 'type': 'Long' + }, + 34869: { + 'name': 'ISOSpeedLatitudezzz', + 'type': 'Long' + }, + 36864: { + 'name': 'ExifVersion', + 'type': 'Undefined' + }, + 36867: { + 'name': 'DateTimeOriginal', + 'type': 'Ascii' + }, + 36868: { + 'name': 'DateTimeDigitized', + 'type': 'Ascii' + }, + 37121: { + 'name': 'ComponentsConfiguration', + 'type': 'Undefined' + }, + 37122: { + 'name': 'CompressedBitsPerPixel', + 'type': 'Rational' + }, + 37377: { + 'name': 'ShutterSpeedValue', + 'type': 'SRational' + }, + 37378: { + 'name': 'ApertureValue', + 'type': 'Rational' + }, + 37379: { + 'name': 'BrightnessValue', + 'type': 'SRational' + }, + 37380: { + 'name': 'ExposureBiasValue', + 'type': 'SRational' + }, + 37381: { + 'name': 'MaxApertureValue', + 'type': 'Rational' + }, + 37382: { + 'name': 'SubjectDistance', + 'type': 'Rational' + }, + 37383: { + 'name': 'MeteringMode', + 'type': 'Short' + }, + 37384: { + 'name': 'LightSource', + 'type': 'Short' + }, + 37385: { + 'name': 'Flash', + 'type': 'Short' + }, + 37386: { + 'name': 'FocalLength', + 'type': 'Rational' + }, + 37396: { + 'name': 'SubjectArea', + 'type': 'Short' + }, + 37500: { + 'name': 'MakerNote', + 'type': 'Undefined' + }, + 37510: { + 'name': 'UserComment', + 'type': 'Ascii' + }, + 37520: { + 'name': 'SubSecTime', + 'type': 'Ascii' + }, + 37521: { + 'name': 'SubSecTimeOriginal', + 'type': 'Ascii' + }, + 37522: { + 'name': 'SubSecTimeDigitized', + 'type': 'Ascii' + }, + 40960: { + 'name': 'FlashpixVersion', + 'type': 'Undefined' + }, + 40961: { + 'name': 'ColorSpace', + 'type': 'Short' + }, + 40962: { + 'name': 'PixelXDimension', + 'type': 'Long' + }, + 40963: { + 'name': 'PixelYDimension', + 'type': 'Long' + }, + 40964: { + 'name': 'RelatedSoundFile', + 'type': 'Ascii' + }, + 40965: { + 'name': 'InteroperabilityTag', + 'type': 'Long' + }, + 41483: { + 'name': 'FlashEnergy', + 'type': 'Rational' + }, + 41484: { + 'name': 'SpatialFrequencyResponse', + 'type': 'Undefined' + }, + 41486: { + 'name': 'FocalPlaneXResolution', + 'type': 'Rational' + }, + 41487: { + 'name': 'FocalPlaneYResolution', + 'type': 'Rational' + }, + 41488: { + 'name': 'FocalPlaneResolutionUnit', + 'type': 'Short' + }, + 41492: { + 'name': 'SubjectLocation', + 'type': 'Short' + }, + 41493: { + 'name': 'ExposureIndex', + 'type': 'Rational' + }, + 41495: { + 'name': 'SensingMethod', + 'type': 'Short' + }, + 41728: { + 'name': 'FileSource', + 'type': 'Undefined' + }, + 41729: { + 'name': 'SceneType', + 'type': 'Undefined' + }, + 41730: { + 'name': 'CFAPattern', + 'type': 'Undefined' + }, + 41985: { + 'name': 'CustomRendered', + 'type': 'Short' + }, + 41986: { + 'name': 'ExposureMode', + 'type': 'Short' + }, + 41987: { + 'name': 'WhiteBalance', + 'type': 'Short' + }, + 41988: { + 'name': 'DigitalZoomRatio', + 'type': 'Rational' + }, + 41989: { + 'name': 'FocalLengthIn35mmFilm', + 'type': 'Short' + }, + 41990: { + 'name': 'SceneCaptureType', + 'type': 'Short' + }, + 41991: { + 'name': 'GainControl', + 'type': 'Short' + }, + 41992: { + 'name': 'Contrast', + 'type': 'Short' + }, + 41993: { + 'name': 'Saturation', + 'type': 'Short' + }, + 41994: { + 'name': 'Sharpness', + 'type': 'Short' + }, + 41995: { + 'name': 'DeviceSettingDescription', + 'type': 'Undefined' + }, + 41996: { + 'name': 'SubjectDistanceRange', + 'type': 'Short' + }, + 42016: { + 'name': 'ImageUniqueID', + 'type': 'Ascii' + }, + 42032: { + 'name': 'CameraOwnerName', + 'type': 'Ascii' + }, + 42033: { + 'name': 'BodySerialNumber', + 'type': 'Ascii' + }, + 42034: { + 'name': 'LensSpecification', + 'type': 'Rational' + }, + 42035: { + 'name': 'LensMake', + 'type': 'Ascii' + }, + 42036: { + 'name': 'LensModel', + 'type': 'Ascii' + }, + 42037: { + 'name': 'LensSerialNumber', + 'type': 'Ascii' + }, + 42240: { + 'name': 'Gamma', + 'type': 'Rational' + } + }, + 'GPS': { + 0: { + 'name': 'GPSVersionID', + 'type': 'Byte' + }, + 1: { + 'name': 'GPSLatitudeRef', + 'type': 'Ascii' + }, + 2: { + 'name': 'GPSLatitude', + 'type': 'Rational' + }, + 3: { + 'name': 'GPSLongitudeRef', + 'type': 'Ascii' + }, + 4: { + 'name': 'GPSLongitude', + 'type': 'Rational' + }, + 5: { + 'name': 'GPSAltitudeRef', + 'type': 'Byte' + }, + 6: { + 'name': 'GPSAltitude', + 'type': 'Rational' + }, + 7: { + 'name': 'GPSTimeStamp', + 'type': 'Rational' + }, + 8: { + 'name': 'GPSSatellites', + 'type': 'Ascii' + }, + 9: { + 'name': 'GPSStatus', + 'type': 'Ascii' + }, + 10: { + 'name': 'GPSMeasureMode', + 'type': 'Ascii' + }, + 11: { + 'name': 'GPSDOP', + 'type': 'Rational' + }, + 12: { + 'name': 'GPSSpeedRef', + 'type': 'Ascii' + }, + 13: { + 'name': 'GPSSpeed', + 'type': 'Rational' + }, + 14: { + 'name': 'GPSTrackRef', + 'type': 'Ascii' + }, + 15: { + 'name': 'GPSTrack', + 'type': 'Rational' + }, + 16: { + 'name': 'GPSImgDirectionRef', + 'type': 'Ascii' + }, + 17: { + 'name': 'GPSImgDirection', + 'type': 'Rational' + }, + 18: { + 'name': 'GPSMapDatum', + 'type': 'Ascii' + }, + 19: { + 'name': 'GPSDestLatitudeRef', + 'type': 'Ascii' + }, + 20: { + 'name': 'GPSDestLatitude', + 'type': 'Rational' + }, + 21: { + 'name': 'GPSDestLongitudeRef', + 'type': 'Ascii' + }, + 22: { + 'name': 'GPSDestLongitude', + 'type': 'Rational' + }, + 23: { + 'name': 'GPSDestBearingRef', + 'type': 'Ascii' + }, + 24: { + 'name': 'GPSDestBearing', + 'type': 'Rational' + }, + 25: { + 'name': 'GPSDestDistanceRef', + 'type': 'Ascii' + }, + 26: { + 'name': 'GPSDestDistance', + 'type': 'Rational' + }, + 27: { + 'name': 'GPSProcessingMethod', + 'type': 'Undefined' + }, + 28: { + 'name': 'GPSAreaInformation', + 'type': 'Undefined' + }, + 29: { + 'name': 'GPSDateStamp', + 'type': 'Ascii' + }, + 30: { + 'name': 'GPSDifferential', + 'type': 'Short' + }, + 31: { + 'name': 'GPSHPositioningError', + 'type': 'Rational' + } + }, + 'Interop': { + 1: { + 'name': 'InteroperabilityIndex', + 'type': 'Ascii' + } + }, + }; + TAGS["0th"] = TAGS["Image"]; + TAGS["1st"] = TAGS["Image"]; + that.TAGS = TAGS; + + + that.ImageIFD = { + ProcessingSoftware:11, + NewSubfileType:254, + SubfileType:255, + ImageWidth:256, + ImageLength:257, + BitsPerSample:258, + Compression:259, + PhotometricInterpretation:262, + Threshholding:263, + CellWidth:264, + CellLength:265, + FillOrder:266, + DocumentName:269, + ImageDescription:270, + Make:271, + Model:272, + StripOffsets:273, + Orientation:274, + SamplesPerPixel:277, + RowsPerStrip:278, + StripByteCounts:279, + XResolution:282, + YResolution:283, + PlanarConfiguration:284, + GrayResponseUnit:290, + GrayResponseCurve:291, + T4Options:292, + T6Options:293, + ResolutionUnit:296, + TransferFunction:301, + Software:305, + DateTime:306, + Artist:315, + HostComputer:316, + Predictor:317, + WhitePoint:318, + PrimaryChromaticities:319, + ColorMap:320, + HalftoneHints:321, + TileWidth:322, + TileLength:323, + TileOffsets:324, + TileByteCounts:325, + SubIFDs:330, + InkSet:332, + InkNames:333, + NumberOfInks:334, + DotRange:336, + TargetPrinter:337, + ExtraSamples:338, + SampleFormat:339, + SMinSampleValue:340, + SMaxSampleValue:341, + TransferRange:342, + ClipPath:343, + XClipPathUnits:344, + YClipPathUnits:345, + Indexed:346, + JPEGTables:347, + OPIProxy:351, + JPEGProc:512, + JPEGInterchangeFormat:513, + JPEGInterchangeFormatLength:514, + JPEGRestartInterval:515, + JPEGLosslessPredictors:517, + JPEGPointTransforms:518, + JPEGQTables:519, + JPEGDCTables:520, + JPEGACTables:521, + YCbCrCoefficients:529, + YCbCrSubSampling:530, + YCbCrPositioning:531, + ReferenceBlackWhite:532, + XMLPacket:700, + Rating:18246, + RatingPercent:18249, + ImageID:32781, + CFARepeatPatternDim:33421, + CFAPattern:33422, + BatteryLevel:33423, + Copyright:33432, + ExposureTime:33434, + ImageResources:34377, + ExifTag:34665, + InterColorProfile:34675, + GPSTag:34853, + Interlace:34857, + TimeZoneOffset:34858, + SelfTimerMode:34859, + FlashEnergy:37387, + SpatialFrequencyResponse:37388, + Noise:37389, + FocalPlaneXResolution:37390, + FocalPlaneYResolution:37391, + FocalPlaneResolutionUnit:37392, + ImageNumber:37393, + SecurityClassification:37394, + ImageHistory:37395, + ExposureIndex:37397, + TIFFEPStandardID:37398, + SensingMethod:37399, + XPTitle:40091, + XPComment:40092, + XPAuthor:40093, + XPKeywords:40094, + XPSubject:40095, + PrintImageMatching:50341, + DNGVersion:50706, + DNGBackwardVersion:50707, + UniqueCameraModel:50708, + LocalizedCameraModel:50709, + CFAPlaneColor:50710, + CFALayout:50711, + LinearizationTable:50712, + BlackLevelRepeatDim:50713, + BlackLevel:50714, + BlackLevelDeltaH:50715, + BlackLevelDeltaV:50716, + WhiteLevel:50717, + DefaultScale:50718, + DefaultCropOrigin:50719, + DefaultCropSize:50720, + ColorMatrix1:50721, + ColorMatrix2:50722, + CameraCalibration1:50723, + CameraCalibration2:50724, + ReductionMatrix1:50725, + ReductionMatrix2:50726, + AnalogBalance:50727, + AsShotNeutral:50728, + AsShotWhiteXY:50729, + BaselineExposure:50730, + BaselineNoise:50731, + BaselineSharpness:50732, + BayerGreenSplit:50733, + LinearResponseLimit:50734, + CameraSerialNumber:50735, + LensInfo:50736, + ChromaBlurRadius:50737, + AntiAliasStrength:50738, + ShadowScale:50739, + DNGPrivateData:50740, + MakerNoteSafety:50741, + CalibrationIlluminant1:50778, + CalibrationIlluminant2:50779, + BestQualityScale:50780, + RawDataUniqueID:50781, + OriginalRawFileName:50827, + OriginalRawFileData:50828, + ActiveArea:50829, + MaskedAreas:50830, + AsShotICCProfile:50831, + AsShotPreProfileMatrix:50832, + CurrentICCProfile:50833, + CurrentPreProfileMatrix:50834, + ColorimetricReference:50879, + CameraCalibrationSignature:50931, + ProfileCalibrationSignature:50932, + AsShotProfileName:50934, + NoiseReductionApplied:50935, + ProfileName:50936, + ProfileHueSatMapDims:50937, + ProfileHueSatMapData1:50938, + ProfileHueSatMapData2:50939, + ProfileToneCurve:50940, + ProfileEmbedPolicy:50941, + ProfileCopyright:50942, + ForwardMatrix1:50964, + ForwardMatrix2:50965, + PreviewApplicationName:50966, + PreviewApplicationVersion:50967, + PreviewSettingsName:50968, + PreviewSettingsDigest:50969, + PreviewColorSpace:50970, + PreviewDateTime:50971, + RawImageDigest:50972, + OriginalRawFileDigest:50973, + SubTileBlockSize:50974, + RowInterleaveFactor:50975, + ProfileLookTableDims:50981, + ProfileLookTableData:50982, + OpcodeList1:51008, + OpcodeList2:51009, + OpcodeList3:51022, + NoiseProfile:51041, + }; + + + that.ExifIFD = { + ExposureTime:33434, + FNumber:33437, + ExposureProgram:34850, + SpectralSensitivity:34852, + ISOSpeedRatings:34855, + OECF:34856, + SensitivityType:34864, + StandardOutputSensitivity:34865, + RecommendedExposureIndex:34866, + ISOSpeed:34867, + ISOSpeedLatitudeyyy:34868, + ISOSpeedLatitudezzz:34869, + ExifVersion:36864, + DateTimeOriginal:36867, + DateTimeDigitized:36868, + ComponentsConfiguration:37121, + CompressedBitsPerPixel:37122, + ShutterSpeedValue:37377, + ApertureValue:37378, + BrightnessValue:37379, + ExposureBiasValue:37380, + MaxApertureValue:37381, + SubjectDistance:37382, + MeteringMode:37383, + LightSource:37384, + Flash:37385, + FocalLength:37386, + SubjectArea:37396, + MakerNote:37500, + UserComment:37510, + SubSecTime:37520, + SubSecTimeOriginal:37521, + SubSecTimeDigitized:37522, + FlashpixVersion:40960, + ColorSpace:40961, + PixelXDimension:40962, + PixelYDimension:40963, + RelatedSoundFile:40964, + InteroperabilityTag:40965, + FlashEnergy:41483, + SpatialFrequencyResponse:41484, + FocalPlaneXResolution:41486, + FocalPlaneYResolution:41487, + FocalPlaneResolutionUnit:41488, + SubjectLocation:41492, + ExposureIndex:41493, + SensingMethod:41495, + FileSource:41728, + SceneType:41729, + CFAPattern:41730, + CustomRendered:41985, + ExposureMode:41986, + WhiteBalance:41987, + DigitalZoomRatio:41988, + FocalLengthIn35mmFilm:41989, + SceneCaptureType:41990, + GainControl:41991, + Contrast:41992, + Saturation:41993, + Sharpness:41994, + DeviceSettingDescription:41995, + SubjectDistanceRange:41996, + ImageUniqueID:42016, + CameraOwnerName:42032, + BodySerialNumber:42033, + LensSpecification:42034, + LensMake:42035, + LensModel:42036, + LensSerialNumber:42037, + Gamma:42240, + }; + + + that.GPSIFD = { + GPSVersionID:0, + GPSLatitudeRef:1, + GPSLatitude:2, + GPSLongitudeRef:3, + GPSLongitude:4, + GPSAltitudeRef:5, + GPSAltitude:6, + GPSTimeStamp:7, + GPSSatellites:8, + GPSStatus:9, + GPSMeasureMode:10, + GPSDOP:11, + GPSSpeedRef:12, + GPSSpeed:13, + GPSTrackRef:14, + GPSTrack:15, + GPSImgDirectionRef:16, + GPSImgDirection:17, + GPSMapDatum:18, + GPSDestLatitudeRef:19, + GPSDestLatitude:20, + GPSDestLongitudeRef:21, + GPSDestLongitude:22, + GPSDestBearingRef:23, + GPSDestBearing:24, + GPSDestDistanceRef:25, + GPSDestDistance:26, + GPSProcessingMethod:27, + GPSAreaInformation:28, + GPSDateStamp:29, + GPSDifferential:30, + GPSHPositioningError:31, + }; + + + that.InteropIFD = { + InteroperabilityIndex:1, + }; + + that.GPSHelper = { + degToDmsRational:function (degFloat) { + var minFloat = degFloat % 1 * 60; + var secFloat = minFloat % 1 * 60; + var deg = Math.floor(degFloat); + var min = Math.floor(minFloat); + var sec = Math.round(secFloat * 100); + + return [[deg, 1], [min, 1], [sec, 100]]; + } + }; + + + if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = that; + } + exports.piexif = that; + } else { + window.piexif = that; + } + +})(); diff --git a/src/main/resources/static/js/plugins/fileinput/plugins/piexif.min.js b/src/main/resources/static/js/plugins/fileinput/plugins/piexif.min.js new file mode 100644 index 000000000..10d612457 --- /dev/null +++ b/src/main/resources/static/js/plugins/fileinput/plugins/piexif.min.js @@ -0,0 +1 @@ +!function(){"use strict";function e(e){return JSON.parse(JSON.stringify(e))}function t(e){for(var t=y(e);"ÿà"<=t[1].slice(0,2)&&t[1].slice(0,2)<="ÿï";)t=[t[0]].concat(t.slice(2));return t.join("")}function a(e){return s(">"+p("B",e.length),e)}function i(e){return s(">"+p("H",e.length),e)}function n(e){return s(">"+p("L",e.length),e)}function r(e,t,r){var o,l,m,y,c="",S="";if("Byte"==t)o=e.length,4>=o?S=a(e)+p("\x00",4-o):(S=s(">L",[r]),c=a(e));else if("Short"==t)o=e.length,2>=o?S=i(e)+p("\x00\x00",2-o):(S=s(">L",[r]),c=i(e));else if("Long"==t)o=e.length,1>=o?S=n(e):(S=s(">L",[r]),c=n(e));else if("Ascii"==t)l=e+"\x00",o=l.length,o>4?(S=s(">L",[r]),c=l):S=l+p("\x00",4-o);else if("Rational"==t){if("number"==typeof e[0])o=1,m=e[0],y=e[1],l=s(">L",[m])+s(">L",[y]);else{o=e.length,l="";for(var f=0;o>f;f++)m=e[f][0],y=e[f][1],l+=s(">L",[m])+s(">L",[y])}S=s(">L",[r]),c=l}else if("SRational"==t){if("number"==typeof e[0])o=1,m=e[0],y=e[1],l=s(">l",[m])+s(">l",[y]);else{o=e.length,l="";for(var f=0;o>f;f++)m=e[f][0],y=e[f][1],l+=s(">l",[m])+s(">l",[y])}S=s(">L",[r]),c=l}else"Undefined"==t&&(o=e.length,o>4?(S=s(">L",[r]),c=e):S=e+p("\x00",4-o));var h=s(">L",[o]);return[h,S,c]}function o(e,t,a){var i,n=8,o=Object.keys(e).length,l=s(">H",[o]);i=["0th","1st"].indexOf(t)>-1?2+12*o+4:2+12*o;var m,p="",y="";for(var m in e)if("string"==typeof m&&(m=parseInt(m)),!("0th"==t&&[34665,34853].indexOf(m)>-1||"Exif"==t&&40965==m||"1st"==t&&[513,514].indexOf(m)>-1)){var c=e[m],S=s(">H",[m]),f=u[t][m].type,h=s(">H",[g[f]]);"number"==typeof c&&(c=[c]);var d=n+i+a+y.length,P=r(c,f,d),C=P[0],R=P[1],L=P[2];p+=S+h+C+R,y+=L}return[l+p,y]}function l(e){var t,a;if("ÿØ"==e.slice(0,2))t=y(e),a=c(t),a?this.tiftag=a.slice(10):this.tiftag=null;else if(["II","MM"].indexOf(e.slice(0,2))>-1)this.tiftag=e;else{if("Exif"!=e.slice(0,4))throw"Given file is neither JPEG nor TIFF.";this.tiftag=e.slice(6)}}function s(e,t){if(!(t instanceof Array))throw"'pack' error. Got invalid type argument.";if(e.length-1!=t.length)throw"'pack' error. "+(e.length-1)+" marks, "+t.length+" elements.";var a;if("<"==e[0])a=!0;else{if(">"!=e[0])throw"";a=!1}for(var i="",n=1,r=null,o=null,l=null;o=e[n];){if("b"==o.toLowerCase()){if(r=t[n-1],"b"==o&&0>r&&(r+=256),r>255||0>r)throw"'pack' error.";l=String.fromCharCode(r)}else if("H"==o){if(r=t[n-1],r>65535||0>r)throw"'pack' error.";l=String.fromCharCode(Math.floor(r%65536/256))+String.fromCharCode(r%256),a&&(l=l.split("").reverse().join(""))}else{if("l"!=o.toLowerCase())throw"'pack' error.";if(r=t[n-1],"l"==o&&0>r&&(r+=4294967296),r>4294967295||0>r)throw"'pack' error.";l=String.fromCharCode(Math.floor(r/16777216))+String.fromCharCode(Math.floor(r%16777216/65536))+String.fromCharCode(Math.floor(r%65536/256))+String.fromCharCode(r%256),a&&(l=l.split("").reverse().join(""))}i+=l,n+=1}return i}function m(e,t){if("string"!=typeof t)throw"'unpack' error. Got invalid type argument.";for(var a=0,i=1;i"!=e[0])throw"'unpack' error.";n=!1}for(var r=[],o=0,l=1,s=null,m=null,p=null,y="";m=e[l];){if("b"==m.toLowerCase())p=1,y=t.slice(o,o+p),s=y.charCodeAt(0),"b"==m&&s>=128&&(s-=256);else if("H"==m)p=2,y=t.slice(o,o+p),n&&(y=y.split("").reverse().join("")),s=256*y.charCodeAt(0)+y.charCodeAt(1);else{if("l"!=m.toLowerCase())throw"'unpack' error. "+m;p=4,y=t.slice(o,o+p),n&&(y=y.split("").reverse().join("")),s=16777216*y.charCodeAt(0)+65536*y.charCodeAt(1)+256*y.charCodeAt(2)+y.charCodeAt(3),"l"==m&&s>=2147483648&&(s-=4294967296)}r.push(s),o+=p,l+=1}return r}function p(e,t){for(var a="",i=0;t>i;i++)a+=e;return a}function y(e){if("ÿØ"!=e.slice(0,2))throw"Given data isn't JPEG.";for(var t=2,a=["ÿØ"];;){if("ÿÚ"==e.slice(t,t+2)){a.push(e.slice(t));break}var i=m(">H",e.slice(t+2,t+4))[0],n=t+i+2;if(a.push(e.slice(t,n)),t=n,t>=e.length)throw"Wrong JPEG data."}return a}function c(e){for(var t,a=0;aH",[e.length+2])+e,n=y(t),r=S(n,i);return a&&(r="data:image/jpeg;base64,"+h(r)),r},f.load=function(e){var t;if("string"!=typeof e)throw"'load' gots invalid type argument.";if("ÿØ"==e.slice(0,2))t=e;else if("data:image/jpeg;base64,"==e.slice(0,23)||"data:image/jpg;base64,"==e.slice(0,22))t=d(e.split(",")[1]);else{if("Exif"!=e.slice(0,4))throw"'load' gots invalid file data.";t=e.slice(6)}var a={"0th":{},Exif:{},GPS:{},Interop:{},"1st":{},thumbnail:null},i=new l(t);if(null===i.tiftag)return a;"II"==i.tiftag.slice(0,2)?i.endian_mark="<":i.endian_mark=">";var n=m(i.endian_mark+"L",i.tiftag.slice(4,8))[0];a["0th"]=i.get_ifd(n,"0th");var r=a["0th"].first_ifd_pointer;if(delete a["0th"].first_ifd_pointer,34665 in a["0th"]&&(n=a["0th"][34665],a.Exif=i.get_ifd(n,"Exif")),34853 in a["0th"]&&(n=a["0th"][34853],a.GPS=i.get_ifd(n,"GPS")),40965 in a.Exif&&(n=a.Exif[40965],a.Interop=i.get_ifd(n,"Interop")),"\x00\x00\x00\x00"!=r&&(n=m(i.endian_mark+"L",r)[0],a["1st"]=i.get_ifd(n,"1st"),513 in a["1st"]&&514 in a["1st"])){var o=a["1st"][513]+a["1st"][514],s=i.tiftag.slice(a["1st"][513],o);a.thumbnail=s}return a},f.dump=function(a){var i,n,r,l,m,p=8,y=e(a),c="Exif\x00\x00MM\x00*\x00\x00\x00\b",S=!1,h=!1,d=!1,u=!1;i="0th"in y?y["0th"]:{},"Exif"in y&&Object.keys(y.Exif).length||"Interop"in y&&Object.keys(y.Interop).length?(i[34665]=1,S=!0,n=y.Exif,"Interop"in y&&Object.keys(y.Interop).length?(n[40965]=1,d=!0,r=y.Interop):Object.keys(n).indexOf(f.ExifIFD.InteroperabilityTag.toString())>-1&&delete n[40965]):Object.keys(i).indexOf(f.ImageIFD.ExifTag.toString())>-1&&delete i[34665],"GPS"in y&&Object.keys(y.GPS).length?(i[f.ImageIFD.GPSTag]=1,h=!0,l=y.GPS):Object.keys(i).indexOf(f.ImageIFD.GPSTag.toString())>-1&&delete i[f.ImageIFD.GPSTag],"1st"in y&&"thumbnail"in y&&null!=y.thumbnail&&(u=!0,y["1st"][513]=1,y["1st"][514]=1,m=y["1st"]);var P,C,R,L,x,I=o(i,"0th",0),D=I[0].length+12*S+12*h+4+I[1].length,G="",A=0,v="",b=0,T="",k=0,w="";if(S&&(P=o(n,"Exif",D),A=P[0].length+12*d+P[1].length),h&&(C=o(l,"GPS",D+A),v=C.join(""),b=v.length),d){var F=D+A+b;R=o(r,"Interop",F),T=R.join(""),k=T.length}if(u){var F=D+A+b+k;if(L=o(m,"1st",F),x=t(y.thumbnail),x.length>64e3)throw"Given thumbnail is too large. max 64kB"}var B="",E="",M="",O="\x00\x00\x00\x00";if(S){var N=p+D,U=s(">L",[N]),_=34665,H=s(">H",[_]),j=s(">H",[g.Long]),V=s(">L",[1]);B=H+j+V+U}if(h){var N=p+D+A,U=s(">L",[N]),_=34853,H=s(">H",[_]),j=s(">H",[g.Long]),V=s(">L",[1]);E=H+j+V+U}if(d){var N=p+D+A+b,U=s(">L",[N]),_=40965,H=s(">H",[_]),j=s(">H",[g.Long]),V=s(">L",[1]);M=H+j+V+U}if(u){var N=p+D+A+b+k;O=s(">L",[N]);var J=N+L[0].length+24+4+L[1].length,X="\x00\x00\x00\x00"+s(">L",[J]),z="\x00\x00\x00\x00"+s(">L",[x.length]);w=L[0]+X+z+"\x00\x00\x00\x00"+L[1]+x}var Y=I[0]+B+E+O+I[1];return S&&(G=P[0]+M+P[1]),c+Y+G+v+T+w},l.prototype={get_ifd:function(e,t){var a,i={},n=m(this.endian_mark+"H",this.tiftag.slice(e,e+2))[0],r=e+2;a=["0th","1st"].indexOf(t)>-1?"Image":t;for(var o=0;n>o;o++){e=r+12*o;var l=m(this.endian_mark+"H",this.tiftag.slice(e,e+2))[0],s=m(this.endian_mark+"H",this.tiftag.slice(e+2,e+4))[0],p=m(this.endian_mark+"L",this.tiftag.slice(e+4,e+8))[0],y=this.tiftag.slice(e+8,e+12),c=[s,p,y];l in u[a]&&(i[l]=this.convert_value(c))}return"0th"==t&&(e=r+12*n,i.first_ifd_pointer=this.tiftag.slice(e,e+4)),i},convert_value:function(e){var t,a=null,i=e[0],n=e[1],r=e[2];if(1==i)n>4?(t=m(this.endian_mark+"L",r)[0],a=m(this.endian_mark+p("B",n),this.tiftag.slice(t,t+n))):a=m(this.endian_mark+p("B",n),r.slice(0,n));else if(2==i)n>4?(t=m(this.endian_mark+"L",r)[0],a=this.tiftag.slice(t,t+n-1)):a=r.slice(0,n-1);else if(3==i)n>2?(t=m(this.endian_mark+"L",r)[0],a=m(this.endian_mark+p("H",n),this.tiftag.slice(t,t+2*n))):a=m(this.endian_mark+p("H",n),r.slice(0,2*n));else if(4==i)n>1?(t=m(this.endian_mark+"L",r)[0],a=m(this.endian_mark+p("L",n),this.tiftag.slice(t,t+4*n))):a=m(this.endian_mark+p("L",n),r);else if(5==i)if(t=m(this.endian_mark+"L",r)[0],n>1){a=[];for(var o=0;n>o;o++)a.push([m(this.endian_mark+"L",this.tiftag.slice(t+8*o,t+4+8*o))[0],m(this.endian_mark+"L",this.tiftag.slice(t+4+8*o,t+8+8*o))[0]])}else a=[m(this.endian_mark+"L",this.tiftag.slice(t,t+4))[0],m(this.endian_mark+"L",this.tiftag.slice(t+4,t+8))[0]];else if(7==i)n>4?(t=m(this.endian_mark+"L",r)[0],a=this.tiftag.slice(t,t+n)):a=r.slice(0,n);else{if(10!=i)throw"Exif might be wrong. Got incorrect value type to decode. type:"+i;if(t=m(this.endian_mark+"L",r)[0],n>1){a=[];for(var o=0;n>o;o++)a.push([m(this.endian_mark+"l",this.tiftag.slice(t+8*o,t+4+8*o))[0],m(this.endian_mark+"l",this.tiftag.slice(t+4+8*o,t+8+8*o))[0]])}else a=[m(this.endian_mark+"l",this.tiftag.slice(t,t+4))[0],m(this.endian_mark+"l",this.tiftag.slice(t+4,t+8))[0]]}return a instanceof Array&&1==a.length?a[0]:a}},"undefined"!=typeof window&&"function"==typeof window.btoa)var h=window.btoa;if("undefined"==typeof h)var h=function(e){for(var t,a,i,n,r,o,l,s="",m=0,p="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";m>2,r=(3&t)<<4|a>>4,o=(15&a)<<2|i>>6,l=63&i,isNaN(a)?o=l=64:isNaN(i)&&(l=64),s=s+p.charAt(n)+p.charAt(r)+p.charAt(o)+p.charAt(l);return s};if("undefined"!=typeof window&&"function"==typeof window.atob)var d=window.atob;if("undefined"==typeof d)var d=function(e){var t,a,i,n,r,o,l,s="",m=0,p="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";for(e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");m>4,a=(15&r)<<4|o>>2,i=(3&o)<<6|l,s+=String.fromCharCode(t),64!=o&&(s+=String.fromCharCode(a)),64!=l&&(s+=String.fromCharCode(i));return s};var g={Byte:1,Ascii:2,Short:3,Long:4,Rational:5,Undefined:7,SLong:9,SRational:10},u={Image:{11:{name:"ProcessingSoftware",type:"Ascii"},254:{name:"NewSubfileType",type:"Long"},255:{name:"SubfileType",type:"Short"},256:{name:"ImageWidth",type:"Long"},257:{name:"ImageLength",type:"Long"},258:{name:"BitsPerSample",type:"Short"},259:{name:"Compression",type:"Short"},262:{name:"PhotometricInterpretation",type:"Short"},263:{name:"Threshholding",type:"Short"},264:{name:"CellWidth",type:"Short"},265:{name:"CellLength",type:"Short"},266:{name:"FillOrder",type:"Short"},269:{name:"DocumentName",type:"Ascii"},270:{name:"ImageDescription",type:"Ascii"},271:{name:"Make",type:"Ascii"},272:{name:"Model",type:"Ascii"},273:{name:"StripOffsets",type:"Long"},274:{name:"Orientation",type:"Short"},277:{name:"SamplesPerPixel",type:"Short"},278:{name:"RowsPerStrip",type:"Long"},279:{name:"StripByteCounts",type:"Long"},282:{name:"XResolution",type:"Rational"},283:{name:"YResolution",type:"Rational"},284:{name:"PlanarConfiguration",type:"Short"},290:{name:"GrayResponseUnit",type:"Short"},291:{name:"GrayResponseCurve",type:"Short"},292:{name:"T4Options",type:"Long"},293:{name:"T6Options",type:"Long"},296:{name:"ResolutionUnit",type:"Short"},301:{name:"TransferFunction",type:"Short"},305:{name:"Software",type:"Ascii"},306:{name:"DateTime",type:"Ascii"},315:{name:"Artist",type:"Ascii"},316:{name:"HostComputer",type:"Ascii"},317:{name:"Predictor",type:"Short"},318:{name:"WhitePoint",type:"Rational"},319:{name:"PrimaryChromaticities",type:"Rational"},320:{name:"ColorMap",type:"Short"},321:{name:"HalftoneHints",type:"Short"},322:{name:"TileWidth",type:"Short"},323:{name:"TileLength",type:"Short"},324:{name:"TileOffsets",type:"Short"},325:{name:"TileByteCounts",type:"Short"},330:{name:"SubIFDs",type:"Long"},332:{name:"InkSet",type:"Short"},333:{name:"InkNames",type:"Ascii"},334:{name:"NumberOfInks",type:"Short"},336:{name:"DotRange",type:"Byte"},337:{name:"TargetPrinter",type:"Ascii"},338:{name:"ExtraSamples",type:"Short"},339:{name:"SampleFormat",type:"Short"},340:{name:"SMinSampleValue",type:"Short"},341:{name:"SMaxSampleValue",type:"Short"},342:{name:"TransferRange",type:"Short"},343:{name:"ClipPath",type:"Byte"},344:{name:"XClipPathUnits",type:"Long"},345:{name:"YClipPathUnits",type:"Long"},346:{name:"Indexed",type:"Short"},347:{name:"JPEGTables",type:"Undefined"},351:{name:"OPIProxy",type:"Short"},512:{name:"JPEGProc",type:"Long"},513:{name:"JPEGInterchangeFormat",type:"Long"},514:{name:"JPEGInterchangeFormatLength",type:"Long"},515:{name:"JPEGRestartInterval",type:"Short"},517:{name:"JPEGLosslessPredictors",type:"Short"},518:{name:"JPEGPointTransforms",type:"Short"},519:{name:"JPEGQTables",type:"Long"},520:{name:"JPEGDCTables",type:"Long"},521:{name:"JPEGACTables",type:"Long"},529:{name:"YCbCrCoefficients",type:"Rational"},530:{name:"YCbCrSubSampling",type:"Short"},531:{name:"YCbCrPositioning",type:"Short"},532:{name:"ReferenceBlackWhite",type:"Rational"},700:{name:"XMLPacket",type:"Byte"},18246:{name:"Rating",type:"Short"},18249:{name:"RatingPercent",type:"Short"},32781:{name:"ImageID",type:"Ascii"},33421:{name:"CFARepeatPatternDim",type:"Short"},33422:{name:"CFAPattern",type:"Byte"},33423:{name:"BatteryLevel",type:"Rational"},33432:{name:"Copyright",type:"Ascii"},33434:{name:"ExposureTime",type:"Rational"},34377:{name:"ImageResources",type:"Byte"},34665:{name:"ExifTag",type:"Long"},34675:{name:"InterColorProfile",type:"Undefined"},34853:{name:"GPSTag",type:"Long"},34857:{name:"Interlace",type:"Short"},34858:{name:"TimeZoneOffset",type:"Long"},34859:{name:"SelfTimerMode",type:"Short"},37387:{name:"FlashEnergy",type:"Rational"},37388:{name:"SpatialFrequencyResponse",type:"Undefined"},37389:{name:"Noise",type:"Undefined"},37390:{name:"FocalPlaneXResolution",type:"Rational"},37391:{name:"FocalPlaneYResolution",type:"Rational"},37392:{name:"FocalPlaneResolutionUnit",type:"Short"},37393:{name:"ImageNumber",type:"Long"},37394:{name:"SecurityClassification",type:"Ascii"},37395:{name:"ImageHistory",type:"Ascii"},37397:{name:"ExposureIndex",type:"Rational"},37398:{name:"TIFFEPStandardID",type:"Byte"},37399:{name:"SensingMethod",type:"Short"},40091:{name:"XPTitle",type:"Byte"},40092:{name:"XPComment",type:"Byte"},40093:{name:"XPAuthor",type:"Byte"},40094:{name:"XPKeywords",type:"Byte"},40095:{name:"XPSubject",type:"Byte"},50341:{name:"PrintImageMatching",type:"Undefined"},50706:{name:"DNGVersion",type:"Byte"},50707:{name:"DNGBackwardVersion",type:"Byte"},50708:{name:"UniqueCameraModel",type:"Ascii"},50709:{name:"LocalizedCameraModel",type:"Byte"},50710:{name:"CFAPlaneColor",type:"Byte"},50711:{name:"CFALayout",type:"Short"},50712:{name:"LinearizationTable",type:"Short"},50713:{name:"BlackLevelRepeatDim",type:"Short"},50714:{name:"BlackLevel",type:"Rational"},50715:{name:"BlackLevelDeltaH",type:"SRational"},50716:{name:"BlackLevelDeltaV",type:"SRational"},50717:{name:"WhiteLevel",type:"Short"},50718:{name:"DefaultScale",type:"Rational"},50719:{name:"DefaultCropOrigin",type:"Short"},50720:{name:"DefaultCropSize",type:"Short"},50721:{name:"ColorMatrix1",type:"SRational"},50722:{name:"ColorMatrix2",type:"SRational"},50723:{name:"CameraCalibration1",type:"SRational"},50724:{name:"CameraCalibration2",type:"SRational"},50725:{name:"ReductionMatrix1",type:"SRational"},50726:{name:"ReductionMatrix2",type:"SRational"},50727:{name:"AnalogBalance",type:"Rational"},50728:{name:"AsShotNeutral",type:"Short"},50729:{name:"AsShotWhiteXY",type:"Rational"},50730:{name:"BaselineExposure",type:"SRational"},50731:{name:"BaselineNoise",type:"Rational"},50732:{name:"BaselineSharpness",type:"Rational"},50733:{name:"BayerGreenSplit",type:"Long"},50734:{name:"LinearResponseLimit",type:"Rational"},50735:{name:"CameraSerialNumber",type:"Ascii"},50736:{name:"LensInfo",type:"Rational"},50737:{name:"ChromaBlurRadius",type:"Rational"},50738:{name:"AntiAliasStrength",type:"Rational"},50739:{name:"ShadowScale",type:"SRational"},50740:{name:"DNGPrivateData",type:"Byte"},50741:{name:"MakerNoteSafety",type:"Short"},50778:{name:"CalibrationIlluminant1",type:"Short"},50779:{name:"CalibrationIlluminant2",type:"Short"},50780:{name:"BestQualityScale",type:"Rational"},50781:{name:"RawDataUniqueID",type:"Byte"},50827:{name:"OriginalRawFileName",type:"Byte"},50828:{name:"OriginalRawFileData",type:"Undefined"},50829:{name:"ActiveArea",type:"Short"},50830:{name:"MaskedAreas",type:"Short"},50831:{name:"AsShotICCProfile",type:"Undefined"},50832:{name:"AsShotPreProfileMatrix",type:"SRational"},50833:{name:"CurrentICCProfile",type:"Undefined"},50834:{name:"CurrentPreProfileMatrix",type:"SRational"},50879:{name:"ColorimetricReference",type:"Short"},50931:{name:"CameraCalibrationSignature",type:"Byte"},50932:{name:"ProfileCalibrationSignature",type:"Byte"},50934:{name:"AsShotProfileName",type:"Byte"},50935:{name:"NoiseReductionApplied",type:"Rational"},50936:{name:"ProfileName",type:"Byte"},50937:{name:"ProfileHueSatMapDims",type:"Long"},50938:{name:"ProfileHueSatMapData1",type:"Float"},50939:{name:"ProfileHueSatMapData2",type:"Float"},50940:{name:"ProfileToneCurve",type:"Float"},50941:{name:"ProfileEmbedPolicy",type:"Long"},50942:{name:"ProfileCopyright",type:"Byte"},50964:{name:"ForwardMatrix1",type:"SRational"},50965:{name:"ForwardMatrix2",type:"SRational"},50966:{name:"PreviewApplicationName",type:"Byte"},50967:{name:"PreviewApplicationVersion",type:"Byte"},50968:{name:"PreviewSettingsName",type:"Byte"},50969:{name:"PreviewSettingsDigest",type:"Byte"},50970:{name:"PreviewColorSpace",type:"Long"},50971:{name:"PreviewDateTime",type:"Ascii"},50972:{name:"RawImageDigest",type:"Undefined"},50973:{name:"OriginalRawFileDigest",type:"Undefined"},50974:{name:"SubTileBlockSize",type:"Long"},50975:{name:"RowInterleaveFactor",type:"Long"},50981:{name:"ProfileLookTableDims",type:"Long"},50982:{name:"ProfileLookTableData",type:"Float"},51008:{name:"OpcodeList1",type:"Undefined"},51009:{name:"OpcodeList2",type:"Undefined"},51022:{name:"OpcodeList3",type:"Undefined"}},Exif:{33434:{name:"ExposureTime",type:"Rational"},33437:{name:"FNumber",type:"Rational"},34850:{name:"ExposureProgram",type:"Short"},34852:{name:"SpectralSensitivity",type:"Ascii"},34855:{name:"ISOSpeedRatings",type:"Short"},34856:{name:"OECF",type:"Undefined"},34864:{name:"SensitivityType",type:"Short"},34865:{name:"StandardOutputSensitivity",type:"Long"},34866:{name:"RecommendedExposureIndex",type:"Long"},34867:{name:"ISOSpeed",type:"Long"},34868:{name:"ISOSpeedLatitudeyyy",type:"Long"},34869:{name:"ISOSpeedLatitudezzz",type:"Long"},36864:{name:"ExifVersion",type:"Undefined"},36867:{name:"DateTimeOriginal",type:"Ascii"},36868:{name:"DateTimeDigitized",type:"Ascii"},37121:{name:"ComponentsConfiguration",type:"Undefined"},37122:{name:"CompressedBitsPerPixel",type:"Rational"},37377:{name:"ShutterSpeedValue",type:"SRational"},37378:{name:"ApertureValue",type:"Rational"},37379:{name:"BrightnessValue",type:"SRational"},37380:{name:"ExposureBiasValue",type:"SRational"},37381:{name:"MaxApertureValue",type:"Rational"},37382:{name:"SubjectDistance",type:"Rational"},37383:{name:"MeteringMode",type:"Short"},37384:{name:"LightSource",type:"Short"},37385:{name:"Flash",type:"Short"},37386:{name:"FocalLength",type:"Rational"},37396:{name:"SubjectArea",type:"Short"},37500:{name:"MakerNote",type:"Undefined"},37510:{name:"UserComment",type:"Ascii"},37520:{name:"SubSecTime",type:"Ascii"},37521:{name:"SubSecTimeOriginal",type:"Ascii"},37522:{name:"SubSecTimeDigitized",type:"Ascii"},40960:{name:"FlashpixVersion",type:"Undefined"},40961:{name:"ColorSpace",type:"Short"},40962:{name:"PixelXDimension",type:"Long"},40963:{name:"PixelYDimension",type:"Long"},40964:{name:"RelatedSoundFile",type:"Ascii"},40965:{name:"InteroperabilityTag",type:"Long"},41483:{name:"FlashEnergy",type:"Rational"},41484:{name:"SpatialFrequencyResponse",type:"Undefined"},41486:{name:"FocalPlaneXResolution",type:"Rational"},41487:{name:"FocalPlaneYResolution",type:"Rational"},41488:{name:"FocalPlaneResolutionUnit",type:"Short"},41492:{name:"SubjectLocation",type:"Short"},41493:{name:"ExposureIndex",type:"Rational"},41495:{name:"SensingMethod",type:"Short"},41728:{name:"FileSource",type:"Undefined"},41729:{name:"SceneType",type:"Undefined"},41730:{name:"CFAPattern",type:"Undefined"},41985:{name:"CustomRendered",type:"Short"},41986:{name:"ExposureMode",type:"Short"},41987:{name:"WhiteBalance",type:"Short"},41988:{name:"DigitalZoomRatio",type:"Rational"},41989:{name:"FocalLengthIn35mmFilm",type:"Short"},41990:{name:"SceneCaptureType",type:"Short"},41991:{name:"GainControl",type:"Short"},41992:{name:"Contrast",type:"Short"},41993:{name:"Saturation",type:"Short"},41994:{name:"Sharpness",type:"Short"},41995:{name:"DeviceSettingDescription",type:"Undefined"},41996:{name:"SubjectDistanceRange",type:"Short"},42016:{name:"ImageUniqueID",type:"Ascii"},42032:{name:"CameraOwnerName",type:"Ascii"},42033:{name:"BodySerialNumber",type:"Ascii"},42034:{name:"LensSpecification",type:"Rational"},42035:{name:"LensMake",type:"Ascii"},42036:{name:"LensModel",type:"Ascii"},42037:{name:"LensSerialNumber",type:"Ascii"},42240:{name:"Gamma",type:"Rational"}},GPS:{0:{name:"GPSVersionID",type:"Byte"},1:{name:"GPSLatitudeRef",type:"Ascii"},2:{name:"GPSLatitude",type:"Rational"},3:{name:"GPSLongitudeRef",type:"Ascii"},4:{name:"GPSLongitude",type:"Rational"},5:{name:"GPSAltitudeRef",type:"Byte"},6:{name:"GPSAltitude",type:"Rational"},7:{name:"GPSTimeStamp",type:"Rational"},8:{name:"GPSSatellites",type:"Ascii"},9:{name:"GPSStatus",type:"Ascii"},10:{name:"GPSMeasureMode",type:"Ascii"},11:{name:"GPSDOP",type:"Rational"},12:{name:"GPSSpeedRef",type:"Ascii"},13:{name:"GPSSpeed",type:"Rational"},14:{name:"GPSTrackRef",type:"Ascii"},15:{name:"GPSTrack",type:"Rational"},16:{name:"GPSImgDirectionRef",type:"Ascii"},17:{name:"GPSImgDirection",type:"Rational"},18:{name:"GPSMapDatum",type:"Ascii"},19:{name:"GPSDestLatitudeRef",type:"Ascii"},20:{name:"GPSDestLatitude",type:"Rational"},21:{name:"GPSDestLongitudeRef",type:"Ascii"},22:{name:"GPSDestLongitude",type:"Rational"},23:{name:"GPSDestBearingRef",type:"Ascii"},24:{name:"GPSDestBearing",type:"Rational"},25:{name:"GPSDestDistanceRef",type:"Ascii"},26:{name:"GPSDestDistance",type:"Rational"},27:{name:"GPSProcessingMethod",type:"Undefined"},28:{name:"GPSAreaInformation",type:"Undefined"},29:{name:"GPSDateStamp",type:"Ascii"},30:{name:"GPSDifferential",type:"Short"},31:{name:"GPSHPositioningError",type:"Rational"}},Interop:{1:{name:"InteroperabilityIndex",type:"Ascii"}}};u["0th"]=u.Image,u["1st"]=u.Image,f.TAGS=u,f.ImageIFD={ProcessingSoftware:11,NewSubfileType:254,SubfileType:255,ImageWidth:256,ImageLength:257,BitsPerSample:258,Compression:259,PhotometricInterpretation:262,Threshholding:263,CellWidth:264,CellLength:265,FillOrder:266,DocumentName:269,ImageDescription:270,Make:271,Model:272,StripOffsets:273,Orientation:274,SamplesPerPixel:277,RowsPerStrip:278,StripByteCounts:279,XResolution:282,YResolution:283,PlanarConfiguration:284,GrayResponseUnit:290,GrayResponseCurve:291,T4Options:292,T6Options:293,ResolutionUnit:296,TransferFunction:301,Software:305,DateTime:306,Artist:315,HostComputer:316,Predictor:317,WhitePoint:318,PrimaryChromaticities:319,ColorMap:320,HalftoneHints:321,TileWidth:322,TileLength:323,TileOffsets:324,TileByteCounts:325,SubIFDs:330,InkSet:332,InkNames:333,NumberOfInks:334,DotRange:336,TargetPrinter:337,ExtraSamples:338,SampleFormat:339,SMinSampleValue:340,SMaxSampleValue:341,TransferRange:342,ClipPath:343,XClipPathUnits:344,YClipPathUnits:345,Indexed:346,JPEGTables:347,OPIProxy:351,JPEGProc:512,JPEGInterchangeFormat:513,JPEGInterchangeFormatLength:514,JPEGRestartInterval:515,JPEGLosslessPredictors:517,JPEGPointTransforms:518,JPEGQTables:519,JPEGDCTables:520,JPEGACTables:521,YCbCrCoefficients:529,YCbCrSubSampling:530,YCbCrPositioning:531,ReferenceBlackWhite:532,XMLPacket:700,Rating:18246,RatingPercent:18249,ImageID:32781,CFARepeatPatternDim:33421,CFAPattern:33422,BatteryLevel:33423,Copyright:33432,ExposureTime:33434,ImageResources:34377,ExifTag:34665,InterColorProfile:34675,GPSTag:34853,Interlace:34857,TimeZoneOffset:34858,SelfTimerMode:34859,FlashEnergy:37387,SpatialFrequencyResponse:37388,Noise:37389,FocalPlaneXResolution:37390,FocalPlaneYResolution:37391,FocalPlaneResolutionUnit:37392,ImageNumber:37393,SecurityClassification:37394,ImageHistory:37395,ExposureIndex:37397,TIFFEPStandardID:37398,SensingMethod:37399,XPTitle:40091,XPComment:40092,XPAuthor:40093,XPKeywords:40094,XPSubject:40095,PrintImageMatching:50341,DNGVersion:50706,DNGBackwardVersion:50707,UniqueCameraModel:50708,LocalizedCameraModel:50709,CFAPlaneColor:50710,CFALayout:50711,LinearizationTable:50712,BlackLevelRepeatDim:50713,BlackLevel:50714,BlackLevelDeltaH:50715,BlackLevelDeltaV:50716,WhiteLevel:50717,DefaultScale:50718,DefaultCropOrigin:50719,DefaultCropSize:50720,ColorMatrix1:50721,ColorMatrix2:50722,CameraCalibration1:50723,CameraCalibration2:50724,ReductionMatrix1:50725,ReductionMatrix2:50726,AnalogBalance:50727,AsShotNeutral:50728,AsShotWhiteXY:50729,BaselineExposure:50730,BaselineNoise:50731,BaselineSharpness:50732,BayerGreenSplit:50733,LinearResponseLimit:50734,CameraSerialNumber:50735,LensInfo:50736,ChromaBlurRadius:50737,AntiAliasStrength:50738,ShadowScale:50739,DNGPrivateData:50740,MakerNoteSafety:50741,CalibrationIlluminant1:50778,CalibrationIlluminant2:50779,BestQualityScale:50780,RawDataUniqueID:50781,OriginalRawFileName:50827,OriginalRawFileData:50828,ActiveArea:50829,MaskedAreas:50830,AsShotICCProfile:50831,AsShotPreProfileMatrix:50832,CurrentICCProfile:50833,CurrentPreProfileMatrix:50834,ColorimetricReference:50879,CameraCalibrationSignature:50931,ProfileCalibrationSignature:50932,AsShotProfileName:50934,NoiseReductionApplied:50935,ProfileName:50936,ProfileHueSatMapDims:50937,ProfileHueSatMapData1:50938,ProfileHueSatMapData2:50939,ProfileToneCurve:50940,ProfileEmbedPolicy:50941,ProfileCopyright:50942,ForwardMatrix1:50964,ForwardMatrix2:50965,PreviewApplicationName:50966,PreviewApplicationVersion:50967,PreviewSettingsName:50968,PreviewSettingsDigest:50969,PreviewColorSpace:50970,PreviewDateTime:50971,RawImageDigest:50972,OriginalRawFileDigest:50973,SubTileBlockSize:50974,RowInterleaveFactor:50975,ProfileLookTableDims:50981,ProfileLookTableData:50982,OpcodeList1:51008,OpcodeList2:51009,OpcodeList3:51022,NoiseProfile:51041},f.ExifIFD={ExposureTime:33434,FNumber:33437,ExposureProgram:34850,SpectralSensitivity:34852,ISOSpeedRatings:34855,OECF:34856,SensitivityType:34864,StandardOutputSensitivity:34865,RecommendedExposureIndex:34866,ISOSpeed:34867,ISOSpeedLatitudeyyy:34868,ISOSpeedLatitudezzz:34869,ExifVersion:36864,DateTimeOriginal:36867,DateTimeDigitized:36868,ComponentsConfiguration:37121,CompressedBitsPerPixel:37122,ShutterSpeedValue:37377,ApertureValue:37378,BrightnessValue:37379,ExposureBiasValue:37380,MaxApertureValue:37381,SubjectDistance:37382,MeteringMode:37383,LightSource:37384,Flash:37385,FocalLength:37386,SubjectArea:37396,MakerNote:37500,UserComment:37510,SubSecTime:37520,SubSecTimeOriginal:37521,SubSecTimeDigitized:37522,FlashpixVersion:40960,ColorSpace:40961,PixelXDimension:40962,PixelYDimension:40963,RelatedSoundFile:40964,InteroperabilityTag:40965,FlashEnergy:41483,SpatialFrequencyResponse:41484,FocalPlaneXResolution:41486,FocalPlaneYResolution:41487,FocalPlaneResolutionUnit:41488,SubjectLocation:41492,ExposureIndex:41493,SensingMethod:41495,FileSource:41728,SceneType:41729,CFAPattern:41730,CustomRendered:41985,ExposureMode:41986,WhiteBalance:41987,DigitalZoomRatio:41988,FocalLengthIn35mmFilm:41989,SceneCaptureType:41990,GainControl:41991,Contrast:41992,Saturation:41993,Sharpness:41994,DeviceSettingDescription:41995,SubjectDistanceRange:41996,ImageUniqueID:42016,CameraOwnerName:42032,BodySerialNumber:42033,LensSpecification:42034,LensMake:42035,LensModel:42036,LensSerialNumber:42037,Gamma:42240},f.GPSIFD={GPSVersionID:0,GPSLatitudeRef:1,GPSLatitude:2,GPSLongitudeRef:3,GPSLongitude:4,GPSAltitudeRef:5,GPSAltitude:6,GPSTimeStamp:7,GPSSatellites:8,GPSStatus:9,GPSMeasureMode:10,GPSDOP:11,GPSSpeedRef:12,GPSSpeed:13,GPSTrackRef:14,GPSTrack:15,GPSImgDirectionRef:16,GPSImgDirection:17,GPSMapDatum:18,GPSDestLatitudeRef:19,GPSDestLatitude:20,GPSDestLongitudeRef:21,GPSDestLongitude:22,GPSDestBearingRef:23,GPSDestBearing:24,GPSDestDistanceRef:25,GPSDestDistance:26,GPSProcessingMethod:27,GPSAreaInformation:28,GPSDateStamp:29,GPSDifferential:30,GPSHPositioningError:31},f.InteropIFD={InteroperabilityIndex:1},f.GPSHelper={degToDmsRational:function(e){var t=e%1*60,a=t%1*60,i=Math.floor(e),n=Math.floor(t),r=Math.round(100*a);return[[i,1],[n,1],[r,100]]}},"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=f),exports.piexif=f):window.piexif=f}(); \ No newline at end of file diff --git a/src/main/resources/static/js/plugins/fileinput/plugins/purify.js b/src/main/resources/static/js/plugins/fileinput/plugins/purify.js new file mode 100644 index 000000000..c4bc4983d --- /dev/null +++ b/src/main/resources/static/js/plugins/fileinput/plugins/purify.js @@ -0,0 +1,812 @@ +;(function(factory) { + 'use strict'; + /* global window: false, define: false, module: false */ + var root = typeof window === 'undefined' ? null : window; + + if (typeof define === 'function' && define.amd) { + define(function(){ return factory(root); }); + } else if (typeof module !== 'undefined') { + module.exports = factory(root); + } else { + root.DOMPurify = factory(root); + } +}(function factory(window) { + 'use strict'; + + var DOMPurify = function(window) { + return factory(window); + }; + + /** + * Version label, exposed for easier checks + * if DOMPurify is up to date or not + */ + DOMPurify.version = '0.7.4'; + + if (!window || !window.document || window.document.nodeType !== 9) { + // not running in a browser, provide a factory function + // so that you can pass your own Window + DOMPurify.isSupported = false; + return DOMPurify; + } + + var document = window.document; + var originalDocument = document; + var DocumentFragment = window.DocumentFragment; + var HTMLTemplateElement = window.HTMLTemplateElement; + var NodeFilter = window.NodeFilter; + var NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap; + var Text = window.Text; + var Comment = window.Comment; + var DOMParser = window.DOMParser; + + // As per issue #47, the web-components registry is inherited by a + // new document created via createHTMLDocument. As per the spec + // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries) + // a new empty registry is used when creating a template contents owner + // document, so we use that as our parent document to ensure nothing + // is inherited. + if (typeof HTMLTemplateElement === 'function') { + var template = document.createElement('template'); + if (template.content && template.content.ownerDocument) { + document = template.content.ownerDocument; + } + } + var implementation = document.implementation; + var createNodeIterator = document.createNodeIterator; + var getElementsByTagName = document.getElementsByTagName; + var createDocumentFragment = document.createDocumentFragment; + var importNode = originalDocument.importNode; + + var hooks = {}; + + /** + * Expose whether this browser supports running the full DOMPurify. + */ + DOMPurify.isSupported = + typeof implementation.createHTMLDocument !== 'undefined' && + document.documentMode !== 9; + + /* Add properties to a lookup table */ + var _addToSet = function(set, array) { + var l = array.length; + while (l--) { + if (typeof array[l] === 'string') { + array[l] = array[l].toLowerCase(); + } + set[array[l]] = true; + } + return set; + }; + + /* Shallow clone an object */ + var _cloneObj = function(object) { + var newObject = {}; + var property; + for (property in object) { + if (object.hasOwnProperty(property)) { + newObject[property] = object[property]; + } + } + return newObject; + }; + + /** + * We consider the elements and attributes below to be safe. Ideally + * don't add any new ones but feel free to remove unwanted ones. + */ + + /* allowed element names */ + var ALLOWED_TAGS = null; + var DEFAULT_ALLOWED_TAGS = _addToSet({}, [ + + // HTML + 'a','abbr','acronym','address','area','article','aside','audio','b', + 'bdi','bdo','big','blink','blockquote','body','br','button','canvas', + 'caption','center','cite','code','col','colgroup','content','data', + 'datalist','dd','decorator','del','details','dfn','dir','div','dl','dt', + 'element','em','fieldset','figcaption','figure','font','footer','form', + 'h1','h2','h3','h4','h5','h6','head','header','hgroup','hr','html','i', + 'img','input','ins','kbd','label','legend','li','main','map','mark', + 'marquee','menu','menuitem','meter','nav','nobr','ol','optgroup', + 'option','output','p','pre','progress','q','rp','rt','ruby','s','samp', + 'section','select','shadow','small','source','spacer','span','strike', + 'strong','style','sub','summary','sup','table','tbody','td','template', + 'textarea','tfoot','th','thead','time','tr','track','tt','u','ul','var', + 'video','wbr', + + // SVG + 'svg','altglyph','altglyphdef','altglyphitem','animatecolor', + 'animatemotion','animatetransform','circle','clippath','defs','desc', + 'ellipse','filter','font','g','glyph','glyphref','hkern','image','line', + 'lineargradient','marker','mask','metadata','mpath','path','pattern', + 'polygon','polyline','radialgradient','rect','stop','switch','symbol', + 'text','textpath','title','tref','tspan','view','vkern', + + // SVG Filters + 'feBlend','feColorMatrix','feComponentTransfer','feComposite', + 'feConvolveMatrix','feDiffuseLighting','feDisplacementMap', + 'feFlood','feFuncA','feFuncB','feFuncG','feFuncR','feGaussianBlur', + 'feMerge','feMergeNode','feMorphology','feOffset', + 'feSpecularLighting','feTile','feTurbulence', + + //MathML + 'math','menclose','merror','mfenced','mfrac','mglyph','mi','mlabeledtr', + 'mmuliscripts','mn','mo','mover','mpadded','mphantom','mroot','mrow', + 'ms','mpspace','msqrt','mystyle','msub','msup','msubsup','mtable','mtd', + 'mtext','mtr','munder','munderover', + + //Text + '#text' + ]); + + /* Allowed attribute names */ + var ALLOWED_ATTR = null; + var DEFAULT_ALLOWED_ATTR = _addToSet({}, [ + + // HTML + 'accept','action','align','alt','autocomplete','background','bgcolor', + 'border','cellpadding','cellspacing','checked','cite','class','clear','color', + 'cols','colspan','coords','datetime','default','dir','disabled', + 'download','enctype','face','for','headers','height','hidden','high','href', + 'hreflang','id','ismap','label','lang','list','loop', 'low','max', + 'maxlength','media','method','min','multiple','name','noshade','novalidate', + 'nowrap','open','optimum','pattern','placeholder','poster','preload','pubdate', + 'radiogroup','readonly','rel','required','rev','reversed','rows', + 'rowspan','spellcheck','scope','selected','shape','size','span', + 'srclang','start','src','step','style','summary','tabindex','title', + 'type','usemap','valign','value','width','xmlns', + + // SVG + 'accent-height','accumulate','additivive','alignment-baseline', + 'ascent','attributename','attributetype','azimuth','basefrequency', + 'baseline-shift','begin','bias','by','clip','clip-path','clip-rule', + 'color','color-interpolation','color-interpolation-filters','color-profile', + 'color-rendering','cx','cy','d','dx','dy','diffuseconstant','direction', + 'display','divisor','dur','edgemode','elevation','end','fill','fill-opacity', + 'fill-rule','filter','flood-color','flood-opacity','font-family','font-size', + 'font-size-adjust','font-stretch','font-style','font-variant','font-weight', + 'fx', 'fy','g1','g2','glyph-name','glyphref','gradientunits','gradienttransform', + 'image-rendering','in','in2','k','k1','k2','k3','k4','kerning','keypoints', + 'keysplines','keytimes','lengthadjust','letter-spacing','kernelmatrix', + 'kernelunitlength','lighting-color','local','marker-end','marker-mid', + 'marker-start','markerheight','markerunits','markerwidth','maskcontentunits', + 'maskunits','max','mask','mode','min','numoctaves','offset','operator', + 'opacity','order','orient','orientation','origin','overflow','paint-order', + 'path','pathlength','patterncontentunits','patterntransform','patternunits', + 'points','preservealpha','r','rx','ry','radius','refx','refy','repeatcount', + 'repeatdur','restart','result','rotate','scale','seed','shape-rendering', + 'specularconstant','specularexponent','spreadmethod','stddeviation','stitchtiles', + 'stop-color','stop-opacity','stroke-dasharray','stroke-dashoffset','stroke-linecap', + 'stroke-linejoin','stroke-miterlimit','stroke-opacity','stroke','stroke-width', + 'surfacescale','targetx','targety','transform','text-anchor','text-decoration', + 'text-rendering','textlength','u1','u2','unicode','values','viewbox', + 'visibility','vert-adv-y','vert-origin-x','vert-origin-y','word-spacing', + 'wrap','writing-mode','xchannelselector','ychannelselector','x','x1','x2', + 'y','y1','y2','z','zoomandpan', + + // MathML + 'accent','accentunder','bevelled','close','columnsalign','columnlines', + 'columnspan','denomalign','depth','display','displaystyle','fence', + 'frame','largeop','length','linethickness','lspace','lquote', + 'mathbackground','mathcolor','mathsize','mathvariant','maxsize', + 'minsize','movablelimits','notation','numalign','open','rowalign', + 'rowlines','rowspacing','rowspan','rspace','rquote','scriptlevel', + 'scriptminsize','scriptsizemultiplier','selection','separator', + 'separators','stretchy','subscriptshift','supscriptshift','symmetric', + 'voffset', + + // XML + 'xlink:href','xml:id','xlink:title','xml:space','xmlns:xlink' + ]); + + /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */ + var FORBID_TAGS = null; + + /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */ + var FORBID_ATTR = null; + + /* Decide if custom data attributes are okay */ + var ALLOW_DATA_ATTR = true; + + /* Decide if unknown protocols are okay */ + var ALLOW_UNKNOWN_PROTOCOLS = false; + + /* Output should be safe for jQuery's $() factory? */ + var SAFE_FOR_JQUERY = false; + + /* Output should be safe for common template engines. + * This means, DOMPurify removes data attributes, mustaches and ERB + */ + var SAFE_FOR_TEMPLATES = false; + + /* Specify template detection regex for SAFE_FOR_TEMPLATES mode */ + var MUSTACHE_EXPR = /\{\{[\s\S]*|[\s\S]*\}\}/gm; + var ERB_EXPR = /<%[\s\S]*|[\s\S]*%>/gm; + + /* Decide if document with ... should be returned */ + var WHOLE_DOCUMENT = false; + + /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html string. + * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead + */ + var RETURN_DOM = false; + + /* Decide if a DOM `DocumentFragment` should be returned, instead of a html string */ + var RETURN_DOM_FRAGMENT = false; + + /* If `RETURN_DOM` or `RETURN_DOM_FRAGMENT` is enabled, decide if the returned DOM + * `Node` is imported into the current `Document`. If this flag is not enabled the + * `Node` will belong (its ownerDocument) to a fresh `HTMLDocument`, created by + * DOMPurify. */ + var RETURN_DOM_IMPORT = false; + + /* Output should be free from DOM clobbering attacks? */ + var SANITIZE_DOM = true; + + /* Keep element content when removing element? */ + var KEEP_CONTENT = true; + + /* Tags to ignore content of when KEEP_CONTENT is true */ + var FORBID_CONTENTS = _addToSet({}, [ + 'audio', 'head', 'math', 'script', 'style', 'svg', 'video' + ]); + + /* Tags that are safe for data: URIs */ + var DATA_URI_TAGS = _addToSet({}, [ + 'audio', 'video', 'img', 'source' + ]); + + /* Attributes safe for values like "javascript:" */ + var URI_SAFE_ATTRIBUTES = _addToSet({}, [ + 'alt','class','for','id','label','name','pattern','placeholder', + 'summary','title','value','style','xmlns' + ]); + + /* Keep a reference to config to pass to hooks */ + var CONFIG = null; + + /* Ideally, do not touch anything below this line */ + /* ______________________________________________ */ + + var formElement = document.createElement('form'); + + /** + * _parseConfig + * + * @param optional config literal + */ + var _parseConfig = function(cfg) { + /* Shield configuration object from tampering */ + if (typeof cfg !== 'object') { + cfg = {}; + } + + /* Set configuration parameters */ + ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? + _addToSet({}, cfg.ALLOWED_TAGS) : DEFAULT_ALLOWED_TAGS; + ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? + _addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR; + FORBID_TAGS = 'FORBID_TAGS' in cfg ? + _addToSet({}, cfg.FORBID_TAGS) : {}; + FORBID_ATTR = 'FORBID_ATTR' in cfg ? + _addToSet({}, cfg.FORBID_ATTR) : {}; + ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true + ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false + SAFE_FOR_JQUERY = cfg.SAFE_FOR_JQUERY || false; // Default false + SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false + WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false + RETURN_DOM = cfg.RETURN_DOM || false; // Default false + RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false + RETURN_DOM_IMPORT = cfg.RETURN_DOM_IMPORT || false; // Default false + SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true + KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true + + if (SAFE_FOR_TEMPLATES) { + ALLOW_DATA_ATTR = false; + } + + if (RETURN_DOM_FRAGMENT) { + RETURN_DOM = true; + } + + /* Merge configuration parameters */ + if (cfg.ADD_TAGS) { + if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) { + ALLOWED_TAGS = _cloneObj(ALLOWED_TAGS); + } + _addToSet(ALLOWED_TAGS, cfg.ADD_TAGS); + } + if (cfg.ADD_ATTR) { + if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) { + ALLOWED_ATTR = _cloneObj(ALLOWED_ATTR); + } + _addToSet(ALLOWED_ATTR, cfg.ADD_ATTR); + } + + /* Add #text in case KEEP_CONTENT is set to true */ + if (KEEP_CONTENT) { ALLOWED_TAGS['#text'] = true; } + + // Prevent further manipulation of configuration. + // Not available in IE8, Safari 5, etc. + if (Object && 'freeze' in Object) { Object.freeze(cfg); } + + CONFIG = cfg; + }; + + /** + * _forceRemove + * + * @param a DOM node + */ + var _forceRemove = function(node) { + try { + node.parentNode.removeChild(node); + } catch (e) { + node.outerHTML = ''; + } + }; + + /** + * _initDocument + * + * @param a string of dirty markup + * @return a DOM, filled with the dirty markup + */ + var _initDocument = function(dirty) { + /* Create a HTML document using DOMParser */ + var doc, body; + try { + doc = new DOMParser().parseFromString(dirty, 'text/html'); + } catch (e) {} + + /* Some browsers throw, some browsers return null for the code above + DOMParser with text/html support is only in very recent browsers. */ + if (!doc) { + doc = implementation.createHTMLDocument(''); + body = doc.body; + body.parentNode.removeChild(body.parentNode.firstElementChild); + body.outerHTML = dirty; + } + + /* Work on whole document or just its body */ + if (typeof doc.getElementsByTagName === 'function') { + return doc.getElementsByTagName( + WHOLE_DOCUMENT ? 'html' : 'body')[0]; + } + return getElementsByTagName.call(doc, + WHOLE_DOCUMENT ? 'html' : 'body')[0]; + }; + + /** + * _createIterator + * + * @param document/fragment to create iterator for + * @return iterator instance + */ + var _createIterator = function(root) { + return createNodeIterator.call(root.ownerDocument || root, + root, + NodeFilter.SHOW_ELEMENT + | NodeFilter.SHOW_COMMENT + | NodeFilter.SHOW_TEXT, + function() { return NodeFilter.FILTER_ACCEPT; }, + false + ); + }; + + /** + * _isClobbered + * + * @param element to check for clobbering attacks + * @return true if clobbered, false if safe + */ + var _isClobbered = function(elm) { + if (elm instanceof Text || elm instanceof Comment) { + return false; + } + if ( typeof elm.nodeName !== 'string' + || typeof elm.textContent !== 'string' + || typeof elm.removeChild !== 'function' + || !(elm.attributes instanceof NamedNodeMap) + || typeof elm.removeAttribute !== 'function' + || typeof elm.setAttribute !== 'function' + ) { + return true; + } + return false; + }; + + /** + * _sanitizeElements + * + * @protect nodeName + * @protect textContent + * @protect removeChild + * + * @param node to check for permission to exist + * @return true if node was killed, false if left alive + */ + var _sanitizeElements = function(currentNode) { + var tagName, content; + /* Execute a hook if present */ + _executeHook('beforeSanitizeElements', currentNode, null); + + /* Check if element is clobbered or can clobber */ + if (_isClobbered(currentNode)) { + _forceRemove(currentNode); + return true; + } + + /* Now let's check the element's type and name */ + tagName = currentNode.nodeName.toLowerCase(); + + /* Execute a hook if present */ + _executeHook('uponSanitizeElement', currentNode, { + tagName: tagName + }); + + /* Remove element if anything forbids its presence */ + if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) { + /* Keep content except for black-listed elements */ + if (KEEP_CONTENT && !FORBID_CONTENTS[tagName] + && typeof currentNode.insertAdjacentHTML === 'function') { + try { + currentNode.insertAdjacentHTML('AfterEnd', currentNode.innerHTML); + } catch (e) {} + } + _forceRemove(currentNode); + return true; + } + + /* Convert markup to cover jQuery behavior */ + if (SAFE_FOR_JQUERY && !currentNode.firstElementChild && + (!currentNode.content || !currentNode.content.firstElementChild)) { + currentNode.innerHTML = currentNode.textContent.replace(/ tag that has an "id" + // attribute at the time. + if (lcName === 'name' && + currentNode.nodeName === 'IMG' && attributes.id) { + idAttr = attributes.id; + attributes = Array.prototype.slice.apply(attributes); + currentNode.removeAttribute('id'); + currentNode.removeAttribute(name); + if (attributes.indexOf(idAttr) > l) { + currentNode.setAttribute('id', idAttr.value); + } + } else { + // This avoids a crash in Safari v9.0 with double-ids. + // The trick is to first set the id to be empty and then to + // remove the attriubute + if (name === 'id') { + currentNode.setAttribute(name, ''); + } + currentNode.removeAttribute(name); + } + + /* Did the hooks approve of the attribute? */ + if (!hookEvent.keepAttr) { + continue; + } + + /* Make sure attribute cannot clobber */ + if (SANITIZE_DOM && + (lcName === 'id' || lcName === 'name') && + (value in window || value in document || value in formElement)) { + continue; + } + + /* Sanitize attribute content to be template-safe */ + if (SAFE_FOR_TEMPLATES) { + value = value.replace(MUSTACHE_EXPR, ' '); + value = value.replace(ERB_EXPR, ' '); + } + + if ( + /* Check the name is permitted */ + (ALLOWED_ATTR[lcName] && !FORBID_ATTR[lcName] && ( + /* Check no script, data or unknown possibly unsafe URI + unless we know URI values are safe for that attribute */ + URI_SAFE_ATTRIBUTES[lcName] || + IS_ALLOWED_URI.test(value.replace(ATTR_WHITESPACE,'')) || + /* Keep image data URIs alive if src is allowed */ + (lcName === 'src' && value.indexOf('data:') === 0 && + DATA_URI_TAGS[currentNode.nodeName.toLowerCase()]) + )) || + /* Allow potentially valid data-* attributes: + * At least one character after "-" (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes) + * XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804) + * We don't need to check the value; it's always URI safe. + */ + (ALLOW_DATA_ATTR && DATA_ATTR.test(lcName)) || + /* Allow unknown protocols: + * This provides support for links that are handled by protocol handlers which may be unknown + * ahead of time, e.g. fb:, spotify: + */ + (ALLOW_UNKNOWN_PROTOCOLS && !IS_SCRIPT_OR_DATA.test(value.replace(ATTR_WHITESPACE,''))) + ) { + /* Handle invalid data-* attribute set by try-catching it */ + try { + currentNode.setAttribute(name, value); + } catch (e) {} + } + } + + /* Execute a hook if present */ + _executeHook('afterSanitizeAttributes', currentNode, null); + }; + + /** + * _sanitizeShadowDOM + * + * @param fragment to iterate over recursively + * @return void + */ + var _sanitizeShadowDOM = function(fragment) { + var shadowNode; + var shadowIterator = _createIterator(fragment); + + /* Execute a hook if present */ + _executeHook('beforeSanitizeShadowDOM', fragment, null); + + while ( (shadowNode = shadowIterator.nextNode()) ) { + /* Execute a hook if present */ + _executeHook('uponSanitizeShadowNode', shadowNode, null); + + /* Sanitize tags and elements */ + if (_sanitizeElements(shadowNode)) { + continue; + } + + /* Deep shadow DOM detected */ + if (shadowNode.content instanceof DocumentFragment) { + _sanitizeShadowDOM(shadowNode.content); + } + + /* Check attributes, sanitize if necessary */ + _sanitizeAttributes(shadowNode); + } + + /* Execute a hook if present */ + _executeHook('afterSanitizeShadowDOM', fragment, null); + }; + + /** + * _executeHook + * Execute user configurable hooks + * + * @param {String} entryPoint Name of the hook's entry point + * @param {Node} currentNode + */ + var _executeHook = function(entryPoint, currentNode, data) { + if (!hooks[entryPoint]) { return; } + + hooks[entryPoint].forEach(function(hook) { + hook.call(DOMPurify, currentNode, data, CONFIG); + }); + }; + + /** + * sanitize + * Public method providing core sanitation functionality + * + * @param {String} dirty string + * @param {Object} configuration object + */ + DOMPurify.sanitize = function(dirty, cfg) { + var body, currentNode, oldNode, nodeIterator, returnNode; + /* Make sure we have a string to sanitize. + DO NOT return early, as this will return the wrong type if + the user has requested a DOM object rather than a string */ + if (!dirty) { + dirty = ''; + } + + /* Stringify, in case dirty is an object */ + if (typeof dirty !== 'string') { + if (typeof dirty.toString !== 'function') { + throw new TypeError('toString is not a function'); + } else { + dirty = dirty.toString(); + } + } + + /* Check we can run. Otherwise fall back or ignore */ + if (!DOMPurify.isSupported) { + if (typeof window.toStaticHTML === 'object' + || typeof window.toStaticHTML === 'function') { + return window.toStaticHTML(dirty); + } + return dirty; + } + + /* Assign config vars */ + _parseConfig(cfg); + + /* Exit directly if we have nothing to do */ + if (!RETURN_DOM && !WHOLE_DOCUMENT && dirty.indexOf('<') === -1) { + return dirty; + } + + /* Initialize the document to work on */ + body = _initDocument(dirty); + + /* Check we have a DOM node from the data */ + if (!body) { + return RETURN_DOM ? null : ''; + } + + /* Get node iterator */ + nodeIterator = _createIterator(body); + + /* Now start iterating over the created document */ + while ( (currentNode = nodeIterator.nextNode()) ) { + + /* Fix IE's strange behavior with manipulated textNodes #89 */ + if (currentNode.nodeType === 3 && currentNode === oldNode) { + continue; + } + + /* Sanitize tags and elements */ + if (_sanitizeElements(currentNode)) { + continue; + } + + /* Shadow DOM detected, sanitize it */ + if (currentNode.content instanceof DocumentFragment) { + _sanitizeShadowDOM(currentNode.content); + } + + /* Check attributes, sanitize if necessary */ + _sanitizeAttributes(currentNode); + + oldNode = currentNode; + } + + /* Return sanitized string or DOM */ + if (RETURN_DOM) { + + if (RETURN_DOM_FRAGMENT) { + returnNode = createDocumentFragment.call(body.ownerDocument); + + while (body.firstChild) { + returnNode.appendChild(body.firstChild); + } + } else { + returnNode = body; + } + + if (RETURN_DOM_IMPORT) { + /* adoptNode() is not used because internal state is not reset + (e.g. the past names map of a HTMLFormElement), this is safe + in theory but we would rather not risk another attack vector. + The state that is cloned by importNode() is explicitly defined + by the specs. */ + returnNode = importNode.call(originalDocument, returnNode, true); + } + + return returnNode; + } + + return WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML; + }; + + /** + * addHook + * Public method to add DOMPurify hooks + * + * @param {String} entryPoint + * @param {Function} hookFunction + */ + DOMPurify.addHook = function(entryPoint, hookFunction) { + if (typeof hookFunction !== 'function') { return; } + hooks[entryPoint] = hooks[entryPoint] || []; + hooks[entryPoint].push(hookFunction); + }; + + /** + * removeHook + * Public method to remove a DOMPurify hook at a given entryPoint + * (pops it from the stack of hooks if more are present) + * + * @param {String} entryPoint + * @return void + */ + DOMPurify.removeHook = function(entryPoint) { + if (hooks[entryPoint]) { + hooks[entryPoint].pop(); + } + }; + + /** + * removeHooks + * Public method to remove all DOMPurify hooks at a given entryPoint + * + * @param {String} entryPoint + * @return void + */ + DOMPurify.removeHooks = function(entryPoint) { + if (hooks[entryPoint]) { + hooks[entryPoint] = []; + } + }; + + /** + * removeAllHooks + * Public method to remove all DOMPurify hooks + * + * @return void + */ + DOMPurify.removeAllHooks = function() { + hooks = []; + }; + + return DOMPurify; +})); diff --git a/src/main/resources/static/js/plugins/fileinput/plugins/purify.min.js b/src/main/resources/static/js/plugins/fileinput/plugins/purify.min.js new file mode 100644 index 000000000..c782f146f --- /dev/null +++ b/src/main/resources/static/js/plugins/fileinput/plugins/purify.min.js @@ -0,0 +1 @@ +(function(e){"use strict";var t=typeof window==="undefined"?null:window;if(typeof define==="function"&&define.amd){define(function(){return e(t)})}else if(typeof module!=="undefined"){module.exports=e(t)}else{t.DOMPurify=e(t)}})(function e(t){"use strict";var r=function(t){return e(t)};r.version="0.7.4";if(!t||!t.document||t.document.nodeType!==9){r.isSupported=false;return r}var n=t.document;var a=n;var i=t.DocumentFragment;var o=t.HTMLTemplateElement;var l=t.NodeFilter;var s=t.NamedNodeMap||t.MozNamedAttrMap;var f=t.Text;var c=t.Comment;var u=t.DOMParser;if(typeof o==="function"){var d=n.createElement("template");if(d.content&&d.content.ownerDocument){n=d.content.ownerDocument}}var m=n.implementation;var p=n.createNodeIterator;var h=n.getElementsByTagName;var v=n.createDocumentFragment;var g=a.importNode;var y={};r.isSupported=typeof m.createHTMLDocument!=="undefined"&&n.documentMode!==9;var b=function(e,t){var r=t.length;while(r--){if(typeof t[r]==="string"){t[r]=t[r].toLowerCase()}e[t[r]]=true}return e};var T=function(e){var t={};var r;for(r in e){if(e.hasOwnProperty(r)){t[r]=e[r]}}return t};var x=null;var k=b({},["a","abbr","acronym","address","area","article","aside","audio","b","bdi","bdo","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","content","data","datalist","dd","decorator","del","details","dfn","dir","div","dl","dt","element","em","fieldset","figcaption","figure","font","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","img","input","ins","kbd","label","legend","li","main","map","mark","marquee","menu","menuitem","meter","nav","nobr","ol","optgroup","option","output","p","pre","progress","q","rp","rt","ruby","s","samp","section","select","shadow","small","source","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","tr","track","tt","u","ul","var","video","wbr","svg","altglyph","altglyphdef","altglyphitem","animatecolor","animatemotion","animatetransform","circle","clippath","defs","desc","ellipse","filter","font","g","glyph","glyphref","hkern","image","line","lineargradient","marker","mask","metadata","mpath","path","pattern","polygon","polyline","radialgradient","rect","stop","switch","symbol","text","textpath","title","tref","tspan","view","vkern","feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feMerge","feMergeNode","feMorphology","feOffset","feSpecularLighting","feTile","feTurbulence","math","menclose","merror","mfenced","mfrac","mglyph","mi","mlabeledtr","mmuliscripts","mn","mo","mover","mpadded","mphantom","mroot","mrow","ms","mpspace","msqrt","mystyle","msub","msup","msubsup","mtable","mtd","mtext","mtr","munder","munderover","#text"]);var A=null;var w=b({},["accept","action","align","alt","autocomplete","background","bgcolor","border","cellpadding","cellspacing","checked","cite","class","clear","color","cols","colspan","coords","datetime","default","dir","disabled","download","enctype","face","for","headers","height","hidden","high","href","hreflang","id","ismap","label","lang","list","loop","low","max","maxlength","media","method","min","multiple","name","noshade","novalidate","nowrap","open","optimum","pattern","placeholder","poster","preload","pubdate","radiogroup","readonly","rel","required","rev","reversed","rows","rowspan","spellcheck","scope","selected","shape","size","span","srclang","start","src","step","style","summary","tabindex","title","type","usemap","valign","value","width","xmlns","accent-height","accumulate","additivive","alignment-baseline","ascent","attributename","attributetype","azimuth","basefrequency","baseline-shift","begin","bias","by","clip","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","cx","cy","d","dx","dy","diffuseconstant","direction","display","divisor","dur","edgemode","elevation","end","fill","fill-opacity","fill-rule","filter","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","fx","fy","g1","g2","glyph-name","glyphref","gradientunits","gradienttransform","image-rendering","in","in2","k","k1","k2","k3","k4","kerning","keypoints","keysplines","keytimes","lengthadjust","letter-spacing","kernelmatrix","kernelunitlength","lighting-color","local","marker-end","marker-mid","marker-start","markerheight","markerunits","markerwidth","maskcontentunits","maskunits","max","mask","mode","min","numoctaves","offset","operator","opacity","order","orient","orientation","origin","overflow","paint-order","path","pathlength","patterncontentunits","patterntransform","patternunits","points","preservealpha","r","rx","ry","radius","refx","refy","repeatcount","repeatdur","restart","result","rotate","scale","seed","shape-rendering","specularconstant","specularexponent","spreadmethod","stddeviation","stitchtiles","stop-color","stop-opacity","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke","stroke-width","surfacescale","targetx","targety","transform","text-anchor","text-decoration","text-rendering","textlength","u1","u2","unicode","values","viewbox","visibility","vert-adv-y","vert-origin-x","vert-origin-y","word-spacing","wrap","writing-mode","xchannelselector","ychannelselector","x","x1","x2","y","y1","y2","z","zoomandpan","accent","accentunder","bevelled","close","columnsalign","columnlines","columnspan","denomalign","depth","display","displaystyle","fence","frame","largeop","length","linethickness","lspace","lquote","mathbackground","mathcolor","mathsize","mathvariant","maxsize","minsize","movablelimits","notation","numalign","open","rowalign","rowlines","rowspacing","rowspan","rspace","rquote","scriptlevel","scriptminsize","scriptsizemultiplier","selection","separator","separators","stretchy","subscriptshift","supscriptshift","symmetric","voffset","xlink:href","xml:id","xlink:title","xml:space","xmlns:xlink"]);var E=null;var S=null;var M=true;var O=false;var L=false;var D=false;var N=/\{\{[\s\S]*|[\s\S]*\}\}/gm;var _=/<%[\s\S]*|[\s\S]*%>/gm;var C=false;var z=false;var R=false;var F=false;var H=true;var B=true;var W=b({},["audio","head","math","script","style","svg","video"]);var j=b({},["audio","video","img","source"]);var G=b({},["alt","class","for","id","label","name","pattern","placeholder","summary","title","value","style","xmlns"]);var I=null;var q=n.createElement("form");var P=function(e){if(typeof e!=="object"){e={}}x="ALLOWED_TAGS"in e?b({},e.ALLOWED_TAGS):k;A="ALLOWED_ATTR"in e?b({},e.ALLOWED_ATTR):w;E="FORBID_TAGS"in e?b({},e.FORBID_TAGS):{};S="FORBID_ATTR"in e?b({},e.FORBID_ATTR):{};M=e.ALLOW_DATA_ATTR!==false;O=e.ALLOW_UNKNOWN_PROTOCOLS||false;L=e.SAFE_FOR_JQUERY||false;D=e.SAFE_FOR_TEMPLATES||false;C=e.WHOLE_DOCUMENT||false;z=e.RETURN_DOM||false;R=e.RETURN_DOM_FRAGMENT||false;F=e.RETURN_DOM_IMPORT||false;H=e.SANITIZE_DOM!==false;B=e.KEEP_CONTENT!==false;if(D){M=false}if(R){z=true}if(e.ADD_TAGS){if(x===k){x=T(x)}b(x,e.ADD_TAGS)}if(e.ADD_ATTR){if(A===w){A=T(A)}b(A,e.ADD_ATTR)}if(B){x["#text"]=true}if(Object&&"freeze"in Object){Object.freeze(e)}I=e};var U=function(e){try{e.parentNode.removeChild(e)}catch(t){e.outerHTML=""}};var V=function(e){var t,r;try{t=(new u).parseFromString(e,"text/html")}catch(n){}if(!t){t=m.createHTMLDocument("");r=t.body;r.parentNode.removeChild(r.parentNode.firstElementChild);r.outerHTML=e}if(typeof t.getElementsByTagName==="function"){return t.getElementsByTagName(C?"html":"body")[0]}return h.call(t,C?"html":"body")[0]};var K=function(e){return p.call(e.ownerDocument||e,e,l.SHOW_ELEMENT|l.SHOW_COMMENT|l.SHOW_TEXT,function(){return l.FILTER_ACCEPT},false)};var J=function(e){if(e instanceof f||e instanceof c){return false}if(typeof e.nodeName!=="string"||typeof e.textContent!=="string"||typeof e.removeChild!=="function"||!(e.attributes instanceof s)||typeof e.removeAttribute!=="function"||typeof e.setAttribute!=="function"){return true}return false};var Q=function(e){var t,r;re("beforeSanitizeElements",e,null);if(J(e)){U(e);return true}t=e.nodeName.toLowerCase();re("uponSanitizeElement",e,{tagName:t});if(!x[t]||E[t]){if(B&&!W[t]&&typeof e.insertAdjacentHTML==="function"){try{e.insertAdjacentHTML("AfterEnd",e.innerHTML)}catch(n){}}U(e);return true}if(L&&!e.firstElementChild&&(!e.content||!e.content.firstElementChild)){e.innerHTML=e.textContent.replace(/c){e.setAttribute("id",l.value)}}else{if(a==="id"){e.setAttribute(a,"")}e.removeAttribute(a)}if(!f.keepAttr){continue}if(H&&(o==="id"||o==="name")&&(i in t||i in n||i in q)){continue}if(D){i=i.replace(N," ");i=i.replace(_," ")}if(A[o]&&!S[o]&&(G[o]||Y.test(i.replace($,""))||o==="src"&&i.indexOf("data:")===0&&j[e.nodeName.toLowerCase()])||M&&X.test(o)||O&&!Z.test(i.replace($,""))){try{e.setAttribute(a,i)}catch(u){}}}re("afterSanitizeAttributes",e,null)};var te=function(e){var t;var r=K(e);re("beforeSanitizeShadowDOM",e,null);while(t=r.nextNode()){re("uponSanitizeShadowNode",t,null);if(Q(t)){continue}if(t.content instanceof i){te(t.content)}ee(t)}re("afterSanitizeShadowDOM",e,null)};var re=function(e,t,n){if(!y[e]){return}y[e].forEach(function(e){e.call(r,t,n,I)})};r.sanitize=function(e,n){var o,l,s,f,c;if(!e){e=""}if(typeof e!=="string"){if(typeof e.toString!=="function"){throw new TypeError("toString is not a function")}else{e=e.toString()}}if(!r.isSupported){if(typeof t.toStaticHTML==="object"||typeof t.toStaticHTML==="function"){return t.toStaticHTML(e)}return e}P(n);if(!z&&!C&&e.indexOf("<")===-1){return e}o=V(e);if(!o){return z?null:""}f=K(o);while(l=f.nextNode()){if(l.nodeType===3&&l===s){continue}if(Q(l)){continue}if(l.content instanceof i){te(l.content)}ee(l);s=l}if(z){if(R){c=v.call(o.ownerDocument);while(o.firstChild){c.appendChild(o.firstChild)}}else{c=o}if(F){c=g.call(a,c,true)}return c}return C?o.outerHTML:o.innerHTML};r.addHook=function(e,t){if(typeof t!=="function"){return}y[e]=y[e]||[];y[e].push(t)};r.removeHook=function(e){if(y[e]){y[e].pop()}};r.removeHooks=function(e){if(y[e]){y[e]=[]}};r.removeAllHooks=function(){y=[]};return r}); \ No newline at end of file diff --git a/src/main/resources/static/js/plugins/fileinput/plugins/sortable.js b/src/main/resources/static/js/plugins/fileinput/plugins/sortable.js new file mode 100644 index 000000000..9fc23b8c6 --- /dev/null +++ b/src/main/resources/static/js/plugins/fileinput/plugins/sortable.js @@ -0,0 +1,1590 @@ +/**! + * KvSortable + * @author RubaXa + * @license MIT + * + * Changed kvsortable plugin naming to prevent conflict with JQuery UI Sortable + * @author Kartik Visweswaran + */ + +(function kvsortableModule(factory) { + "use strict"; + + if (typeof define === "function" && define.amd) { + define(factory); + } + else if (typeof module != "undefined" && typeof module.exports != "undefined") { + module.exports = factory(); + } + else { + /* jshint sub:true */ + window["KvSortable"] = factory(); + } +})(function kvsortableFactory() { + "use strict"; + + if (typeof window === "undefined" || !window.document) { + return function kvsortableError() { + throw new Error("KvSortable.js requires a window with a document"); + }; + } + + var dragEl, + parentEl, + ghostEl, + cloneEl, + rootEl, + nextEl, + lastDownEl, + + scrollEl, + scrollParentEl, + scrollCustomFn, + + lastEl, + lastCSS, + lastParentCSS, + + oldIndex, + newIndex, + + activeGroup, + putKvSortable, + + autoScroll = {}, + + tapEvt, + touchEvt, + + moved, + + /** @const */ + R_SPACE = /\s+/g, + R_FLOAT = /left|right|inline/, + + expando = 'KvSortable' + (new Date).getTime(), + + win = window, + document = win.document, + parseInt = win.parseInt, + setTimeout = win.setTimeout, + + $ = win.jQuery || win.Zepto, + Polymer = win.Polymer, + + captureMode = false, + passiveMode = false, + + supportDraggable = ('draggable' in document.createElement('div')), + supportCssPointerEvents = (function (el) { + // false when IE11 + if (!!navigator.userAgent.match(/(?:Trident.*rv[ :]?11\.|msie)/i)) { + return false; + } + el = document.createElement('x'); + el.style.cssText = 'pointer-events:auto'; + return el.style.pointerEvents === 'auto'; + })(), + + _silent = false, + + abs = Math.abs, + min = Math.min, + + savedInputChecked = [], + touchDragOverListeners = [], + + _autoScroll = _throttle(function (/**Event*/evt, /**Object*/options, /**HTMLElement*/rootEl) { + // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521 + if (rootEl && options.scroll) { + var _this = rootEl[expando], + el, + rect, + sens = options.scrollSensitivity, + speed = options.scrollSpeed, + + x = evt.clientX, + y = evt.clientY, + + winWidth = window.innerWidth, + winHeight = window.innerHeight, + + vx, + vy, + + scrollOffsetX, + scrollOffsetY + ; + + // Delect scrollEl + if (scrollParentEl !== rootEl) { + scrollEl = options.scroll; + scrollParentEl = rootEl; + scrollCustomFn = options.scrollFn; + + if (scrollEl === true) { + scrollEl = rootEl; + + do { + if ((scrollEl.offsetWidth < scrollEl.scrollWidth) || + (scrollEl.offsetHeight < scrollEl.scrollHeight) + ) { + break; + } + /* jshint boss:true */ + } while (scrollEl = scrollEl.parentNode); + } + } + + if (scrollEl) { + el = scrollEl; + rect = scrollEl.getBoundingClientRect(); + vx = (abs(rect.right - x) <= sens) - (abs(rect.left - x) <= sens); + vy = (abs(rect.bottom - y) <= sens) - (abs(rect.top - y) <= sens); + } + + + if (!(vx || vy)) { + vx = (winWidth - x <= sens) - (x <= sens); + vy = (winHeight - y <= sens) - (y <= sens); + + /* jshint expr:true */ + (vx || vy) && (el = win); + } + + + if (autoScroll.vx !== vx || autoScroll.vy !== vy || autoScroll.el !== el) { + autoScroll.el = el; + autoScroll.vx = vx; + autoScroll.vy = vy; + + clearInterval(autoScroll.pid); + + if (el) { + autoScroll.pid = setInterval(function () { + scrollOffsetY = vy ? vy * speed : 0; + scrollOffsetX = vx ? vx * speed : 0; + + if ('function' === typeof(scrollCustomFn)) { + return scrollCustomFn.call(_this, scrollOffsetX, scrollOffsetY, evt); + } + + if (el === win) { + win.scrollTo(win.pageXOffset + scrollOffsetX, win.pageYOffset + scrollOffsetY); + } else { + el.scrollTop += scrollOffsetY; + el.scrollLeft += scrollOffsetX; + } + }, 24); + } + } + } + }, 30), + + _prepareGroup = function (options) { + function toFn(value, pull) { + if (value === void 0 || value === true) { + value = group.name; + } + + if (typeof value === 'function') { + return value; + } else { + return function (to, from) { + var fromGroup = from.options.group.name; + + return pull + ? value + : value && (value.join + ? value.indexOf(fromGroup) > -1 + : (fromGroup == value) + ); + }; + } + } + + var group = {}; + var originalGroup = options.group; + + if (!originalGroup || typeof originalGroup != 'object') { + originalGroup = {name: originalGroup}; + } + + group.name = originalGroup.name; + group.checkPull = toFn(originalGroup.pull, true); + group.checkPut = toFn(originalGroup.put); + group.revertClone = originalGroup.revertClone; + + options.group = group; + } + ; + + // Detect support a passive mode + try { + window.addEventListener('test', null, Object.defineProperty({}, 'passive', { + get: function () { + // `false`, because everything starts to work incorrectly and instead of d'n'd, + // begins the page has scrolled. + passiveMode = false; + captureMode = { + capture: false, + passive: passiveMode + }; + } + })); + } catch (err) {} + + /** + * @class KvSortable + * @param {HTMLElement} el + * @param {Object} [options] + */ + function KvSortable(el, options) { + if (!(el && el.nodeType && el.nodeType === 1)) { + throw 'KvSortable: `el` must be HTMLElement, and not ' + {}.toString.call(el); + } + + this.el = el; // root element + this.options = options = _extend({}, options); + + + // Export instance + el[expando] = this; + + // Default options + var defaults = { + group: Math.random(), + sort: true, + disabled: false, + store: null, + handle: null, + scroll: true, + scrollSensitivity: 30, + scrollSpeed: 10, + draggable: /[uo]l/i.test(el.nodeName) ? 'li' : '>*', + ghostClass: 'kvsortable-ghost', + chosenClass: 'kvsortable-chosen', + dragClass: 'kvsortable-drag', + ignore: 'a, img', + filter: null, + preventOnFilter: true, + animation: 0, + setData: function (dataTransfer, dragEl) { + dataTransfer.setData('Text', dragEl.textContent); + }, + dropBubble: false, + dragoverBubble: false, + dataIdAttr: 'data-id', + delay: 0, + forceFallback: false, + fallbackClass: 'kvsortable-fallback', + fallbackOnBody: false, + fallbackTolerance: 0, + fallbackOffset: {x: 0, y: 0}, + supportPointer: KvSortable.supportPointer !== false + }; + + + // Set default options + for (var name in defaults) { + !(name in options) && (options[name] = defaults[name]); + } + + _prepareGroup(options); + + // Bind all private methods + for (var fn in this) { + if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { + this[fn] = this[fn].bind(this); + } + } + + // Setup drag mode + this.nativeDraggable = options.forceFallback ? false : supportDraggable; + + // Bind events + _on(el, 'mousedown', this._onTapStart); + _on(el, 'touchstart', this._onTapStart); + options.supportPointer && _on(el, 'pointerdown', this._onTapStart); + + if (this.nativeDraggable) { + _on(el, 'dragover', this); + _on(el, 'dragenter', this); + } + + touchDragOverListeners.push(this._onDragOver); + + // Restore sorting + options.store && this.sort(options.store.get(this)); + } + + + KvSortable.prototype = /** @lends KvSortable.prototype */ { + constructor: KvSortable, + + _onTapStart: function (/** Event|TouchEvent */evt) { + var _this = this, + el = this.el, + options = this.options, + preventOnFilter = options.preventOnFilter, + type = evt.type, + touch = evt.touches && evt.touches[0], + target = (touch || evt).target, + originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0]) || target, + filter = options.filter, + startIndex; + + _saveInputCheckedState(el); + + + // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group. + if (dragEl) { + return; + } + + if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) { + return; // only left button or enabled + } + + // cancel dnd if original target is content editable + if (originalTarget.isContentEditable) { + return; + } + + target = _closest(target, options.draggable, el); + + if (!target) { + return; + } + + if (lastDownEl === target) { + // Ignoring duplicate `down` + return; + } + + // Get the index of the dragged element within its parent + startIndex = _index(target, options.draggable); + + // Check filter + if (typeof filter === 'function') { + if (filter.call(this, evt, target, this)) { + _dispatchEvent(_this, originalTarget, 'filter', target, el, el, startIndex); + preventOnFilter && evt.preventDefault(); + return; // cancel dnd + } + } + else if (filter) { + filter = filter.split(',').some(function (criteria) { + criteria = _closest(originalTarget, criteria.trim(), el); + + if (criteria) { + _dispatchEvent(_this, criteria, 'filter', target, el, el, startIndex); + return true; + } + }); + + if (filter) { + preventOnFilter && evt.preventDefault(); + return; // cancel dnd + } + } + + if (options.handle && !_closest(originalTarget, options.handle, el)) { + return; + } + + // Prepare `dragstart` + this._prepareDragStart(evt, touch, target, startIndex); + }, + + _prepareDragStart: function (/** Event */evt, /** Touch */touch, /** HTMLElement */target, /** Number */startIndex) { + var _this = this, + el = _this.el, + options = _this.options, + ownerDocument = el.ownerDocument, + dragStartFn; + + if (target && !dragEl && (target.parentNode === el)) { + tapEvt = evt; + + rootEl = el; + dragEl = target; + parentEl = dragEl.parentNode; + nextEl = dragEl.nextSibling; + lastDownEl = target; + activeGroup = options.group; + oldIndex = startIndex; + + this._lastX = (touch || evt).clientX; + this._lastY = (touch || evt).clientY; + + dragEl.style['will-change'] = 'all'; + + dragStartFn = function () { + // Delayed drag has been triggered + // we can re-enable the events: touchmove/mousemove + _this._disableDelayedDrag(); + + // Make the element draggable + dragEl.draggable = _this.nativeDraggable; + + // Chosen item + _toggleClass(dragEl, options.chosenClass, true); + + // Bind the events: dragstart/dragend + _this._triggerDragStart(evt, touch); + + // Drag start event + _dispatchEvent(_this, rootEl, 'choose', dragEl, rootEl, rootEl, oldIndex); + }; + + // Disable "draggable" + options.ignore.split(',').forEach(function (criteria) { + _find(dragEl, criteria.trim(), _disableDraggable); + }); + + _on(ownerDocument, 'mouseup', _this._onDrop); + _on(ownerDocument, 'touchend', _this._onDrop); + _on(ownerDocument, 'touchcancel', _this._onDrop); + _on(ownerDocument, 'selectstart', _this); + options.supportPointer && _on(ownerDocument, 'pointercancel', _this._onDrop); + + if (options.delay) { + // If the user moves the pointer or let go the click or touch + // before the delay has been reached: + // disable the delayed drag + _on(ownerDocument, 'mouseup', _this._disableDelayedDrag); + _on(ownerDocument, 'touchend', _this._disableDelayedDrag); + _on(ownerDocument, 'touchcancel', _this._disableDelayedDrag); + _on(ownerDocument, 'mousemove', _this._disableDelayedDrag); + _on(ownerDocument, 'touchmove', _this._disableDelayedDrag); + options.supportPointer && _on(ownerDocument, 'pointermove', _this._disableDelayedDrag); + + _this._dragStartTimer = setTimeout(dragStartFn, options.delay); + } else { + dragStartFn(); + } + + + } + }, + + _disableDelayedDrag: function () { + var ownerDocument = this.el.ownerDocument; + + clearTimeout(this._dragStartTimer); + _off(ownerDocument, 'mouseup', this._disableDelayedDrag); + _off(ownerDocument, 'touchend', this._disableDelayedDrag); + _off(ownerDocument, 'touchcancel', this._disableDelayedDrag); + _off(ownerDocument, 'mousemove', this._disableDelayedDrag); + _off(ownerDocument, 'touchmove', this._disableDelayedDrag); + _off(ownerDocument, 'pointermove', this._disableDelayedDrag); + }, + + _triggerDragStart: function (/** Event */evt, /** Touch */touch) { + touch = touch || (evt.pointerType == 'touch' ? evt : null); + + if (touch) { + // Touch device support + tapEvt = { + target: dragEl, + clientX: touch.clientX, + clientY: touch.clientY + }; + + this._onDragStart(tapEvt, 'touch'); + } + else if (!this.nativeDraggable) { + this._onDragStart(tapEvt, true); + } + else { + _on(dragEl, 'dragend', this); + _on(rootEl, 'dragstart', this._onDragStart); + } + + try { + if (document.selection) { + // Timeout neccessary for IE9 + _nextTick(function () { + document.selection.empty(); + }); + } else { + window.getSelection().removeAllRanges(); + } + } catch (err) { + } + }, + + _dragStarted: function () { + if (rootEl && dragEl) { + var options = this.options; + + // Apply effect + _toggleClass(dragEl, options.ghostClass, true); + _toggleClass(dragEl, options.dragClass, false); + + KvSortable.active = this; + + // Drag start event + _dispatchEvent(this, rootEl, 'start', dragEl, rootEl, rootEl, oldIndex); + } else { + this._nulling(); + } + }, + + _emulateDragOver: function () { + if (touchEvt) { + if (this._lastX === touchEvt.clientX && this._lastY === touchEvt.clientY) { + return; + } + + this._lastX = touchEvt.clientX; + this._lastY = touchEvt.clientY; + + if (!supportCssPointerEvents) { + _css(ghostEl, 'display', 'none'); + } + + var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY); + var parent = target; + var i = touchDragOverListeners.length; + + if (target && target.shadowRoot) { + target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY); + parent = target; + } + + if (parent) { + do { + if (parent[expando]) { + while (i--) { + touchDragOverListeners[i]({ + clientX: touchEvt.clientX, + clientY: touchEvt.clientY, + target: target, + rootEl: parent + }); + } + + break; + } + + target = parent; // store last element + } + /* jshint boss:true */ + while (parent = parent.parentNode); + } + + if (!supportCssPointerEvents) { + _css(ghostEl, 'display', ''); + } + } + }, + + + _onTouchMove: function (/**TouchEvent*/evt) { + if (tapEvt) { + var options = this.options, + fallbackTolerance = options.fallbackTolerance, + fallbackOffset = options.fallbackOffset, + touch = evt.touches ? evt.touches[0] : evt, + dx = (touch.clientX - tapEvt.clientX) + fallbackOffset.x, + dy = (touch.clientY - tapEvt.clientY) + fallbackOffset.y, + translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)'; + + // only set the status to dragging, when we are actually dragging + if (!KvSortable.active) { + if (fallbackTolerance && + min(abs(touch.clientX - this._lastX), abs(touch.clientY - this._lastY)) < fallbackTolerance + ) { + return; + } + + this._dragStarted(); + } + + // as well as creating the ghost element on the document body + this._appendGhost(); + + moved = true; + touchEvt = touch; + + _css(ghostEl, 'webkitTransform', translate3d); + _css(ghostEl, 'mozTransform', translate3d); + _css(ghostEl, 'msTransform', translate3d); + _css(ghostEl, 'transform', translate3d); + + evt.preventDefault(); + } + }, + + _appendGhost: function () { + if (!ghostEl) { + var rect = dragEl.getBoundingClientRect(), + css = _css(dragEl), + options = this.options, + ghostRect; + + ghostEl = dragEl.cloneNode(true); + + _toggleClass(ghostEl, options.ghostClass, false); + _toggleClass(ghostEl, options.fallbackClass, true); + _toggleClass(ghostEl, options.dragClass, true); + + _css(ghostEl, 'top', rect.top - parseInt(css.marginTop, 10)); + _css(ghostEl, 'left', rect.left - parseInt(css.marginLeft, 10)); + _css(ghostEl, 'width', rect.width); + _css(ghostEl, 'height', rect.height); + _css(ghostEl, 'opacity', '0.8'); + _css(ghostEl, 'position', 'fixed'); + _css(ghostEl, 'zIndex', '100000'); + _css(ghostEl, 'pointerEvents', 'none'); + + options.fallbackOnBody && document.body.appendChild(ghostEl) || rootEl.appendChild(ghostEl); + + // Fixing dimensions. + ghostRect = ghostEl.getBoundingClientRect(); + _css(ghostEl, 'width', rect.width * 2 - ghostRect.width); + _css(ghostEl, 'height', rect.height * 2 - ghostRect.height); + } + }, + + _onDragStart: function (/**Event*/evt, /**boolean*/useFallback) { + var _this = this; + var dataTransfer = evt.dataTransfer; + var options = _this.options; + + _this._offUpEvents(); + + if (activeGroup.checkPull(_this, _this, dragEl, evt)) { + cloneEl = _clone(dragEl); + + cloneEl.draggable = false; + cloneEl.style['will-change'] = ''; + + _css(cloneEl, 'display', 'none'); + _toggleClass(cloneEl, _this.options.chosenClass, false); + + // #1143: IFrame support workaround + _this._cloneId = _nextTick(function () { + rootEl.insertBefore(cloneEl, dragEl); + _dispatchEvent(_this, rootEl, 'clone', dragEl); + }); + } + + _toggleClass(dragEl, options.dragClass, true); + + if (useFallback) { + if (useFallback === 'touch') { + // Bind touch events + _on(document, 'touchmove', _this._onTouchMove); + _on(document, 'touchend', _this._onDrop); + _on(document, 'touchcancel', _this._onDrop); + + if (options.supportPointer) { + _on(document, 'pointermove', _this._onTouchMove); + _on(document, 'pointerup', _this._onDrop); + } + } else { + // Old brwoser + _on(document, 'mousemove', _this._onTouchMove); + _on(document, 'mouseup', _this._onDrop); + } + + _this._loopId = setInterval(_this._emulateDragOver, 50); + } + else { + if (dataTransfer) { + dataTransfer.effectAllowed = 'move'; + options.setData && options.setData.call(_this, dataTransfer, dragEl); + } + + _on(document, 'drop', _this); + + // #1143: Бывает элемент с IFrame внутри блокирует `drop`, + // поэтому если вызвался `mouseover`, значит надо отменять весь d'n'd. + // Breaking Chrome 62+ + // _on(document, 'mouseover', _this); + + _this._dragStartId = _nextTick(_this._dragStarted); + } + }, + + _onDragOver: function (/**Event*/evt) { + var el = this.el, + target, + dragRect, + targetRect, + revert, + options = this.options, + group = options.group, + activeKvSortable = KvSortable.active, + isOwner = (activeGroup === group), + isMovingBetweenKvSortable = false, + canSort = options.sort; + + if (evt.preventDefault !== void 0) { + evt.preventDefault(); + !options.dragoverBubble && evt.stopPropagation(); + } + + if (dragEl.animated) { + return; + } + + moved = true; + + if (activeKvSortable && !options.disabled && + (isOwner + ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list + : ( + putKvSortable === this || + ( + (activeKvSortable.lastPullMode = activeGroup.checkPull(this, activeKvSortable, dragEl, evt)) && + group.checkPut(this, activeKvSortable, dragEl, evt) + ) + ) + ) && + (evt.rootEl === void 0 || evt.rootEl === this.el) // touch fallback + ) { + // Smart auto-scrolling + _autoScroll(evt, options, this.el); + + if (_silent) { + return; + } + + target = _closest(evt.target, options.draggable, el); + dragRect = dragEl.getBoundingClientRect(); + + if (putKvSortable !== this) { + putKvSortable = this; + isMovingBetweenKvSortable = true; + } + + if (revert) { + _cloneHide(activeKvSortable, true); + parentEl = rootEl; // actualization + + if (cloneEl || nextEl) { + rootEl.insertBefore(dragEl, cloneEl || nextEl); + } + else if (!canSort) { + rootEl.appendChild(dragEl); + } + + return; + } + + + if ((el.children.length === 0) || (el.children[0] === ghostEl) || + (el === evt.target) && (_ghostIsLast(el, evt)) + ) { + //assign target only if condition is true + if (el.children.length !== 0 && el.children[0] !== ghostEl && el === evt.target) { + target = el.lastElementChild; + } + + if (target) { + if (target.animated) { + return; + } + + targetRect = target.getBoundingClientRect(); + } + + _cloneHide(activeKvSortable, isOwner); + + if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt) !== false) { + if (!dragEl.contains(el)) { + el.appendChild(dragEl); + parentEl = el; // actualization + } + + this._animate(dragRect, dragEl); + target && this._animate(targetRect, target); + } + } + else if (target && !target.animated && target !== dragEl && (target.parentNode[expando] !== void 0)) { + if (lastEl !== target) { + lastEl = target; + lastCSS = _css(target); + lastParentCSS = _css(target.parentNode); + } + + targetRect = target.getBoundingClientRect(); + + var width = targetRect.right - targetRect.left, + height = targetRect.bottom - targetRect.top, + floating = R_FLOAT.test(lastCSS.cssFloat + lastCSS.display) + || (lastParentCSS.display == 'flex' && lastParentCSS['flex-direction'].indexOf('row') === 0), + isWide = (target.offsetWidth > dragEl.offsetWidth), + isLong = (target.offsetHeight > dragEl.offsetHeight), + halfway = (floating ? (evt.clientX - targetRect.left) / width : (evt.clientY - targetRect.top) / height) > 0.5, + nextSibling = target.nextElementSibling, + after = false + ; + + if (floating) { + var elTop = dragEl.offsetTop, + tgTop = target.offsetTop; + + if (elTop === tgTop) { + after = (target.previousElementSibling === dragEl) && !isWide || halfway && isWide; + } + else if (target.previousElementSibling === dragEl || dragEl.previousElementSibling === target) { + after = (evt.clientY - targetRect.top) / height > 0.5; + } else { + after = tgTop > elTop; + } + } else if (!isMovingBetweenKvSortable) { + after = (nextSibling !== dragEl) && !isLong || halfway && isLong; + } + + var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after); + + if (moveVector !== false) { + if (moveVector === 1 || moveVector === -1) { + after = (moveVector === 1); + } + + _silent = true; + setTimeout(_unsilent, 30); + + _cloneHide(activeKvSortable, isOwner); + + if (!dragEl.contains(el)) { + if (after && !nextSibling) { + el.appendChild(dragEl); + } else { + target.parentNode.insertBefore(dragEl, after ? nextSibling : target); + } + } + + parentEl = dragEl.parentNode; // actualization + + this._animate(dragRect, dragEl); + this._animate(targetRect, target); + } + } + } + }, + + _animate: function (prevRect, target) { + var ms = this.options.animation; + + if (ms) { + var currentRect = target.getBoundingClientRect(); + + if (prevRect.nodeType === 1) { + prevRect = prevRect.getBoundingClientRect(); + } + + _css(target, 'transition', 'none'); + _css(target, 'transform', 'translate3d(' + + (prevRect.left - currentRect.left) + 'px,' + + (prevRect.top - currentRect.top) + 'px,0)' + ); + + target.offsetWidth; // repaint + + _css(target, 'transition', 'all ' + ms + 'ms'); + _css(target, 'transform', 'translate3d(0,0,0)'); + + clearTimeout(target.animated); + target.animated = setTimeout(function () { + _css(target, 'transition', ''); + _css(target, 'transform', ''); + target.animated = false; + }, ms); + } + }, + + _offUpEvents: function () { + var ownerDocument = this.el.ownerDocument; + + _off(document, 'touchmove', this._onTouchMove); + _off(document, 'pointermove', this._onTouchMove); + _off(ownerDocument, 'mouseup', this._onDrop); + _off(ownerDocument, 'touchend', this._onDrop); + _off(ownerDocument, 'pointerup', this._onDrop); + _off(ownerDocument, 'touchcancel', this._onDrop); + _off(ownerDocument, 'pointercancel', this._onDrop); + _off(ownerDocument, 'selectstart', this); + }, + + _onDrop: function (/**Event*/evt) { + var el = this.el, + options = this.options; + + clearInterval(this._loopId); + clearInterval(autoScroll.pid); + clearTimeout(this._dragStartTimer); + + _cancelNextTick(this._cloneId); + _cancelNextTick(this._dragStartId); + + // Unbind events + _off(document, 'mouseover', this); + _off(document, 'mousemove', this._onTouchMove); + + if (this.nativeDraggable) { + _off(document, 'drop', this); + _off(el, 'dragstart', this._onDragStart); + } + + this._offUpEvents(); + + if (evt) { + if (moved) { + evt.preventDefault(); + !options.dropBubble && evt.stopPropagation(); + } + + ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl); + + if (rootEl === parentEl || KvSortable.active.lastPullMode !== 'clone') { + // Remove clone + cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl); + } + + if (dragEl) { + if (this.nativeDraggable) { + _off(dragEl, 'dragend', this); + } + + _disableDraggable(dragEl); + dragEl.style['will-change'] = ''; + + // Remove class's + _toggleClass(dragEl, this.options.ghostClass, false); + _toggleClass(dragEl, this.options.chosenClass, false); + + // Drag stop event + _dispatchEvent(this, rootEl, 'unchoose', dragEl, parentEl, rootEl, oldIndex); + + if (rootEl !== parentEl) { + newIndex = _index(dragEl, options.draggable); + + if (newIndex >= 0) { + // Add event + _dispatchEvent(null, parentEl, 'add', dragEl, parentEl, rootEl, oldIndex, newIndex); + + // Remove event + _dispatchEvent(this, rootEl, 'remove', dragEl, parentEl, rootEl, oldIndex, newIndex); + + // drag from one list and drop into another + _dispatchEvent(null, parentEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex); + _dispatchEvent(this, rootEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex); + } + } + else { + if (dragEl.nextSibling !== nextEl) { + // Get the index of the dragged element within its parent + newIndex = _index(dragEl, options.draggable); + + if (newIndex >= 0) { + // drag & drop within the same list + _dispatchEvent(this, rootEl, 'update', dragEl, parentEl, rootEl, oldIndex, newIndex); + _dispatchEvent(this, rootEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex); + } + } + } + + if (KvSortable.active) { + /* jshint eqnull:true */ + if (newIndex == null || newIndex === -1) { + newIndex = oldIndex; + } + + _dispatchEvent(this, rootEl, 'end', dragEl, parentEl, rootEl, oldIndex, newIndex); + + // Save sorting + this.save(); + } + } + + } + + this._nulling(); + }, + + _nulling: function() { + rootEl = + dragEl = + parentEl = + ghostEl = + nextEl = + cloneEl = + lastDownEl = + + scrollEl = + scrollParentEl = + + tapEvt = + touchEvt = + + moved = + newIndex = + + lastEl = + lastCSS = + + putKvSortable = + activeGroup = + KvSortable.active = null; + + savedInputChecked.forEach(function (el) { + el.checked = true; + }); + savedInputChecked.length = 0; + }, + + handleEvent: function (/**Event*/evt) { + switch (evt.type) { + case 'drop': + case 'dragend': + this._onDrop(evt); + break; + + case 'dragover': + case 'dragenter': + if (dragEl) { + this._onDragOver(evt); + _globalDragOver(evt); + } + break; + + case 'mouseover': + this._onDrop(evt); + break; + + case 'selectstart': + evt.preventDefault(); + break; + } + }, + + + /** + * Serializes the item into an array of string. + * @returns {String[]} + */ + toArray: function () { + var order = [], + el, + children = this.el.children, + i = 0, + n = children.length, + options = this.options; + + for (; i < n; i++) { + el = children[i]; + if (_closest(el, options.draggable, this.el)) { + order.push(el.getAttribute(options.dataIdAttr) || _generateId(el)); + } + } + + return order; + }, + + + /** + * Sorts the elements according to the array. + * @param {String[]} order order of the items + */ + sort: function (order) { + var items = {}, rootEl = this.el; + + this.toArray().forEach(function (id, i) { + var el = rootEl.children[i]; + + if (_closest(el, this.options.draggable, rootEl)) { + items[id] = el; + } + }, this); + + order.forEach(function (id) { + if (items[id]) { + rootEl.removeChild(items[id]); + rootEl.appendChild(items[id]); + } + }); + }, + + + /** + * Save the current sorting + */ + save: function () { + var store = this.options.store; + store && store.set(this); + }, + + + /** + * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. + * @param {HTMLElement} el + * @param {String} [selector] default: `options.draggable` + * @returns {HTMLElement|null} + */ + closest: function (el, selector) { + return _closest(el, selector || this.options.draggable, this.el); + }, + + + /** + * Set/get option + * @param {string} name + * @param {*} [value] + * @returns {*} + */ + option: function (name, value) { + var options = this.options; + + if (value === void 0) { + return options[name]; + } else { + options[name] = value; + + if (name === 'group') { + _prepareGroup(options); + } + } + }, + + + /** + * Destroy + */ + destroy: function () { + var el = this.el; + + el[expando] = null; + + _off(el, 'mousedown', this._onTapStart); + _off(el, 'touchstart', this._onTapStart); + _off(el, 'pointerdown', this._onTapStart); + + if (this.nativeDraggable) { + _off(el, 'dragover', this); + _off(el, 'dragenter', this); + } + + // Remove draggable attributes + Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) { + el.removeAttribute('draggable'); + }); + + touchDragOverListeners.splice(touchDragOverListeners.indexOf(this._onDragOver), 1); + + this._onDrop(); + + this.el = el = null; + } + }; + + + function _cloneHide(kvsortable, state) { + if (kvsortable.lastPullMode !== 'clone') { + state = true; + } + + if (cloneEl && (cloneEl.state !== state)) { + _css(cloneEl, 'display', state ? 'none' : ''); + + if (!state) { + if (cloneEl.state) { + if (kvsortable.options.group.revertClone) { + rootEl.insertBefore(cloneEl, nextEl); + kvsortable._animate(dragEl, cloneEl); + } else { + rootEl.insertBefore(cloneEl, dragEl); + } + } + } + + cloneEl.state = state; + } + } + + + function _closest(/**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx) { + if (el) { + ctx = ctx || document; + + do { + if ((selector === '>*' && el.parentNode === ctx) || _matches(el, selector)) { + return el; + } + /* jshint boss:true */ + } while (el = _getParentOrHost(el)); + } + + return null; + } + + + function _getParentOrHost(el) { + var parent = el.host; + + return (parent && parent.nodeType) ? parent : el.parentNode; + } + + + function _globalDragOver(/**Event*/evt) { + if (evt.dataTransfer) { + evt.dataTransfer.dropEffect = 'move'; + } + evt.preventDefault(); + } + + + function _on(el, event, fn) { + el.addEventListener(event, fn, captureMode); + } + + + function _off(el, event, fn) { + el.removeEventListener(event, fn, captureMode); + } + + + function _toggleClass(el, name, state) { + if (el) { + if (el.classList) { + el.classList[state ? 'add' : 'remove'](name); + } + else { + var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' '); + el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' '); + } + } + } + + + function _css(el, prop, val) { + var style = el && el.style; + + if (style) { + if (val === void 0) { + if (document.defaultView && document.defaultView.getComputedStyle) { + val = document.defaultView.getComputedStyle(el, ''); + } + else if (el.currentStyle) { + val = el.currentStyle; + } + + return prop === void 0 ? val : val[prop]; + } + else { + if (!(prop in style)) { + prop = '-webkit-' + prop; + } + + style[prop] = val + (typeof val === 'string' ? '' : 'px'); + } + } + } + + + function _find(ctx, tagName, iterator) { + if (ctx) { + var list = ctx.getElementsByTagName(tagName), i = 0, n = list.length; + + if (iterator) { + for (; i < n; i++) { + iterator(list[i], i); + } + } + + return list; + } + + return []; + } + + + + function _dispatchEvent(kvsortable, rootEl, name, targetEl, toEl, fromEl, startIndex, newIndex) { + kvsortable = (kvsortable || rootEl[expando]); + + var evt = document.createEvent('Event'), + options = kvsortable.options, + onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1); + + evt.initEvent(name, true, true); + + evt.to = toEl || rootEl; + evt.from = fromEl || rootEl; + evt.item = targetEl || rootEl; + evt.clone = cloneEl; + + evt.oldIndex = startIndex; + evt.newIndex = newIndex; + + rootEl.dispatchEvent(evt); + + if (options[onName]) { + options[onName].call(kvsortable, evt); + } + } + + + function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvt, willInsertAfter) { + var evt, + kvsortable = fromEl[expando], + onMoveFn = kvsortable.options.onMove, + retVal; + + evt = document.createEvent('Event'); + evt.initEvent('move', true, true); + + evt.to = toEl; + evt.from = fromEl; + evt.dragged = dragEl; + evt.draggedRect = dragRect; + evt.related = targetEl || toEl; + evt.relatedRect = targetRect || toEl.getBoundingClientRect(); + evt.willInsertAfter = willInsertAfter; + + fromEl.dispatchEvent(evt); + + if (onMoveFn) { + retVal = onMoveFn.call(kvsortable, evt, originalEvt); + } + + return retVal; + } + + + function _disableDraggable(el) { + el.draggable = false; + } + + + function _unsilent() { + _silent = false; + } + + + /** @returns {HTMLElement|false} */ + function _ghostIsLast(el, evt) { + var lastEl = el.lastElementChild, + rect = lastEl.getBoundingClientRect(); + + // 5 — min delta + // abs — нельзя добавлять, а то глюки при наведении сверху + return (evt.clientY - (rect.top + rect.height) > 5) || + (evt.clientX - (rect.left + rect.width) > 5); + } + + + /** + * Generate id + * @param {HTMLElement} el + * @returns {String} + * @private + */ + function _generateId(el) { + var str = el.tagName + el.className + el.src + el.href + el.textContent, + i = str.length, + sum = 0; + + while (i--) { + sum += str.charCodeAt(i); + } + + return sum.toString(36); + } + + /** + * Returns the index of an element within its parent for a selected set of + * elements + * @param {HTMLElement} el + * @param {selector} selector + * @return {number} + */ + function _index(el, selector) { + var index = 0; + + if (!el || !el.parentNode) { + return -1; + } + + while (el && (el = el.previousElementSibling)) { + if ((el.nodeName.toUpperCase() !== 'TEMPLATE') && (selector === '>*' || _matches(el, selector))) { + index++; + } + } + + return index; + } + + function _matches(/**HTMLElement*/el, /**String*/selector) { + if (el) { + selector = selector.split('.'); + + var tag = selector.shift().toUpperCase(), + re = new RegExp('\\s(' + selector.join('|') + ')(?=\\s)', 'g'); + + return ( + (tag === '' || el.nodeName.toUpperCase() == tag) && + (!selector.length || ((' ' + el.className + ' ').match(re) || []).length == selector.length) + ); + } + + return false; + } + + function _throttle(callback, ms) { + var args, _this; + + return function () { + if (args === void 0) { + args = arguments; + _this = this; + + setTimeout(function () { + if (args.length === 1) { + callback.call(_this, args[0]); + } else { + callback.apply(_this, args); + } + + args = void 0; + }, ms); + } + }; + } + + function _extend(dst, src) { + if (dst && src) { + for (var key in src) { + if (src.hasOwnProperty(key)) { + dst[key] = src[key]; + } + } + } + + return dst; + } + + function _clone(el) { + if (Polymer && Polymer.dom) { + return Polymer.dom(el).cloneNode(true); + } + else if ($) { + return $(el).clone(true)[0]; + } + else { + return el.cloneNode(true); + } + } + + function _saveInputCheckedState(root) { + var inputs = root.getElementsByTagName('input'); + var idx = inputs.length; + + while (idx--) { + var el = inputs[idx]; + el.checked && savedInputChecked.push(el); + } + } + + function _nextTick(fn) { + return setTimeout(fn, 0); + } + + function _cancelNextTick(id) { + return clearTimeout(id); + } + + // Fixed #973: + _on(document, 'touchmove', function (evt) { + if (KvSortable.active) { + evt.preventDefault(); + } + }); + + // Export utils + KvSortable.utils = { + on: _on, + off: _off, + css: _css, + find: _find, + is: function (el, selector) { + return !!_closest(el, selector, el); + }, + extend: _extend, + throttle: _throttle, + closest: _closest, + toggleClass: _toggleClass, + clone: _clone, + index: _index, + nextTick: _nextTick, + cancelNextTick: _cancelNextTick + }; + + + /** + * Create kvsortable instance + * @param {HTMLElement} el + * @param {Object} [options] + */ + KvSortable.create = function (el, options) { + return new KvSortable(el, options); + }; + + + // Export + KvSortable.version = '1.7.0'; + return KvSortable; +}); +/** + * jQuery plugin for KvSortable + */ +(function (factory) { + "use strict"; + + if (typeof define === "function" && define.amd) { + define(["jquery"], factory); + } + else { + /* jshint sub:true */ + factory(jQuery); + } +})(function ($) { + "use strict"; + $.fn.kvsortable = function (options) { + var retVal, + args = arguments; + + this.each(function () { + var $el = $(this), kvsortable = $el.data('kvsortable'); + + if (!kvsortable && (options instanceof Object || !options)) { + kvsortable = new KvSortable(this, options); + $el.data('kvsortable', kvsortable); + } + + if (kvsortable) { + if (options === 'widget') { + retVal = kvsortable; + } + else if (options === 'destroy') { + kvsortable.destroy(); + $el.removeData('kvsortable'); + } + else if (typeof kvsortable[options] === 'function') { + retVal = kvsortable[options].apply(kvsortable, [].slice.call(args, 1)); + } + else if (options in kvsortable.options) { + retVal = kvsortable.option.apply(kvsortable, args); + } + } + }); + + return (retVal === void 0) ? this : retVal; + }; +}); \ No newline at end of file diff --git a/src/main/resources/static/js/plugins/fileinput/plugins/sortable.min.js b/src/main/resources/static/js/plugins/fileinput/plugins/sortable.min.js new file mode 100644 index 000000000..602876a0d --- /dev/null +++ b/src/main/resources/static/js/plugins/fileinput/plugins/sortable.min.js @@ -0,0 +1 @@ +!function(t){"use strict";"function"==typeof define&&define.amd?define(t):"undefined"!=typeof module&&void 0!==module.exports?module.exports=t():window.KvSortable=t()}(function(){"use strict";function t(e,n){if(!e||!e.nodeType||1!==e.nodeType)throw"KvSortable: `el` must be HTMLElement, and not "+{}.toString.call(e);this.el=e,this.options=n=g({},n),e[U]=this;var i={group:Math.random(),sort:!0,disabled:!1,store:null,handle:null,scroll:!0,scrollSensitivity:30,scrollSpeed:10,draggable:/[uo]l/i.test(e.nodeName)?"li":">*",ghostClass:"kvsortable-ghost",chosenClass:"kvsortable-chosen",dragClass:"kvsortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,setData:function(t,e){t.setData("Text",e.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,forceFallback:!1,fallbackClass:"kvsortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==t.supportPointer};for(var r in i)!(r in n)&&(n[r]=i[r]);rt(n);for(var a in this)"_"===a.charAt(0)&&"function"==typeof this[a]&&(this[a]=this[a].bind(this));this.nativeDraggable=!n.forceFallback&&Z,o(e,"mousedown",this._onTapStart),o(e,"touchstart",this._onTapStart),n.supportPointer&&o(e,"pointerdown",this._onTapStart),this.nativeDraggable&&(o(e,"dragover",this),o(e,"dragenter",this)),ot.push(this._onDragOver),n.store&&this.sort(n.store.get(this))}function e(t,e){"clone"!==t.lastPullMode&&(e=!0),w&&w.state!==e&&(a(w,"display",e?"none":""),e||w.state&&(t.options.group.revertClone?(T.insertBefore(w,C),t._animate(_,w)):T.insertBefore(w,_)),w.state=e)}function n(t,e,n){if(t){n=n||W;do{if(">*"===e&&t.parentNode===n||f(t,e))return t}while(t=function(t){var e=t.host;return e&&e.nodeType?e:t.parentNode}(t))}return null}function o(t,e,n){t.addEventListener(e,n,G)}function i(t,e,n){t.removeEventListener(e,n,G)}function r(t,e,n){if(t)if(t.classList)t.classList[n?"add":"remove"](e);else{var o=(" "+t.className+" ").replace(L," ").replace(" "+e+" "," ");t.className=(o+(n?" "+e:"")).replace(L," ")}}function a(t,e,n){var o=t&&t.style;if(o){if(void 0===n)return W.defaultView&&W.defaultView.getComputedStyle?n=W.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];e in o||(e="-webkit-"+e),o[e]=n+("string"==typeof n?"":"px")}}function s(t,e,n){if(t){var o=t.getElementsByTagName(e),i=0,r=o.length;if(n)for(;i*"!==e&&!f(t,e)||n++;return n}function f(t,e){if(t){var n=(e=e.split(".")).shift().toUpperCase(),o=new RegExp("\\s("+e.join("|")+")(?=\\s)","g");return!(""!==n&&t.nodeName.toUpperCase()!=n||e.length&&((" "+t.className+" ").match(o)||[]).length!=e.length)}return!1}function p(t,e){var n,o;return function(){void 0===n&&(n=arguments,o=this,q(function(){1===n.length?t.call(o,n[0]):t.apply(o,n),n=void 0},e))}}function g(t,e){if(t&&e)for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}function v(t){return z&&z.dom?z.dom(t).cloneNode(!0):V?V(t).clone(!0)[0]:t.cloneNode(!0)}function m(t){return q(t,0)}function b(t){return clearTimeout(t)}if("undefined"==typeof window||!window.document)return function(){throw new Error("KvSortable.js requires a window with a document")};var _,D,y,w,T,C,S,E,k,x,N,B,P,Y,O,X,I,R,A,M,j={},L=/\s+/g,F=/left|right|inline/,U="KvSortable"+(new Date).getTime(),H=window,W=H.document,K=H.parseInt,q=H.setTimeout,V=H.jQuery||H.Zepto,z=H.Polymer,G=!1,Q=!1,Z="draggable"in W.createElement("div"),J=function(t){return!navigator.userAgent.match(/(?:Trident.*rv[ :]?11\.|msie)/i)&&(t=W.createElement("x"),t.style.cssText="pointer-events:auto","auto"===t.style.pointerEvents)}(),$=!1,tt=Math.abs,et=Math.min,nt=[],ot=[],it=p(function(t,e,n){if(n&&e.scroll){var o,i,r,a,s,l,c=n[U],d=e.scrollSensitivity,h=e.scrollSpeed,u=t.clientX,f=t.clientY,p=window.innerWidth,g=window.innerHeight;if(k!==n&&(E=e.scroll,k=n,x=e.scrollFn,!0===E)){E=n;do{if(E.offsetWidth-1:i==t)}}var n={},o=t.group;o&&"object"==typeof o||(o={name:o}),n.name=o.name,n.checkPull=e(o.pull,!0),n.checkPut=e(o.put),n.revertClone=o.revertClone,t.group=n};try{window.addEventListener("test",null,Object.defineProperty({},"passive",{get:function(){G={capture:!1,passive:Q=!1}}}))}catch(t){}return t.prototype={constructor:t,_onTapStart:function(t){var e,o=this,i=this.el,r=this.options,a=r.preventOnFilter,s=t.type,c=t.touches&&t.touches[0],d=(c||t).target,h=t.target.shadowRoot&&t.path&&t.path[0]||d,f=r.filter;if(function(t){for(var e=t.getElementsByTagName("input"),n=e.length;n--;){var o=e[n];o.checked&&nt.push(o)}}(i),!_&&!(/mousedown|pointerdown/.test(s)&&0!==t.button||r.disabled)&&!h.isContentEditable&&(d=n(d,r.draggable,i))&&S!==d){if(e=u(d,r.draggable),"function"==typeof f){if(f.call(this,t,d,this))return l(o,h,"filter",d,i,i,e),void(a&&t.preventDefault())}else if(f&&(f=f.split(",").some(function(t){if(t=n(h,t.trim(),i))return l(o,t,"filter",d,i,i,e),!0})))return void(a&&t.preventDefault());r.handle&&!n(h,r.handle,i)||this._prepareDragStart(t,c,d,e)}},_prepareDragStart:function(t,e,n,i){var a,c=this,h=c.el,u=c.options,f=h.ownerDocument;n&&!_&&n.parentNode===h&&(R=t,T=h,D=(_=n).parentNode,C=_.nextSibling,S=n,X=u.group,Y=i,this._lastX=(e||t).clientX,this._lastY=(e||t).clientY,_.style["will-change"]="all",a=function(){c._disableDelayedDrag(),_.draggable=c.nativeDraggable,r(_,u.chosenClass,!0),c._triggerDragStart(t,e),l(c,T,"choose",_,T,T,Y)},u.ignore.split(",").forEach(function(t){s(_,t.trim(),d)}),o(f,"mouseup",c._onDrop),o(f,"touchend",c._onDrop),o(f,"touchcancel",c._onDrop),o(f,"selectstart",c),u.supportPointer&&o(f,"pointercancel",c._onDrop),u.delay?(o(f,"mouseup",c._disableDelayedDrag),o(f,"touchend",c._disableDelayedDrag),o(f,"touchcancel",c._disableDelayedDrag),o(f,"mousemove",c._disableDelayedDrag),o(f,"touchmove",c._disableDelayedDrag),u.supportPointer&&o(f,"pointermove",c._disableDelayedDrag),c._dragStartTimer=q(a,u.delay)):a())},_disableDelayedDrag:function(){var t=this.el.ownerDocument;clearTimeout(this._dragStartTimer),i(t,"mouseup",this._disableDelayedDrag),i(t,"touchend",this._disableDelayedDrag),i(t,"touchcancel",this._disableDelayedDrag),i(t,"mousemove",this._disableDelayedDrag),i(t,"touchmove",this._disableDelayedDrag),i(t,"pointermove",this._disableDelayedDrag)},_triggerDragStart:function(t,e){(e=e||("touch"==t.pointerType?t:null))?(R={target:_,clientX:e.clientX,clientY:e.clientY},this._onDragStart(R,"touch")):this.nativeDraggable?(o(_,"dragend",this),o(T,"dragstart",this._onDragStart)):this._onDragStart(R,!0);try{W.selection?m(function(){W.selection.empty()}):window.getSelection().removeAllRanges()}catch(t){}},_dragStarted:function(){if(T&&_){var e=this.options;r(_,e.ghostClass,!0),r(_,e.dragClass,!1),t.active=this,l(this,T,"start",_,T,T,Y)}else this._nulling()},_emulateDragOver:function(){if(A){if(this._lastX===A.clientX&&this._lastY===A.clientY)return;this._lastX=A.clientX,this._lastY=A.clientY,J||a(y,"display","none");var t=W.elementFromPoint(A.clientX,A.clientY),e=t,n=ot.length;if(t&&t.shadowRoot&&(e=t=t.shadowRoot.elementFromPoint(A.clientX,A.clientY)),e)do{if(e[U]){for(;n--;)ot[n]({clientX:A.clientX,clientY:A.clientY,target:t,rootEl:e});break}t=e}while(e=e.parentNode);J||a(y,"display","")}},_onTouchMove:function(e){if(R){var n=this.options,o=n.fallbackTolerance,i=n.fallbackOffset,r=e.touches?e.touches[0]:e,s=r.clientX-R.clientX+i.x,l=r.clientY-R.clientY+i.y,c=e.touches?"translate3d("+s+"px,"+l+"px,0)":"translate("+s+"px,"+l+"px)";if(!t.active){if(o&&et(tt(r.clientX-this._lastX),tt(r.clientY-this._lastY))5||e.clientX-(n.left+n.width)>5}(d,o)){if(0!==d.children.length&&d.children[0]!==y&&d===o.target&&(i=d.lastElementChild),i){if(i.animated)return;s=i.getBoundingClientRect()}e(p,g),!1!==c(T,d,_,r,i,s,o)&&(_.contains(d)||(d.appendChild(_),D=d),this._animate(r,_),i&&this._animate(s,i))}else if(i&&!i.animated&&i!==_&&void 0!==i.parentNode[U]){N!==i&&(N=i,B=a(i),P=a(i.parentNode));var b=(s=i.getBoundingClientRect()).right-s.left,S=s.bottom-s.top,E=F.test(B.cssFloat+B.display)||"flex"==P.display&&0===P["flex-direction"].indexOf("row"),k=i.offsetWidth>_.offsetWidth,x=i.offsetHeight>_.offsetHeight,Y=(E?(o.clientX-s.left)/b:(o.clientY-s.top)/S)>.5,O=i.nextElementSibling,R=!1;if(E){var A=_.offsetTop,j=i.offsetTop;R=A===j?i.previousElementSibling===_&&!k||Y&&k:i.previousElementSibling===_||_.previousElementSibling===i?(o.clientY-s.top)/S>.5:j>A}else v||(R=O!==_&&!x||Y&&x);var L=c(T,d,_,r,i,s,o,R);!1!==L&&(1!==L&&-1!==L||(R=1===L),$=!0,q(h,30),e(p,g),_.contains(d)||(R&&!O?d.appendChild(_):i.parentNode.insertBefore(_,R?O:i)),D=_.parentNode,this._animate(r,_),this._animate(s,i))}}},_animate:function(t,e){var n=this.options.animation;if(n){var o=e.getBoundingClientRect();1===t.nodeType&&(t=t.getBoundingClientRect()),a(e,"transition","none"),a(e,"transform","translate3d("+(t.left-o.left)+"px,"+(t.top-o.top)+"px,0)"),e.offsetWidth,a(e,"transition","all "+n+"ms"),a(e,"transform","translate3d(0,0,0)"),clearTimeout(e.animated),e.animated=q(function(){a(e,"transition",""),a(e,"transform",""),e.animated=!1},n)}},_offUpEvents:function(){var t=this.el.ownerDocument;i(W,"touchmove",this._onTouchMove),i(W,"pointermove",this._onTouchMove),i(t,"mouseup",this._onDrop),i(t,"touchend",this._onDrop),i(t,"pointerup",this._onDrop),i(t,"touchcancel",this._onDrop),i(t,"pointercancel",this._onDrop),i(t,"selectstart",this)},_onDrop:function(e){var n=this.el,o=this.options;clearInterval(this._loopId),clearInterval(j.pid),clearTimeout(this._dragStartTimer),b(this._cloneId),b(this._dragStartId),i(W,"mouseover",this),i(W,"mousemove",this._onTouchMove),this.nativeDraggable&&(i(W,"drop",this),i(n,"dragstart",this._onDragStart)),this._offUpEvents(),e&&(M&&(e.preventDefault(),!o.dropBubble&&e.stopPropagation()),y&&y.parentNode&&y.parentNode.removeChild(y),T!==D&&"clone"===t.active.lastPullMode||w&&w.parentNode&&w.parentNode.removeChild(w),_&&(this.nativeDraggable&&i(_,"dragend",this),d(_),_.style["will-change"]="",r(_,this.options.ghostClass,!1),r(_,this.options.chosenClass,!1),l(this,T,"unchoose",_,D,T,Y),T!==D?(O=u(_,o.draggable))>=0&&(l(null,D,"add",_,D,T,Y,O),l(this,T,"remove",_,D,T,Y,O),l(null,D,"sort",_,D,T,Y,O),l(this,T,"sort",_,D,T,Y,O)):_.nextSibling!==C&&(O=u(_,o.draggable))>=0&&(l(this,T,"update",_,D,T,Y,O),l(this,T,"sort",_,D,T,Y,O)),t.active&&(null!=O&&-1!==O||(O=Y),l(this,T,"end",_,D,T,Y,O),this.save()))),this._nulling()},_nulling:function(){T=_=D=y=C=w=S=E=k=R=A=M=O=N=B=I=X=t.active=null,nt.forEach(function(t){t.checked=!0}),nt.length=0},handleEvent:function(t){switch(t.type){case"drop":case"dragend":this._onDrop(t);break;case"dragover":case"dragenter":_&&(this._onDragOver(t),function(t){t.dataTransfer&&(t.dataTransfer.dropEffect="move"),t.preventDefault()}(t));break;case"mouseover":this._onDrop(t);break;case"selectstart":t.preventDefault()}},toArray:function(){for(var t,e=[],o=this.el.children,i=0,r=o.length,a=this.options;i仅仅支持单个文件同时上传',//重新定义提示 + msgFilesTooMany: '选择上传的文件数量({n}) 超过允许的最大数值{m}!', + allowedFileExtensions: ["xls", "xlsx"], + uploadUrl: prefix+'/batchAdd' + }); +} /*用户管理-部门*/ function dept() { var url = ctx + "system/dept"; @@ -144,6 +165,42 @@ function add() { var url = prefix + '/add'; layer_showAuto("新增用户", url); } +/*用户管理-批量新增*/ +function batchAdd() { + //文件默认上传方法,传ID:uploadfile + $('#uploadfile').fileinput("upload"); + //同步上传错误处理 + $('#uploadfile').on('filebatchuploaderror', function(event, data, msg) { + // get message + $.modalAlert(msg, "error"); + //重置 + $('#uploadfile').fileinput("clear"); + $('#uploadfile').fileinput("reset"); + $('#uploadfile').fileinput('refresh'); + $('#uploadfile').fileinput('enable'); + }); + //同步上传后从后台返回结果 + $('#uploadfile').on('filebatchuploadsuccess', function(event, data, previewId, index) { + var result = data.response; + if (result.code == 0) { + //刷新数据表格 + $('.bootstrap-table').bootstrapTable('refresh'); + var count = result.msg; + $.modalAlert("成功导入" +count+ "条数据","success"); + $('#uploadfile').fileinput('reset'); + $('#exampleModal').modal('hide'); + + } else { + $.modalAlert(result.msg, "error"); + //重置 + $('#uploadfile').fileinput("clear"); + $('#uploadfile').fileinput("reset"); + $('#uploadfile').fileinput('refresh'); + $('#uploadfile').fileinput('enable'); + } + }); + +} /*用户管理-重置密码*/ function resetPwd(userId) { diff --git a/src/main/resources/static/template/用户导入模板.xlsx b/src/main/resources/static/template/用户导入模板.xlsx new file mode 100644 index 000000000..5153758f5 Binary files /dev/null and b/src/main/resources/static/template/用户导入模板.xlsx differ diff --git a/src/main/resources/templates/system/user/profile/avatar.html b/src/main/resources/templates/system/user/profile/avatar.html index 226024593..09d0f8b07 100644 --- a/src/main/resources/templates/system/user/profile/avatar.html +++ b/src/main/resources/templates/system/user/profile/avatar.html @@ -39,7 +39,7 @@ $(window).load(function() { options.imgSrc = e.target.result; //根据MIME判断上传的文件是不是图片类型 if((options.imgSrc).indexOf("image/")==-1){ - alert("错误提示\n" + " 请上传图片类型!"); + parent.layer.alert("文件格式错误,请上传图片类型,如:JPG,JEPG,PNG后缀的文件。", {icon: 2,title:"系统提示"}); } else { cropper = $('.imageBox').cropbox(options); } diff --git a/src/main/resources/templates/system/user/user.html b/src/main/resources/templates/system/user/user.html index caa6215d9..d1f5c548d 100644 --- a/src/main/resources/templates/system/user/user.html +++ b/src/main/resources/templates/system/user/user.html @@ -6,6 +6,9 @@ + + + @@ -33,6 +36,10 @@ 新增 + + 批量新增 + + 删除 @@ -43,10 +50,46 @@ data-sort-name="create_time" data-sort-order="desc"> + + + + + + + 导入Execl表 + + × + + + 用户导入模板.xlsx + + + + + + + + + + + + + + + + + + + + +
' + text + '
{errors}
"+s+"