diff --git a/activiti/src/main/resources/template/js/actFlow/actFlowAdd.js b/activiti/src/main/resources/template/js/actFlow/actFlowAdd.js new file mode 100644 index 0000000000000000000000000000000000000000..39b0f3b0ebc478b9cdf43bc78d9605c7ec3b03b5 --- /dev/null +++ b/activiti/src/main/resources/template/js/actFlow/actFlowAdd.js @@ -0,0 +1,79 @@ + +// 关联的工作流业务模型 +var skyeyeClassFlowableMation = {}; + +layui.config({ + base: basePath, + version: skyeyeVersion +}).extend({ + window: 'js/winui.window' +}).define(['window', 'jquery', 'winui', 'form'], function (exports) { + winui.renderColor(); + var index = parent.layer.getFrameIndex(window.name); + var $ = layui.$, + form = layui.form; + + form.on('radio(businessLinkType)', function (data) { + var val = data.value; + if (val == '1') { + // 不关联业务数据 + $(".business").addClass("layui-hide"); + } else if (val == '2') { + // 关联业务数据 + $(".business").removeClass("layui-hide"); + } + }); + + matchingLanguage(); + form.render(); + form.on('submit(formAddBean)', function (data) { + if (winui.verifyForm(data.elem)) { + var params = { + flowName: $("#flowName").val(), + modelKey: $("#modelKey").val(), + businessLinkType: data.field.businessLinkType + }; + if (params.businessLinkType == 2) { + params.serviceClassName = $("#serviceClassName").attr("className"); + params.businessKey = $("#businessKey").val(); + params.businessData = $("#businessData").val(); + if (isNull(params.serviceClassName)) { + winui.window.msg("请选择工作流业务模型", {icon: 2, time: 2000}); + return false; + } + if (isNull(params.businessKey)) { + winui.window.msg("请输入属性字段", {icon: 2, time: 2000}); + return false; + } + if (isNull(params.businessData)) { + winui.window.msg("请输入属性值", {icon: 2, time: 2000}); + return false; + } + params.dsFormId = ""; + } + + AjaxPostUtil.request({url: flowableBasePath + "writeActFlowMation", params: params, type: 'json', method: 'POST', callback: function (json) { + parent.layer.close(index); + parent.refreshCode = '0'; + }}); + } + return false; + }); + + // 工作流业务模型选择 + $("body").on("click", "#serviceClassNameSel", function (e) { + _openNewWindows({ + url: "../../tpl/skyeyeClassFlowable/skyeyeClassFlowableChoose.html", + title: "工作流业务模型选择", + pageId: "skyeyeClassFlowableChoose", + area: ['90vw', '90vh'], + callBack: function (refreshCode) { + $("#serviceClassName").val(skyeyeClassFlowableMation.serviceName); + $("#serviceClassName").attr("className", skyeyeClassFlowableMation.className); + }}); + }); + + $("body").on("click", "#cancle", function() { + parent.layer.close(index); + }); +}); \ No newline at end of file diff --git a/activiti/src/main/resources/template/js/actFlow/actFlowEdit.js b/activiti/src/main/resources/template/js/actFlow/actFlowEdit.js new file mode 100644 index 0000000000000000000000000000000000000000..6f958054cd6128c413a0cab9f8b6366b7bec1411 --- /dev/null +++ b/activiti/src/main/resources/template/js/actFlow/actFlowEdit.js @@ -0,0 +1,86 @@ + +layui.config({ + base: basePath, + version: skyeyeVersion +}).extend({ + window: 'js/winui.window' +}).define(['window', 'jquery', 'winui', 'form'], function (exports) { + winui.renderColor(); + var index = parent.layer.getFrameIndex(window.name); + var $ = layui.$, + form = layui.form; + + showGrid({ + id: "showForm", + url: flowableBasePath + "queryActFlowMationById", + params: {id: parent.rowId}, + method: 'GET', + pagination: false, + template: $("#beanTemplate").html(), + ajaxSendAfter:function (json) { + if (json.bean.businessLinkType == 1) { + // 不关联业务数据 + $("#businessLinkType").html('否'); + $(".business").addClass("layui-hide"); + } else if (json.bean.businessLinkType == 2) { + // 关联业务数据 + $("#businessLinkType").html('是'); + $(".business").removeClass("layui-hide"); + } + + matchingLanguage(); + form.render(); + form.on('submit(formEditBean)', function (data) { + if (winui.verifyForm(data.elem)) { + var params = { + id: parent.rowId, + flowName: $("#flowName").val(), + modelKey: $("#modelKey").val(), + businessLinkType: json.bean.businessLinkType + }; + if (params.businessLinkType == 2) { + params.serviceClassName = $("#serviceClassName").attr("className"); + params.businessKey = $("#businessKey").val(); + params.businessData = $("#businessData").val(); + if (isNull(params.serviceClassName)) { + winui.window.msg("请选择工作流业务模型", {icon: 2, time: 2000}); + return false; + } + if (isNull(params.businessKey)) { + winui.window.msg("请输入属性字段", {icon: 2, time: 2000}); + return false; + } + if (isNull(params.businessData)) { + winui.window.msg("请输入属性值", {icon: 2, time: 2000}); + return false; + } + params.dsFormId = ""; + } + + AjaxPostUtil.request({url: flowableBasePath + "writeActFlowMation", params: params, type: 'json', method: 'POST', callback: function (json) { + parent.layer.close(index); + parent.refreshCode = '0'; + }}); + } + return false; + }); + } + }); + + // 工作流业务模型选择 + $("body").on("click", "#serviceClassNameSel", function (e) { + _openNewWindows({ + url: "../../tpl/skyeyeClassFlowable/skyeyeClassFlowableChoose.html", + title: "工作流业务模型选择", + pageId: "skyeyeClassFlowableChoose", + area: ['90vw', '90vh'], + callBack: function (refreshCode) { + $("#serviceClassName").val(skyeyeClassFlowableMation.serviceName); + $("#serviceClassName").attr("className", skyeyeClassFlowableMation.className); + }}); + }); + + $("body").on("click", "#cancle", function() { + parent.layer.close(index); + }); +}); \ No newline at end of file diff --git a/activiti/src/main/resources/template/js/actFlow/actFlowList.js b/activiti/src/main/resources/template/js/actFlow/actFlowList.js new file mode 100644 index 0000000000000000000000000000000000000000..a6f1fd6b7074a298fdcd67993e8c67c9e986581c --- /dev/null +++ b/activiti/src/main/resources/template/js/actFlow/actFlowList.js @@ -0,0 +1,184 @@ + +layui.config({ + base: basePath, + version: skyeyeVersion +}).extend({ + window: 'js/winui.window' +}).define(['window', 'table', 'jquery', 'winui', 'form'], function (exports) { + winui.renderColor(); + var $ = layui.$, + form = layui.form, + table = layui.table; + + // 流程模型列表 + authBtn('1552960740348'); + table.render({ + id: 'messageTable', + elem: '#messageTable', + method: 'post', + url: flowableBasePath + 'queryActFlowList', + where: getTableParams(), + even: true, + page: true, + limits: getLimits(), + limit: getLimit(), + cols: [[ + { title: systemLanguage["com.skyeye.serialNumber"][languageType], type: 'numbers', rowspan: '2' }, + { colspan: '4', title: '模型信息', align: 'center'}, + { colspan: '2', title: '发布信息', align: 'center'}, + { field: 'createName', title: systemLanguage["com.skyeye.createName"][languageType], width: 120, rowspan: '2' }, + { field: 'createTime', title: systemLanguage["com.skyeye.createTime"][languageType], align: 'center', width: 150, rowspan: '2' }, + { field: 'lastUpdateName', title: systemLanguage["com.skyeye.lastUpdateName"][languageType], align: 'left', width: 120, rowspan: '2' }, + { field: 'lastUpdateTime', title: systemLanguage["com.skyeye.lastUpdateTime"][languageType], align: 'center', width: 150, rowspan: '2' }, + { title: systemLanguage["com.skyeye.operation"][languageType], fixed: 'right', align: 'center', width: 340, toolbar: '#tableBar', rowspan: '2' } + ], [ + { field: 'flowName', title: '模型名称', width: 150 }, + { field: 'modelId', title: '模型ID', width: 100 }, + { field: 'modelKey', title: '模型key', width: 250 }, + { field: 'version', title: '版本', width: 80, templet: function (d) {return d.model.version}}, + { field: 'deploymentId', title: '发布状态', align: "center", width: 80, templet: function (d) { + if (isNull(d.model.deploymentId)) { + return "未发布"; + } else { + return "已发布"; + } + }}, + { field: 'processDefinitionVersion', title: '版本', width: 100, templet: function (d) { + if (isNull(d.procdef) || isNull(d.procdef.version)) { + return ''; + } + return d.procdef.version + }} + ]], + done: function(json) { + matchingLanguage(); + initTableSearchUtil.initAdvancedSearch(this, json.searchFilter, form, "请输入名称,模型key", function () { + table.reloadData("messageTable", {page: {curr: 1}, where: getTableParams()}); + }); + } + }); + + table.on('tool(messageTable)', function (obj) { + var data = obj.data; + var layEvent = obj.event; + if (layEvent === 'del') { //删除 + del(data, obj); + } else if (layEvent === 'edit') { //编辑 + edit(data); + } else if (layEvent === 'modelDesign') { // 流程设计 + modelDesign(data); + } else if (layEvent === 'fb') { //发布 + fb(data); + } else if (layEvent === 'versionLevel') { //版本升级 + versionLevel(data); + } else if (layEvent === 'qxfb') { // 取消发布 + qxfb(data); + } else if (layEvent === 'ecportXML') { //导出xml + ecportXML(data); + } + }); + + // 删除 + function del(data, obj) { + layer.confirm(systemLanguage["com.skyeye.deleteOperationMsg"][languageType], {icon: 3, title: systemLanguage["com.skyeye.deleteOperation"][languageType]}, function (index) { + layer.close(index); + AjaxPostUtil.request({url: flowableBasePath + "deleteActFlowMationById", params: {id: data.id}, type: 'json', method: 'DELETE', callback: function (json) { + winui.window.msg(systemLanguage["com.skyeye.deleteOperationSuccessMsg"][languageType], {icon: 1, time: 2000}); + loadTable(); + }}); + }); + } + + // 发布 + function fb(data) { + layer.confirm('确认发布选中数据吗?', { icon: 3, title: '发布模型' }, function (index) { + layer.close(index); + AjaxPostUtil.request({url: flowableBasePath + "activitimode003", params: {modelId: data.modelId}, type: 'json', callback: function (json) { + winui.window.msg("发布成功", {icon: 1, time: 2000}); + loadTable(); + }}); + }); + } + + // 版本升级 + function versionLevel(data) { + layer.confirm('确认升级选中数据吗?', { icon: 3, title: '版本升级' }, function (index) { + layer.close(index); + AjaxPostUtil.request({url: flowableBasePath + "activitimode003", params: {modelId: data.modelId}, type: 'json', callback: function (json) { + winui.window.msg("升级成功", {icon: 1, time: 2000}); + loadTable(); + }}); + }); + } + + // 取消发布 + function qxfb(data){ + layer.confirm('确认取消发布选中数据吗?', { icon: 3, title: '取消发布' }, function (index) { + layer.close(index); + AjaxPostUtil.request({url: flowableBasePath + "activitimode007", params: {deploymentId: data.deploymentId}, type: 'json', callback: function (json) { + winui.window.msg("取消发布成功", {icon: 1, time: 2000}); + loadTable(); + }}); + }); + } + + // 导出xml + function ecportXML(data) { + window.open(flowableBasePath + "activitimode010?modelId=" + data.modelId); + } + + // 新增 + $("body").on("click", "#addBean", function() { + _openNewWindows({ + url: "../../tpl/actFlow/actFlowAdd.html", + title: systemLanguage["com.skyeye.addPageTitle"][languageType], + pageId: "actFlowAdd", + area: ['90vw', '90vh'], + callBack: function (refreshCode) { + winui.window.msg(systemLanguage["com.skyeye.successfulOperation"][languageType], {icon: 1, time: 2000}); + loadTable(); + }}); + }); + + // 编辑 + function edit(data) { + rowId = data.id; + _openNewWindows({ + url: "../../tpl/actFlow/actFlowEdit.html", + title: systemLanguage["com.skyeye.editPageTitle"][languageType], + pageId: "actFlowEdit", + area: ['90vw', '90vh'], + callBack: function (refreshCode) { + winui.window.msg(systemLanguage["com.skyeye.successfulOperation"][languageType], {icon: 1, time: 2000}); + loadTable(); + }}); + } + + // 流程设计 + function modelDesign(data) { + _openNewWindows({ + url: "../../static/modeler.html?modelId=" + data.modelId, + title: "绘制流程", + pageId: "canverActivitiModel", + area: ['100vw', '100vh'], + callBack: function (refreshCode) { + winui.window.msg(systemLanguage["com.skyeye.successfulOperation"][languageType], {icon: 1, time: 2000}); + loadTable(); + } + }); + } + + form.render(); + $("body").on("click", "#reloadTable", function() { + loadTable(); + }); + function loadTable() { + table.reloadData("messageTable", {where: getTableParams()}); + } + + function getTableParams() { + return $.extend(true, {}, initTableSearchUtil.getSearchValue("messageTable")); + } + + exports('actFlowList', {}); +}); diff --git a/activiti/src/main/resources/template/js/activitimodel/activitimodellist.js b/activiti/src/main/resources/template/js/activitimodel/activitimodellist.js deleted file mode 100644 index f7c97ba51f9cf19395bad4f09f1fb93d778c2ff3..0000000000000000000000000000000000000000 --- a/activiti/src/main/resources/template/js/activitimodel/activitimodellist.js +++ /dev/null @@ -1,194 +0,0 @@ - -layui.config({ - base: basePath, - version: skyeyeVersion -}).extend({ - window: 'js/winui.window' -}).define(['window', 'table', 'jquery', 'winui', 'form'], function (exports) { - winui.renderColor(); - var $ = layui.$, - form = layui.form, - table = layui.table; - - // 流程设计列表 - authBtn('1552960740348'); - table.render({ - id: 'messageTable', - elem: '#messageTable', - method: 'post', - url: flowableBasePath + 'activitimode002', - where: getTableParams(), - even: true, - page: true, - limits: getLimits(), - limit: getLimit(), - cols: [[ - { title: systemLanguage["com.skyeye.serialNumber"][languageType], type: 'numbers' }, - { field: 'id', title: '模型编号', width: 100 }, - { field: 'name', title: '模型名称', width: 150 }, - { field: 'key', title: '编码', width: 120 }, - { field: 'processKey', title: 'key', width: 250 }, - { field: 'version', title: '版本', width: 80}, - { field: 'deploymentId', title: '发布状态', align: "center", width: 80, templet: function (d) { - if(isNull(d.deploymentId)){ - return "未发布"; - } else { - return "已发布"; - } - }}, - { field: 'deploymentId', title: '部署id', width: 100}, - { field: 'processDefinitionVersion', title: '部署版本', width: 100}, - { field: 'createTime', title: systemLanguage["com.skyeye.createTime"][languageType], align: 'center', width: 150 }, - { field: 'metaInfo', title: '元数据', width: 120}, - { title: systemLanguage["com.skyeye.operation"][languageType], fixed: 'right', align: 'center', width: 340, toolbar: '#tableBar'} - ]], - done: function(json) { - matchingLanguage(); - } - }); - - table.on('tool(messageTable)', function (obj) { - var data = obj.data; - var layEvent = obj.event; - if (layEvent === 'del') { //删除 - del(data, obj); - } else if (layEvent === 'edit') { //编辑 - edit(data); - } else if (layEvent === 'copyModel') { //模型拷贝 - copyModel(data); - } else if (layEvent === 'fb') { //发布 - fb(data); - } else if (layEvent === 'versionLevel') { //版本升级 - versionLevel(data); - } else if (layEvent === 'qxfb') { // 取消发布 - qxfb(data); - } else if (layEvent === 'ecportXML') { //导出xml - ecportXML(data); - } - }); - - form.render(); - form.on('submit(formSearch)', function (data) { - if (winui.verifyForm(data.elem)) { - refreshTable(); - } - return false; - }); - - // 刷新数据 - $("body").on("click", "#reloadTable", function() { - loadTable(); - }); - - //删除 - function del(data, obj) { - var msg = obj ? '确认删除模型【' + obj.data.name + '】吗?' : '确认删除选中数据吗?'; - layer.confirm(msg, { icon: 3, title: '删除模型' }, function (index) { - layer.close(index); - AjaxPostUtil.request({url: flowableBasePath + "activitimode006", params: {rowId: data.id}, type: 'json', callback: function (json) { - winui.window.msg(systemLanguage["com.skyeye.deleteOperationSuccessMsg"][languageType], {icon: 1, time: 2000}); - loadTable(); - }}); - }); - } - - //编辑 - function edit(data) { - rowId = data.id; - _openNewWindows({ - url: "../../static/modeler.html?modelId=" + rowId, - title: "绘制流程", - pageId: "canveractivitimodeledit", - area: ['100vw', '100vh'], - callBack: function (refreshCode) { - winui.window.msg(systemLanguage["com.skyeye.successfulOperation"][languageType], {icon: 1, time: 2000}); - loadTable(); - }}); - } - - //发布 - function fb(data) { - rowId = data.id; - var msg = data ? '确认发布模型【' + data.name + '】吗?' : '确认发布选中数据吗?'; - layer.confirm(msg, { icon: 3, title: '发布模型' }, function (index) { - layer.close(index); - AjaxPostUtil.request({url: flowableBasePath + "activitimode003", params: {modelId: rowId}, type: 'json', callback: function (json) { - winui.window.msg("发布成功", {icon: 1, time: 2000}); - loadTable(); - }}); - }); - } - - //版本升级 - function versionLevel(data) { - rowId = data.id; - var msg = data ? '确认升级模型【' + data.name + '】版本吗?' : '确认升级选中数据吗?'; - layer.confirm(msg, { icon: 3, title: '版本升级' }, function (index) { - layer.close(index); - AjaxPostUtil.request({url: flowableBasePath + "activitimode003", params: {modelId: rowId}, type: 'json', callback: function (json) { - winui.window.msg("升级成功", {icon: 1, time: 2000}); - loadTable(); - }}); - }); - } - - // 取消发布 - function qxfb(data, obj){ - var msg = obj ? '确认取消发布【' + obj.data.name + '】吗?' : '确认取消发布选中数据吗?'; - layer.confirm(msg, { icon: 3, title: '取消发布' }, function (index) { - layer.close(index); - AjaxPostUtil.request({url: flowableBasePath + "activitimode007", params: {deploymentId: data.deploymentId}, type: 'json', callback: function (json) { - winui.window.msg("取消发布成功", {icon: 1, time: 2000}); - loadTable(); - }}); - }); - } - - // 拷贝模型 - function copyModel(data) { - layer.confirm('确认拷贝选中数据吗?', { icon: 3, title: '模型拷贝' }, function (index) { - layer.close(index); - AjaxPostUtil.request({url: flowableBasePath + "activitimode028", params: {modelId: data.id}, type: 'json', callback: function (json) { - winui.window.msg("拷贝成功", {icon: 1, time: 2000}); - loadTable(); - }}); - }); - } - - // 导出xml - function ecportXML(data) { - window.open(flowableBasePath + "activitimode010?modelId=" + data.id); - } - - //新增 - $("body").on("click", "#addBean", function() { - AjaxPostUtil.request({url: flowableBasePath + "activitimode001", params: {}, type: 'json', callback: function (json) { - _openNewWindows({ - url: "../../static/modeler.html?modelId=" + json.bean.id, - title: "绘制流程", - pageId: "canveractivitimodel", - area: ['100vw', '100vh'], - callBack: function (refreshCode) { - winui.window.msg(systemLanguage["com.skyeye.successfulOperation"][languageType], {icon: 1, time: 2000}); - loadTable(); - }}); - }}); - }); - - function loadTable() { - table.reloadData("messageTable", {where: getTableParams()}); - } - - // 搜索 - function refreshTable(){ - table.reloadData("messageTable", {page: {curr: 1}, where: getTableParams()}) - } - - function getTableParams() { - return { - modelName: $("#modelName").val() - }; - } - - exports('codemodellist', {}); -}); diff --git a/activiti/src/main/resources/template/js/skyeyeClassFlowable/skyeyeClassFlowableChoose.js b/activiti/src/main/resources/template/js/skyeyeClassFlowable/skyeyeClassFlowableChoose.js new file mode 100644 index 0000000000000000000000000000000000000000..8876df18e3af46151cf8bbbc42f4c417bf4b6c44 --- /dev/null +++ b/activiti/src/main/resources/template/js/skyeyeClassFlowable/skyeyeClassFlowableChoose.js @@ -0,0 +1,70 @@ + +layui.config({ + base: basePath, + version: skyeyeVersion +}).extend({ + window: 'js/winui.window' +}).define(['window', 'table', 'jquery', 'winui', 'form'], function (exports) { + winui.renderColor(); + var index = parent.layer.getFrameIndex(window.name); + var $ = layui.$, + form = layui.form, + table = layui.table; + + table.render({ + id: 'messageTable', + elem: '#messageTable', + method: 'post', + url: reqBasePath + 'queryClassFlowableDataList', + where: getTableParams(), + even: true, + page: true, + limits: getLimits(), + limit: getLimit(), + cols: [[ + { type: 'radio', fixed: 'left'}, + { title: systemLanguage["com.skyeye.serialNumber"][languageType], fixed: 'left', type: 'numbers' }, + { field: 'serviceName', title: '服务名', align: 'center', width: 150}, + { field: 'className', title: '服务', width: 400} + ]], + done: function(res) { + matchingLanguage(); + + initTableSearchUtil.initAdvancedSearch(this, res.searchFilter, form, "请输入服务名", function () { + table.reloadData("messageTable", {page: {curr: 1}, where: getTableParams()}); + }); + $('#messageTable').next().find('.layui-table-body').find("table" ).find("tbody").children("tr").on('dblclick',function() { + var dubClick = $('#messageTable').next().find('.layui-table-body').find("table").find("tbody").find(".layui-table-hover"); + dubClick.find("input[type='radio']").prop("checked", true); + form.render(); + var chooseIndex = JSON.stringify(dubClick.data('index')); + var obj = res.rows[chooseIndex]; + parent.skyeyeClassFlowableMation = obj; + + parent.refreshCode = '0'; + parent.layer.close(index); + }); + + $('#messageTable').next().find('.layui-table-body').find("table" ).find("tbody").children("tr").on('click',function() { + var click = $('#messageTable').next().find('.layui-table-body').find("table").find("tbody").find(".layui-table-hover"); + click.find("input[type='radio']").prop("checked", true); + form.render(); + }); + } + }); + + form.render(); + $("body").on("click", "#reloadTable", function() { + loadTable(); + }); + + function loadTable() { + table.reloadData("messageTable", {where: getTableParams()}); + } + + function getTableParams() { + return $.extend(true, {}, initTableSearchUtil.getSearchValue("messageTable")); + } + + exports('skyeyeClassFlowableChoose', {}); +}); \ No newline at end of file diff --git a/activiti/src/main/resources/template/tpl/actFlow/actFlowAdd.html b/activiti/src/main/resources/template/tpl/actFlow/actFlowAdd.html new file mode 100644 index 0000000000000000000000000000000000000000..f0a1c6f32ec7954f5438a652e3ff053f18d8744a --- /dev/null +++ b/activiti/src/main/resources/template/tpl/actFlow/actFlowAdd.html @@ -0,0 +1,67 @@ + + + + + + + + + +
+
+
+ +
+ +
+
+
+ +
+ +
在系统中保持唯一。
+
+
+
+ +
+ + +
该选项确定后无法更换
+
+
+
+ +
+ + +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+
+ + +
+
+
+
+ + + + + \ No newline at end of file diff --git a/activiti/src/main/resources/template/tpl/actFlow/actFlowEdit.html b/activiti/src/main/resources/template/tpl/actFlow/actFlowEdit.html new file mode 100644 index 0000000000000000000000000000000000000000..f04ab5f7b641a10b23fc7f8ae24fafa71adf0db7 --- /dev/null +++ b/activiti/src/main/resources/template/tpl/actFlow/actFlowEdit.html @@ -0,0 +1,73 @@ + + + + + + + + + +
+
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/activiti/src/main/resources/template/tpl/activitimodel/activitimodellist.html b/activiti/src/main/resources/template/tpl/actFlow/actFlowList.html similarity index 56% rename from activiti/src/main/resources/template/tpl/activitimodel/activitimodellist.html rename to activiti/src/main/resources/template/tpl/actFlow/actFlowList.html index f445053de222325bd517e7396cc3eec991acf4a0..764d4c782759ed9fa1c14819d7197107d2438711 100644 --- a/activiti/src/main/resources/template/tpl/activitimodel/activitimodellist.html +++ b/activiti/src/main/resources/template/tpl/actFlow/actFlowList.html @@ -8,35 +8,21 @@ -
-
-
-
- -
- -
- - -
-
-
-
- - + +
\ No newline at end of file diff --git a/activiti/src/main/resources/template/tpl/activitimodel/chooseagentgroup.html b/activiti/src/main/resources/template/tpl/actFlow/chooseAgentGroup.html similarity index 100% rename from activiti/src/main/resources/template/tpl/activitimodel/chooseagentgroup.html rename to activiti/src/main/resources/template/tpl/actFlow/chooseAgentGroup.html diff --git a/activiti/src/main/resources/template/tpl/activitimodel/chooseagentpeople.html b/activiti/src/main/resources/template/tpl/actFlow/chooseAgentPeople.html similarity index 100% rename from activiti/src/main/resources/template/tpl/activitimodel/chooseagentpeople.html rename to activiti/src/main/resources/template/tpl/actFlow/chooseAgentPeople.html diff --git a/activiti/src/main/resources/template/tpl/skyeyeClassFlowable/skyeyeClassFlowableChoose.html b/activiti/src/main/resources/template/tpl/skyeyeClassFlowable/skyeyeClassFlowableChoose.html new file mode 100644 index 0000000000000000000000000000000000000000..9aa214a31cd8e309121d5dd37120795a2263e36d --- /dev/null +++ b/activiti/src/main/resources/template/tpl/skyeyeClassFlowable/skyeyeClassFlowableChoose.html @@ -0,0 +1,27 @@ + + + + + + + + + +
双击要选择的数据即可选中。
+
+
+ +
+
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/admin-assistant/src/main/resources/template/js/assetManage/assetManageChoose.js b/admin-assistant/src/main/resources/template/js/assetManage/assetManageChoose.js index bfdc5bca45b5f541595ffa0e77f62d08e6948f28..e2b6bf8d4c62320ea5abe81c763fb7b908b3a44f 100644 --- a/admin-assistant/src/main/resources/template/js/assetManage/assetManageChoose.js +++ b/admin-assistant/src/main/resources/template/js/assetManage/assetManageChoose.js @@ -55,8 +55,8 @@ layui.config({ limits: getLimits(), limit: getLimit(), cols: [[ - { type: assetCheckType ? 'checkbox' : 'radio', rowspan: '3', fixed: 'left'}, - { title: systemLanguage["com.skyeye.serialNumber"][languageType], rowspan: '3', fixed: 'left', type: 'numbers' }, + { type: assetCheckType ? 'checkbox' : 'radio', fixed: 'left'}, + { title: systemLanguage["com.skyeye.serialNumber"][languageType], fixed: 'left', type: 'numbers' }, { field: 'assetName', title: '资产名称', width: 120, templet: function (d) { return '' + d.assetName + ''; }}, diff --git a/report/src/main/resources/template/js/reportModelType/reportModelTypeList.js b/report/src/main/resources/template/js/reportModelType/reportModelTypeList.js index c2749ed61c6ff0cf563554e7cd4b4c5872a94c8c..63936dcb0a66bc78845e080dac0ce692a7205891 100644 --- a/report/src/main/resources/template/js/reportModelType/reportModelTypeList.js +++ b/report/src/main/resources/template/js/reportModelType/reportModelTypeList.js @@ -67,7 +67,7 @@ layui.config({ pageId: "reportModelTypeEdit", area: ['90vw', '90vh'], callBack: function (refreshCode) { - winui.window.msg("操作成功", {icon: 1, time: 2000}); + winui.window.msg(systemLanguage["com.skyeye.successfulOperation"][languageType], {icon: 1, time: 2000}); loadTable(); }}); } @@ -80,7 +80,7 @@ layui.config({ pageId: "reportModelTypeAdd", area: ['90vw', '90vh'], callBack: function (refreshCode) { - winui.window.msg("操作成功", {icon: 1, time: 2000}); + winui.window.msg(systemLanguage["com.skyeye.successfulOperation"][languageType], {icon: 1, time: 2000}); loadTable(); }}); }); diff --git a/web/src/main/resources/static/editor-app/configuration/properties-assignment-controller.js b/web/src/main/resources/static/editor-app/configuration/properties-assignment-controller.js index f0af91c06a574ec477a20626ca757b1da7d72c48..88874b45457a322d2df02b54bf775e401f1f659f 100644 --- a/web/src/main/resources/static/editor-app/configuration/properties-assignment-controller.js +++ b/web/src/main/resources/static/editor-app/configuration/properties-assignment-controller.js @@ -23,11 +23,11 @@ var propertiesMultipes = '0'; var propertiesIds = '0'; -var KisBpmAssignmentCtrl = [ '$scope', '$modal', function($scope, $modal) { +var KisBpmAssignmentCtrl = ['$scope', '$modal', function ($scope, $modal) { // Config for the modal window var opts = { - template: 'editor-app/configuration/properties/assignment-popup.html?version=' + Date.now(), + template: 'editor-app/configuration/properties/assignment-popup.html?version=' + Date.now(), scope: $scope }; @@ -35,66 +35,63 @@ var KisBpmAssignmentCtrl = [ '$scope', '$modal', function($scope, $modal) { $modal(opts); }]; -var KisBpmAssignmentPopupCtrl = [ '$scope', function($scope) { - +var KisBpmAssignmentPopupCtrl = ['$scope', function ($scope) { + // Put json representing assignment on scope if ($scope.property.value !== undefined && $scope.property.value !== null && $scope.property.value.assignment !== undefined - && $scope.property.value.assignment !== null) - { + && $scope.property.value.assignment !== null) { $scope.assignment = $scope.property.value.assignment; } else { $scope.assignment = {}; } - if ($scope.assignment.candidateUsers == undefined || $scope.assignment.candidateUsers.length == 0) - { - $scope.assignment.candidateUsers = [{value: '', name: ''}]; + if ($scope.assignment.candidateUsers == undefined || $scope.assignment.candidateUsers.length == 0) { + $scope.assignment.candidateUsers = [{value: '', name: ''}]; } - + // Click handler for + button after enum value var userValueIndex = 1; - $scope.addCandidateUserValue = function(index) { + $scope.addCandidateUserValue = function (index) { $scope.assignment.candidateUsers.splice(index + 1, 0, {value: 'value ' + userValueIndex++}); }; // Click handler for - button after enum value - $scope.removeCandidateUserValue = function(index) { + $scope.removeCandidateUserValue = function (index) { $scope.assignment.candidateUsers.splice(index, 1); }; - - if ($scope.assignment.candidateGroups == undefined || $scope.assignment.candidateGroups.length == 0) - { - $scope.assignment.candidateGroups = [{value: '', name: ''}]; + + if ($scope.assignment.candidateGroups == undefined || $scope.assignment.candidateGroups.length == 0) { + $scope.assignment.candidateGroups = [{value: '', name: ''}]; } - + var groupValueIndex = 1; - $scope.addCandidateGroupValue = function(index) { + $scope.addCandidateGroupValue = function (index) { $scope.assignment.candidateGroups.splice(index + 1, 0, {value: 'value ' + groupValueIndex++}); }; // Click handler for - button after enum value - $scope.removeCandidateGroupValue = function(index) { + $scope.removeCandidateGroupValue = function (index) { $scope.assignment.candidateGroups.splice(index, 1); }; - $scope.save = function() { + $scope.save = function () { $scope.property.value = {}; handleAssignmentInput($scope); $scope.property.value.assignment = $scope.assignment; - + $scope.updatePropertyInModel($scope.property); $scope.close(); }; // Close button handler - $scope.close = function() { - handleAssignmentInput($scope); - $scope.property.mode = 'read'; - $scope.$hide(); + $scope.close = function () { + handleAssignmentInput($scope); + $scope.property.mode = 'read'; + $scope.$hide(); }; - + //-----------add select User/Group button handler By billJiang-------------- //代理人(审批人)/候选人 $scope.selectUser = function (multiple) { @@ -104,7 +101,7 @@ var KisBpmAssignmentPopupCtrl = [ '$scope', function($scope) { title = "选择候选人(多选)"; //候选人id ids = 0; - if($scope.assignment.candidateUsers) { + if ($scope.assignment.candidateUsers) { var idsArr = []; //alert( $scope.assignment.candidateUsers.length); for (var i = 0; i < $scope.assignment.candidateUsers.length; i++) { @@ -120,7 +117,7 @@ var KisBpmAssignmentPopupCtrl = [ '$scope', function($scope) { propertiesIds = ids; modals.openWin({ winId: 'userSelectWin', - url: basePath + '/tpl/activitimodel/chooseagentpeople.html', + url: basePath + '/tpl/actFlow/chooseAgentPeople.html', width: '800px', title: title, }) @@ -129,7 +126,7 @@ var KisBpmAssignmentPopupCtrl = [ '$scope', function($scope) { //候选组 $scope.selectGroup = function () { var ids = 0; - if($scope.assignment.candidateGroups) { + if ($scope.assignment.candidateGroups) { var idsArr = []; for (var i = 0; i < $scope.assignment.candidateGroups.length; i++) { if ($scope.assignment.candidateGroups[i].value) @@ -142,7 +139,7 @@ var KisBpmAssignmentPopupCtrl = [ '$scope', function($scope) { propertiesIds = ids; modals.openWin({ winId: 'groupSelectWin', - url: basePath + '/tpl/activitimodel/chooseagentgroup.html?ids=' + ids, + url: basePath + '/tpl/actFlow/chooseAgentGroup.html?ids=' + ids, width: '1200px', title: '选择候选组(多选)' }) @@ -197,60 +194,46 @@ var KisBpmAssignmentPopupCtrl = [ '$scope', function($scope) { //加上这句话回填后界面立即生效 $scope.$apply(); }; - - var handleAssignmentInput = function($scope) { - if ($scope.assignment.candidateUsers) - { - var emptyUsers = true; - var toRemoveIndexes = []; - for (var i = 0; i < $scope.assignment.candidateUsers.length; i++) - { - if ($scope.assignment.candidateUsers[i].value != '') - { - emptyUsers = false; - } - else - { - toRemoveIndexes[toRemoveIndexes.length] = i; - } - } - - for (var i = 0; i < toRemoveIndexes.length; i++) - { - $scope.assignment.candidateUsers.splice(toRemoveIndexes[i], 1); - } - - if (emptyUsers) - { - $scope.assignment.candidateUsers = undefined; - } - } - - if ($scope.assignment.candidateGroups) - { - var emptyGroups = true; - var toRemoveIndexes = []; - for (var i = 0; i < $scope.assignment.candidateGroups.length; i++) - { - if ($scope.assignment.candidateGroups[i].value != '') - { - emptyGroups = false; - } - else - { - toRemoveIndexes[toRemoveIndexes.length] = i; - } - } - - for (var i = 0; i < toRemoveIndexes.length; i++) - { - $scope.assignment.candidateGroups.splice(toRemoveIndexes[i], 1); - } - - if (emptyGroups) - { - $scope.assignment.candidateGroups = undefined; - } - } + + var handleAssignmentInput = function ($scope) { + if ($scope.assignment.candidateUsers) { + var emptyUsers = true; + var toRemoveIndexes = []; + for (var i = 0; i < $scope.assignment.candidateUsers.length; i++) { + if ($scope.assignment.candidateUsers[i].value != '') { + emptyUsers = false; + } else { + toRemoveIndexes[toRemoveIndexes.length] = i; + } + } + + for (var i = 0; i < toRemoveIndexes.length; i++) { + $scope.assignment.candidateUsers.splice(toRemoveIndexes[i], 1); + } + + if (emptyUsers) { + $scope.assignment.candidateUsers = undefined; + } + } + + if ($scope.assignment.candidateGroups) { + var emptyGroups = true; + var toRemoveIndexes = []; + for (var i = 0; i < $scope.assignment.candidateGroups.length; i++) { + if ($scope.assignment.candidateGroups[i].value != '') { + emptyGroups = false; + } else { + toRemoveIndexes[toRemoveIndexes.length] = i; + } + } + + for (var i = 0; i < toRemoveIndexes.length; i++) { + $scope.assignment.candidateGroups.splice(toRemoveIndexes[i], 1); + } + + if (emptyGroups) { + $scope.assignment.candidateGroups = undefined; + } + } }; }]; \ No newline at end of file diff --git a/web/src/main/resources/static/editor-app/editor.html b/web/src/main/resources/static/editor-app/editor.html index f735af46df51f9aece3d3b82267c17ac1eff6539..f300df36213e479fda2230b071385158e57af150 100644 --- a/web/src/main/resources/static/editor-app/editor.html +++ b/web/src/main/resources/static/editor-app/editor.html @@ -119,11 +119,13 @@ {{ property.title }} ({{'PROPERTY.REMOVED' | translate}}) : + src="getPropertyTemplateUrl($index)" ng-if="!property.hasReadWriteMode && !property.readOnly"> + ng-if="property.hasReadWriteMode && property.mode == 'read' && !property.readOnly"> + ng-if="property.hasReadWriteMode && property.mode == 'write' && !property.readOnly"> +
diff --git a/web/src/main/resources/static/editor-app/editor/oryx.debug.js b/web/src/main/resources/static/editor-app/editor/oryx.debug.js index f7b83e9ca61958c0073ce3a2123812912dae6b72..17c7edcf1464ec8e1b205cf811aa017b49c9e1db 100644 --- a/web/src/main/resources/static/editor-app/editor/oryx.debug.js +++ b/web/src/main/resources/static/editor-app/editor/oryx.debug.js @@ -1,47 +1,48 @@ /** * @namespace Oryx name space for different utility methods * @name ORYX.Utils -*/ + */ -if(!ORYX) var ORYX = {}; +if (!ORYX) var ORYX = {}; ORYX.Utils = { /** * General helper method for parsing a param out of current location url * @example * // Current url in Browser => "http://oryx.org?param=value" - * ORYX.Utils.getParamFromUrl("param") // => "value" + * ORYX.Utils.getParamFromUrl("param") // => "value" * @param {Object} name */ - getParamFromUrl: function(name){ + getParamFromUrl: function (name) { name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); var regexS = "[\\?&]" + name + "=([^&#]*)"; var regex = new RegExp(regexS); var results = regex.exec(window.location.href); if (results == null) { return null; - } - else { + } else { return results[1]; } }, - - adjustLightness: function(){ - return arguments[0]; - }, - - adjustGradient: function(gradient, reference){ - - if (ORYX.CONFIG.DISABLE_GRADIENT && gradient){ - - var col = reference.getAttributeNS(null, "stop-color") || "#ffffff"; - - $A(gradient.getElementsByTagName("stop")).each(function(stop){ - if (stop == reference){ return; } - stop.setAttributeNS(null, "stop-color", col); - }); - } - } + + adjustLightness: function () { + return arguments[0]; + }, + + adjustGradient: function (gradient, reference) { + + if (ORYX.CONFIG.DISABLE_GRADIENT && gradient) { + + var col = reference.getAttributeNS(null, "stop-color") || "#ffffff"; + + $A(gradient.getElementsByTagName("stop")).each(function (stop) { + if (stop == reference) { + return; + } + stop.setAttributeNS(null, "stop-color", col); + }); + } + } } /* * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. @@ -54,77 +55,79 @@ ORYX.Utils = { */ XMLNS = { - ATOM: "http://www.w3.org/2005/Atom", - XHTML: "http://www.w3.org/1999/xhtml", - ERDF: "http://purl.org/NET/erdf/profile", - RDFS: "http://www.w3.org/2000/01/rdf-schema#", - RDF: "http://www.w3.org/1999/02/22-rdf-syntax-ns#", - RAZIEL: "http://b3mn.org/Raziel", - - SCHEMA: "" + ATOM: "http://www.w3.org/2005/Atom", + XHTML: "http://www.w3.org/1999/xhtml", + ERDF: "http://purl.org/NET/erdf/profile", + RDFS: "http://www.w3.org/2000/01/rdf-schema#", + RDF: "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + RAZIEL: "http://b3mn.org/Raziel", + + SCHEMA: "" }; //TODO kann kickstart sich vielleicht auch um die erzeugung von paketen/ // namespaces k???mmern? z.b. requireNamespace("ORYX.Core.SVG"); var Kickstart = { - started: false, - callbacks: [], - alreadyLoaded: [], - PATH: '', - - load: function() { Kickstart.kick(); }, - - kick: function() { - //console.profile("loading"); - if(!Kickstart.started) { - Kickstart.started = true; - Kickstart.callbacks.each(function(callback) { - // call the registered callback asynchronously. - window.setTimeout(callback, 1); - }); - } - }, + started: false, + callbacks: [], + alreadyLoaded: [], + PATH: '', - register: function(callback) { - //TODO Add some mutual exclusion between kick and register calls. - with(Kickstart) { - if(started) window.setTimeout(callback, 1); - else Kickstart.callbacks.push(callback) - } - }, + load: function () { + Kickstart.kick(); + }, - /** - * Loads a js, assuring that it has only been downloaded once. - * @param {String} url the script to load. - */ - require: function(url) { - // if not already loaded, include it. - if(Kickstart.alreadyLoaded.member(url)) - return false; - return Kickstart.include(url); - }, + kick: function () { + //console.profile("loading"); + if (!Kickstart.started) { + Kickstart.started = true; + Kickstart.callbacks.each(function (callback) { + // call the registered callback asynchronously. + window.setTimeout(callback, 1); + }); + } + }, - /** - * Loads a js, regardless of whether it has only been already downloaded. - * @param {String} url the script to load. - */ - include: function(url) { + register: function (callback) { + //TODO Add some mutual exclusion between kick and register calls. + with (Kickstart) { + if (started) window.setTimeout(callback, 1); + else Kickstart.callbacks.push(callback) + } + }, - // prepare a script tag and place it in html head. - var head = document.getElementsByTagNameNS(XMLNS.XHTML, 'head')[0]; - var s = document.createElementNS(XMLNS.XHTML, "script"); - s.setAttributeNS(XMLNS.XHTML, 'type', 'text/javascript'); - s.src = Kickstart.PATH + url; + /** + * Loads a js, assuring that it has only been downloaded once. + * @param {String} url the script to load. + */ + require: function (url) { + // if not already loaded, include it. + if (Kickstart.alreadyLoaded.member(url)) + return false; + return Kickstart.include(url); + }, + + /** + * Loads a js, regardless of whether it has only been already downloaded. + * @param {String} url the script to load. + */ + include: function (url) { - //TODO macht es sinn, dass neue skript als letztes kind in den head - // einzubinden (stichwort reihenfolge der skript tags)? - head.appendChild(s); + // prepare a script tag and place it in html head. + var head = document.getElementsByTagNameNS(XMLNS.XHTML, 'head')[0]; + var s = document.createElementNS(XMLNS.XHTML, "script"); + s.setAttributeNS(XMLNS.XHTML, 'type', 'text/javascript'); + s.src = Kickstart.PATH + url; - // remember this url. - Kickstart.alreadyLoaded.push(url); + //TODO macht es sinn, dass neue skript als letztes kind in den head + // einzubinden (stichwort reihenfolge der skript tags)? + head.appendChild(s); - return true; - } + // remember this url. + Kickstart.alreadyLoaded.push(url); + + return true; + } } // register kickstart as the new onload event listener on current window. @@ -141,387 +144,395 @@ Event.observe(window, 'load', Kickstart.load);/* var ERDF = { - LITERAL: 0x01, - RESOURCE: 0x02, - DELIMITERS: ['.', '-'], - HASH: '#', - HYPHEN: "-", - - schemas: [], - callback: undefined, - log: undefined, - - init: function(callback) { - - // init logging. - //ERDF.log = Log4js.getLogger("oryx"); - //ERDF.log.setLevel(Log4js.Level.ALL); - //ERDF.log.addAppender(new ConsoleAppender(ERDF.log, false)); - - //if(ERDF.log.isTraceEnabled()) - // ERDF.log.trace("ERDF Parser is initialized."); - - // register callbacks and default schemas. - ERDF.callback = callback; - ERDF.registerSchema('schema', XMLNS.SCHEMA); - ERDF.registerSchema('rdfs', XMLNS.RDFS); - }, + LITERAL: 0x01, + RESOURCE: 0x02, + DELIMITERS: ['.', '-'], + HASH: '#', + HYPHEN: "-", - run: function() { + schemas: [], + callback: undefined, + log: undefined, - //if(ERDF.log.isTraceEnabled()) - // ERDF.log.trace("ERDF Parser is running."); + init: function (callback) { - // do the work. - return ERDF._checkProfile() && ERDF.parse(); - }, - - parse: function() { - - //(ERDF.log.isDebugEnabled()) - // ERDF.log.debug("Begin parsing document metadata."); - - // time measuring - ERDF.__startTime = new Date(); - - var bodies = document.getElementsByTagNameNS(XMLNS.XHTML, 'body'); - var subject = {type: ERDF.RESOURCE, value: ''}; - - var result = ERDF._parseDocumentMetadata() && - ERDF._parseFromTag(bodies[0], subject); - - // time measuring - ERDF.__stopTime = new Date(); - - var duration = (ERDF.__stopTime - ERDF.__startTime)/1000.; - //alert('ERDF parsing took ' + duration + ' s.'); - - return result; - }, - - _parseDocumentMetadata: function() { - - // get links from head element. - var heads = document.getElementsByTagNameNS(XMLNS.XHTML, 'head'); - var links = heads[0].getElementsByTagNameNS(XMLNS.XHTML, 'link'); - var metas = heads[0].getElementsByTagNameNS(XMLNS.XHTML, 'meta'); - - // process links first, since they could contain schema definitions. - $A(links).each(function(link) { - var properties = link.getAttribute('rel'); - var reversedProperties = link.getAttribute('rev'); - var value = link.getAttribute('href'); - - ERDF._parseTriplesFrom( - ERDF.RESOURCE, '', - properties, - ERDF.RESOURCE, value); - - ERDF._parseTriplesFrom( - ERDF.RESOURCE, value, - reversedProperties, - ERDF.RESOURCE, ''); - }); + // init logging. + //ERDF.log = Log4js.getLogger("oryx"); + //ERDF.log.setLevel(Log4js.Level.ALL); + //ERDF.log.addAppender(new ConsoleAppender(ERDF.log, false)); - // continue with metas. - $A(metas).each(function(meta) { - var property = meta.getAttribute('name'); - var value = meta.getAttribute('content'); - - ERDF._parseTriplesFrom( - ERDF.RESOURCE, '', - property, - ERDF.LITERAL, value); - }); + //if(ERDF.log.isTraceEnabled()) + // ERDF.log.trace("ERDF Parser is initialized."); - return true; - }, - - _parseFromTag: function(node, subject, depth) { - - // avoid parsing non-xhtml content. - if(!node || !node.namespaceURI || node.namespaceURI != XMLNS.XHTML) { return; } - - // housekeeping. - if(!depth) depth=0; - var id = node.getAttribute('id'); - - // some logging. - //if(ERDF.log.isTraceEnabled()) - // ERDF.log.trace(">".times(depth) + " Parsing " + node.nodeName + " ("+node.nodeType+") for data on " + - // ((subject.type == ERDF.RESOURCE) ? ('<' + subject.value + '>') : '') + - // ((subject.type == ERDF.LITERAL) ? '"' + subject.value + '"' : '')); - - /* triple finding! */ - - // in a-tags... - if(node.nodeName.endsWith(':a') || node.nodeName == 'a') { - var properties = node.getAttribute('rel'); - var reversedProperties = node.getAttribute('rev'); - var value = node.getAttribute('href'); - var title = node.getAttribute('title'); - var content = node.textContent; - - // rel triples - ERDF._parseTriplesFrom( - subject.type, subject.value, - properties, - ERDF.RESOURCE, value, - function(triple) { - var label = title? title : content; - - // label triples - ERDF._parseTriplesFrom( - triple.object.type, triple.object.value, - 'rdfs.label', - ERDF.LITERAL, label); - }); + // register callbacks and default schemas. + ERDF.callback = callback; + ERDF.registerSchema('schema', XMLNS.SCHEMA); + ERDF.registerSchema('rdfs', XMLNS.RDFS); + }, - // rev triples - ERDF._parseTriplesFrom( - subject.type, subject.value, - reversedProperties, - ERDF.RESOURCE, ''); - - // type triples - ERDF._parseTypeTriplesFrom( - subject.type, subject.value, - properties); - - // in img-tags... - } else if(node.nodeName.endsWith(':img') || node.nodeName == 'img') { - var properties = node.getAttribute('class'); - var value = node.getAttribute('src'); - var alt = node.getAttribute('alt'); - - ERDF._parseTriplesFrom( - subject.type, subject.value, - properties, - ERDF.RESOURCE, value, - function(triple) { - var label = alt; - - // label triples - ERDF._parseTriplesFrom( - triple.object.type, triple.object.value, - 'rdfs.label', - ERDF.LITERAL, label); - }); + run: function () { - } - - // in every tag - var properties = node.getAttribute('class'); - var title = node.getAttribute('title'); - var content = node.textContent; - var label = title ? title : content; - - // regular triples - ERDF._parseTriplesFrom( - subject.type, subject.value, - properties, - ERDF.LITERAL, label); - - if(id) subject = {type: ERDF.RESOURCE, value: ERDF.HASH+id}; - - // type triples - ERDF._parseTypeTriplesFrom( - subject.type, subject.value, - properties); - - // parse all children that are element nodes. - var children = node.childNodes; - if(children) $A(children).each(function(_node) { - if(_node.nodeType == _node.ELEMENT_NODE) - ERDF._parseFromTag(_node, subject, depth+1); }); - }, - - _parseTriplesFrom: function(subjectType, subject, properties, - objectType, object, callback) { - - if(!properties) return; - properties.toLowerCase().split(' ').each( function(property) { - - //if(ERDF.log.isTraceEnabled()) - // ERDF.log.trace("Going for property " + property); - - var schema = ERDF.schemas.find( function(schema) { - return false || ERDF.DELIMITERS.find( function(delimiter) { - return property.startsWith(schema.prefix + delimiter); - }); - }); - - if(schema && object) { - property = property.substring( - schema.prefix.length+1, property.length); - var triple = ERDF.registerTriple( - new ERDF.Resource(subject), - {prefix: schema.prefix, name: property}, - (objectType == ERDF.RESOURCE) ? - new ERDF.Resource(object) : - new ERDF.Literal(object)); - - if(callback) callback(triple); - } - }); - }, - - _parseTypeTriplesFrom: function(subjectType, subject, properties, callback) { - - if(!properties) return; - properties.toLowerCase().split(' ').each( function(property) { - - //if(ERDF.log.isTraceEnabled()) - // ERDF.log.trace("Going for property " + property); - - var schema = ERDF.schemas.find( function(schema) { - return false || ERDF.DELIMITERS.find( function(delimiter) { - return property.startsWith(ERDF.HYPHEN + schema.prefix + delimiter); - }); - }); - - if(schema && subject) { - property = property.substring(schema.prefix.length+2, property.length); - var triple = ERDF.registerTriple( - (subjectType == ERDF.RESOURCE) ? - new ERDF.Resource(subject) : - new ERDF.Literal(subject), - {prefix: 'rdf', name: 'type'}, - new ERDF.Resource(schema.namespace+property)); - if(callback) callback(triple); - } - }); - }, - - /** - * Checks for ERDF profile declaration in head of document. - */ - _checkProfile: function() { + //if(ERDF.log.isTraceEnabled()) + // ERDF.log.trace("ERDF Parser is running."); - // get profiles from head element. - var heads = document.getElementsByTagNameNS(XMLNS.XHTML, 'head'); - var profiles = heads[0].getAttribute("profile"); - var found = false; + // do the work. + return ERDF._checkProfile() && ERDF.parse(); + }, - // if erdf profile is contained. - if(profiles && profiles.split(" ").member(XMLNS.ERDF)) { + parse: function () { - // pass check. - //if(ERDF.log.isTraceEnabled()) - // ERDF.log.trace("Found ERDF profile " + XMLNS.ERDF); - return true; - - } else { - - // otherwise fail check. - //if(ERDF.log.isFatalEnabled()) - // ERDF.log.fatal("No ERDF profile found."); - return false; - } - }, - - __stripHashes: function(s) { - return (s && (typeof s.substring == 'function') && s.substring(0, 1)=='#') ? s.substring(1, s.length) : s; - }, - - registerSchema: function(prefix, namespace) { - - // TODO check whether already registered, if so, complain. - ERDF.schemas.push({ - prefix: prefix, - namespace: namespace - }); - - //if(ERDF.log.isDebugEnabled()) - // ERDF.log.debug("Prefix '"+prefix+"' for '"+namespace+"' registered."); - }, - - registerTriple: function(subject, predicate, object) { - - // if prefix is schema, this is a schema definition. - if(predicate.prefix.toLowerCase() == 'schema') - this.registerSchema(predicate.name, object.value); - - var triple = new ERDF.Triple(subject, predicate, object); - ERDF.callback(triple); - - //if(ERDF.log.isInfoEnabled()) - // ERDF.log.info(triple) - - // return the registered triple. - return triple; - }, - - __enhanceObject: function() { - - /* Resource state querying methods */ - this.isResource = function() { - return this.type == ERDF.RESOURCE }; - this.isLocal = function() { - return this.isResource() && this.value.startsWith('#') }; - this.isCurrentDocument = function() { - return this.isResource() && (this.value == '') }; - - /* Resource getter methods.*/ - this.getId = function() { - return this.isLocal() ? ERDF.__stripHashes(this.value) : false; }; - - /* Liiteral state querying methods */ - this.isLiteral = function() { - return this.type == ERDF.LIITERAL }; - }, - - serialize: function(literal) { - - if(!literal){ - return ""; - } else if (literal.constructor == String) { - return literal; - } else if(literal.constructor == Boolean) { - return literal? 'true':'false'; - } else { - return literal.toString(); - } - } + //(ERDF.log.isDebugEnabled()) + // ERDF.log.debug("Begin parsing document metadata."); + + // time measuring + ERDF.__startTime = new Date(); + + var bodies = document.getElementsByTagNameNS(XMLNS.XHTML, 'body'); + var subject = {type: ERDF.RESOURCE, value: ''}; + + var result = ERDF._parseDocumentMetadata() && + ERDF._parseFromTag(bodies[0], subject); + + // time measuring + ERDF.__stopTime = new Date(); + + var duration = (ERDF.__stopTime - ERDF.__startTime) / 1000.; + //alert('ERDF parsing took ' + duration + ' s.'); + + return result; + }, + + _parseDocumentMetadata: function () { + + // get links from head element. + var heads = document.getElementsByTagNameNS(XMLNS.XHTML, 'head'); + var links = heads[0].getElementsByTagNameNS(XMLNS.XHTML, 'link'); + var metas = heads[0].getElementsByTagNameNS(XMLNS.XHTML, 'meta'); + + // process links first, since they could contain schema definitions. + $A(links).each(function (link) { + var properties = link.getAttribute('rel'); + var reversedProperties = link.getAttribute('rev'); + var value = link.getAttribute('href'); + + ERDF._parseTriplesFrom( + ERDF.RESOURCE, '', + properties, + ERDF.RESOURCE, value); + + ERDF._parseTriplesFrom( + ERDF.RESOURCE, value, + reversedProperties, + ERDF.RESOURCE, ''); + }); + + // continue with metas. + $A(metas).each(function (meta) { + var property = meta.getAttribute('name'); + var value = meta.getAttribute('content'); + + ERDF._parseTriplesFrom( + ERDF.RESOURCE, '', + property, + ERDF.LITERAL, value); + }); + + return true; + }, + + _parseFromTag: function (node, subject, depth) { + + // avoid parsing non-xhtml content. + if (!node || !node.namespaceURI || node.namespaceURI != XMLNS.XHTML) { + return; + } + + // housekeeping. + if (!depth) depth = 0; + var id = node.getAttribute('id'); + + // some logging. + //if(ERDF.log.isTraceEnabled()) + // ERDF.log.trace(">".times(depth) + " Parsing " + node.nodeName + " ("+node.nodeType+") for data on " + + // ((subject.type == ERDF.RESOURCE) ? ('<' + subject.value + '>') : '') + + // ((subject.type == ERDF.LITERAL) ? '"' + subject.value + '"' : '')); + + /* triple finding! */ + + // in a-tags... + if (node.nodeName.endsWith(':a') || node.nodeName == 'a') { + var properties = node.getAttribute('rel'); + var reversedProperties = node.getAttribute('rev'); + var value = node.getAttribute('href'); + var title = node.getAttribute('title'); + var content = node.textContent; + + // rel triples + ERDF._parseTriplesFrom( + subject.type, subject.value, + properties, + ERDF.RESOURCE, value, + function (triple) { + var label = title ? title : content; + + // label triples + ERDF._parseTriplesFrom( + triple.object.type, triple.object.value, + 'rdfs.label', + ERDF.LITERAL, label); + }); + + // rev triples + ERDF._parseTriplesFrom( + subject.type, subject.value, + reversedProperties, + ERDF.RESOURCE, ''); + + // type triples + ERDF._parseTypeTriplesFrom( + subject.type, subject.value, + properties); + + // in img-tags... + } else if (node.nodeName.endsWith(':img') || node.nodeName == 'img') { + var properties = node.getAttribute('class'); + var value = node.getAttribute('src'); + var alt = node.getAttribute('alt'); + + ERDF._parseTriplesFrom( + subject.type, subject.value, + properties, + ERDF.RESOURCE, value, + function (triple) { + var label = alt; + + // label triples + ERDF._parseTriplesFrom( + triple.object.type, triple.object.value, + 'rdfs.label', + ERDF.LITERAL, label); + }); + + } + + // in every tag + var properties = node.getAttribute('class'); + var title = node.getAttribute('title'); + var content = node.textContent; + var label = title ? title : content; + + // regular triples + ERDF._parseTriplesFrom( + subject.type, subject.value, + properties, + ERDF.LITERAL, label); + + if (id) subject = {type: ERDF.RESOURCE, value: ERDF.HASH + id}; + + // type triples + ERDF._parseTypeTriplesFrom( + subject.type, subject.value, + properties); + + // parse all children that are element nodes. + var children = node.childNodes; + if (children) $A(children).each(function (_node) { + if (_node.nodeType == _node.ELEMENT_NODE) + ERDF._parseFromTag(_node, subject, depth + 1); + }); + }, + + _parseTriplesFrom: function (subjectType, subject, properties, + objectType, object, callback) { + + if (!properties) return; + properties.toLowerCase().split(' ').each(function (property) { + + //if(ERDF.log.isTraceEnabled()) + // ERDF.log.trace("Going for property " + property); + + var schema = ERDF.schemas.find(function (schema) { + return false || ERDF.DELIMITERS.find(function (delimiter) { + return property.startsWith(schema.prefix + delimiter); + }); + }); + + if (schema && object) { + property = property.substring( + schema.prefix.length + 1, property.length); + var triple = ERDF.registerTriple( + new ERDF.Resource(subject), + {prefix: schema.prefix, name: property}, + (objectType == ERDF.RESOURCE) ? + new ERDF.Resource(object) : + new ERDF.Literal(object)); + + if (callback) callback(triple); + } + }); + }, + + _parseTypeTriplesFrom: function (subjectType, subject, properties, callback) { + + if (!properties) return; + properties.toLowerCase().split(' ').each(function (property) { + + //if(ERDF.log.isTraceEnabled()) + // ERDF.log.trace("Going for property " + property); + + var schema = ERDF.schemas.find(function (schema) { + return false || ERDF.DELIMITERS.find(function (delimiter) { + return property.startsWith(ERDF.HYPHEN + schema.prefix + delimiter); + }); + }); + + if (schema && subject) { + property = property.substring(schema.prefix.length + 2, property.length); + var triple = ERDF.registerTriple( + (subjectType == ERDF.RESOURCE) ? + new ERDF.Resource(subject) : + new ERDF.Literal(subject), + {prefix: 'rdf', name: 'type'}, + new ERDF.Resource(schema.namespace + property)); + if (callback) callback(triple); + } + }); + }, + + /** + * Checks for ERDF profile declaration in head of document. + */ + _checkProfile: function () { + + // get profiles from head element. + var heads = document.getElementsByTagNameNS(XMLNS.XHTML, 'head'); + var profiles = heads[0].getAttribute("profile"); + var found = false; + + // if erdf profile is contained. + if (profiles && profiles.split(" ").member(XMLNS.ERDF)) { + + // pass check. + //if(ERDF.log.isTraceEnabled()) + // ERDF.log.trace("Found ERDF profile " + XMLNS.ERDF); + return true; + + } else { + + // otherwise fail check. + //if(ERDF.log.isFatalEnabled()) + // ERDF.log.fatal("No ERDF profile found."); + return false; + } + }, + + __stripHashes: function (s) { + return (s && (typeof s.substring == 'function') && s.substring(0, 1) == '#') ? s.substring(1, s.length) : s; + }, + + registerSchema: function (prefix, namespace) { + + // TODO check whether already registered, if so, complain. + ERDF.schemas.push({ + prefix: prefix, + namespace: namespace + }); + + //if(ERDF.log.isDebugEnabled()) + // ERDF.log.debug("Prefix '"+prefix+"' for '"+namespace+"' registered."); + }, + + registerTriple: function (subject, predicate, object) { + + // if prefix is schema, this is a schema definition. + if (predicate.prefix.toLowerCase() == 'schema') + this.registerSchema(predicate.name, object.value); + + var triple = new ERDF.Triple(subject, predicate, object); + ERDF.callback(triple); + + //if(ERDF.log.isInfoEnabled()) + // ERDF.log.info(triple) + + // return the registered triple. + return triple; + }, + + __enhanceObject: function () { + + /* Resource state querying methods */ + this.isResource = function () { + return this.type == ERDF.RESOURCE + }; + this.isLocal = function () { + return this.isResource() && this.value.startsWith('#') + }; + this.isCurrentDocument = function () { + return this.isResource() && (this.value == '') + }; + + /* Resource getter methods.*/ + this.getId = function () { + return this.isLocal() ? ERDF.__stripHashes(this.value) : false; + }; + + /* Liiteral state querying methods */ + this.isLiteral = function () { + return this.type == ERDF.LIITERAL + }; + }, + + serialize: function (literal) { + + if (!literal) { + return ""; + } else if (literal.constructor == String) { + return literal; + } else if (literal.constructor == Boolean) { + return literal ? 'true' : 'false'; + } else { + return literal.toString(); + } + } }; -ERDF.Triple = function(subject, predicate, object) { - - this.subject = subject; - this.predicate = predicate; - this.object = object; - - this.toString = function() { - - return "[ERDF.Triple] " + - this.subject.toString() + ' ' + - this.predicate.prefix + ':' + this.predicate.name + ' ' + - this.object.toString(); - }; +ERDF.Triple = function (subject, predicate, object) { + + this.subject = subject; + this.predicate = predicate; + this.object = object; + + this.toString = function () { + + return "[ERDF.Triple] " + + this.subject.toString() + ' ' + + this.predicate.prefix + ':' + this.predicate.name + ' ' + + this.object.toString(); + }; }; -ERDF.Resource = function(uri) { - - this.type = ERDF.RESOURCE; - this.value = uri; - ERDF.__enhanceObject.apply(this); - - this.toString = function() { - return '<' + this.value + '>'; - } - +ERDF.Resource = function (uri) { + + this.type = ERDF.RESOURCE; + this.value = uri; + ERDF.__enhanceObject.apply(this); + + this.toString = function () { + return '<' + this.value + '>'; + } + }; -ERDF.Literal = function(literal) { - - this.type = ERDF.LITERAL; - this.value = ERDF.serialize(literal); - ERDF.__enhanceObject.apply(this); +ERDF.Literal = function (literal) { + + this.type = ERDF.LITERAL; + this.value = ERDF.serialize(literal); + ERDF.__enhanceObject.apply(this); - this.toString = function() { - return '"' + this.value + '"'; - } + this.toString = function () { + return '"' + this.value + '"'; + } };/* * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. * License rights for this program may be obtained from Alfresco Software, Ltd. @@ -536,20 +547,20 @@ ERDF.Literal = function(literal) { * Save and triple generation behaviour. Use this area to configure * data management to your needs. */ -var USE_ASYNCHRONOUS_REQUESTS = true; -var DISCARD_UNUSED_TRIPLES = true; -var PREFER_SPANS_OVER_DIVS = true; -var PREFER_TITLE_OVER_TEXTNODE = false; -var RESOURCE_ID_PREFIX = 'resource'; +var USE_ASYNCHRONOUS_REQUESTS = true; +var DISCARD_UNUSED_TRIPLES = true; +var PREFER_SPANS_OVER_DIVS = true; +var PREFER_TITLE_OVER_TEXTNODE = false; +var RESOURCE_ID_PREFIX = 'resource'; -var SHOW_DEBUG_ALERTS_WHEN_SAVING = false; -var SHOW_EXTENDED_DEBUG_INFORMATION = false; +var SHOW_DEBUG_ALERTS_WHEN_SAVING = false; +var SHOW_EXTENDED_DEBUG_INFORMATION = false; /* * Back end specific workarounds. */ -var USE_ARESS_WORKAROUNDS = true; +var USE_ARESS_WORKAROUNDS = true; /* * Data management constants. Do not change these, as they are used @@ -558,17 +569,17 @@ var USE_ARESS_WORKAROUNDS = true; */ // Resource constants -var RESOURCE_CREATED = 0x01; -var RESOURCE_REMOVED = 0x02; -var RESOURCE_SAVED = 0x04; -var RESOURCE_RELOADED = 0x08; -var RESOURCE_SYNCHRONIZED = 0x10; +var RESOURCE_CREATED = 0x01; +var RESOURCE_REMOVED = 0x02; +var RESOURCE_SAVED = 0x04; +var RESOURCE_RELOADED = 0x08; +var RESOURCE_SYNCHRONIZED = 0x10; // Triple constants -var TRIPLE_REMOVE = 0x01; -var TRIPLE_ADD = 0x02; -var TRIPLE_RELOAD = 0x04; -var TRIPLE_SAVE = 0x08; +var TRIPLE_REMOVE = 0x01; +var TRIPLE_ADD = 0x02; +var TRIPLE_RELOAD = 0x04; +var TRIPLE_SAVE = 0x08; var PROCESSDATA_REF = 'processdata'; @@ -604,2939 +615,1145 @@ var PROCESSDATA_REF = 'processdata'; * @class DataManager */ var DataManager = { - - /** - * The init method should be called once in the DataManagers lifetime. - * It causes the DataManager to initialize itself, the erdf parser, do all - * neccessary registrations and configurations, to run the parser and - * from then on deliver all resulting triples. - * No parameters needed are needed in a call to this method. - */ - init: function() { - ERDF.init(DataManager._registerTriple); - DataManager.__synclocal(); - }, - - /** - * This triple array is meant to be the whole knowledge of the DataManager. - */ - _triples: [], - - /** - * This method is meant for callback from erdf parsing. It is not to be - * used in another way than to add triples to the triple store. - * @param {Object} triple the triple to add to the triple store. - */ - _registerTriple: function(triple) { - DataManager._triples.push(triple) - }, - - /** - * The __synclocal method is for internal usage only. - * It performs synchronization with the local document, that is, the triple - * store is adjustet to the content of the document, which could have been - * changed by any other applications running on the same page. - */ - __synclocal: function() { - DataManager._triples = []; - ERDF.run(); - }, - - /** - * Makes the shape passed into this method synchronize itself with the DOM. - * This method returns the shapes resource object for further manipulation. - * @param {Object} shape - */ - __synchronizeShape: function(shape) { - - var r = ResourceManager.getResource(shape.resourceId); - var serialize = shape.serialize(); - - // store all serialize values - serialize.each( function(ser) { - - var resource = (ser.type == 'resource'); - var _triple = new ERDF.Triple( - new ERDF.Resource(shape.resourceId), - {prefix: ser.prefix, name: ser.name}, - resource ? - new ERDF.Resource(ser.value) : - new ERDF.Literal(ser.value) - ); - DataManager.setObject(_triple); - }); - - return r; - }, - __storeShape: function(shape) { - - // first synchronize the shape, - var resource = DataManager.__synchronizeShape(shape); - - // then save the synchronized dom. - resource.save(); - }, - - __forceExistance: function(shape) { - - if(!$(shape.resourceId)) { - - if(!$$('.' + PROCESSDATA_REF)[0]) - DataManager.graft(XMLNS.XHTML, - document.getElementsByTagNameNS(XMLNS.XHTML, 'body').item(0), ['div', {'class': PROCESSDATA_REF, 'style':'display:none;'}]); - - // object is literal - DataManager.graft(XMLNS.XHTML, - $$('.' + PROCESSDATA_REF)[0], [ - - 'div', { - 'id': shape.resourceId, - //This should be done in a more dynamic way!!!!! - 'class': (shape instanceof ORYX.Core.Canvas) ? "-oryx-canvas" : undefined - } - ]); - - } else { - var resource = $(shape.resourceId) - var children = $A(resource.childNodes) - children.each( function(child) { - resource.removeChild(child); - }); - }; - }, - - __persistShape: function(shape) { - - // a shape serialization. - var shapeData = shape.serialize(); - - // initialize a triple array and construct a shape resource - // to be used in triple generation. - var triplesArray = []; - var shapeResource = new ERDF.Resource(shape.resourceId); - - // remove all triples for this particular shape's resource - DataManager.removeTriples( DataManager.query( - shapeResource, undefined, undefined)); - - // for each data set in the shape's serialization - shapeData.each( function(data) { - - // construct a triple's value - var value = (data.type == 'resource') ? - new ERDF.Resource(data.value) : - new ERDF.Literal(data.value); - - // construct triple and add it to the DOM. - DataManager.addTriple( new ERDF.Triple( - shapeResource, - {prefix: data.prefix, name: data.name}, - value - )); - }); - }, - - __persistDOM: function(facade) { - - // getChildShapes gets all shapes (nodes AND edges), deep flag - // makes it return a flattened child hierarchy. - - var canvas = facade.getCanvas(); - var shapes = canvas.getChildShapes(true); - var result = ''; - - // persist all shapes. - shapes.each( function(shape) { - DataManager.__forceExistance(shape); - }); - //DataManager.__synclocal(); - - DataManager.__renderCanvas(facade); - result += DataManager.serialize( - $(ERDF.__stripHashes(facade.getCanvas().resourceId)), true); - - shapes.each( function(shape) { - - DataManager.__persistShape(shape); - result += DataManager.serialize( - $(ERDF.__stripHashes(shape.resourceId)), true); - }); - - //result += DataManager.__renderCanvas(facade); - - return result; - }, + /** + * The init method should be called once in the DataManagers lifetime. + * It causes the DataManager to initialize itself, the erdf parser, do all + * neccessary registrations and configurations, to run the parser and + * from then on deliver all resulting triples. + * No parameters needed are needed in a call to this method. + */ + init: function () { + ERDF.init(DataManager._registerTriple); + DataManager.__synclocal(); + }, - __renderCanvas: function(facade) { - - var canvas = facade.getCanvas(); - var stencilSets = facade.getStencilSets(); - var shapes = canvas.getChildShapes(true); - - DataManager.__forceExistance(canvas); - - DataManager.__persistShape(canvas); - - var shapeResource = new ERDF.Resource(canvas.resourceId); - - // remove all triples for this particular shape's resource - DataManager.removeTriples( DataManager.query( - shapeResource, undefined, undefined)); - - DataManager.addTriple( new ERDF.Triple( - shapeResource, - {prefix: "oryx", name: "mode"}, - new ERDF.Literal("writable") - )); - - DataManager.addTriple( new ERDF.Triple( - shapeResource, - {prefix: "oryx", name: "mode"}, - new ERDF.Literal("fullscreen") - )); - - stencilSets.values().each(function(stencilset) { - DataManager.addTriple( new ERDF.Triple( - shapeResource, - {prefix: "oryx", name: "stencilset"}, - new ERDF.Resource(stencilset.source().replace(/&/g, "%26")) - )); - - DataManager.addTriple( new ERDF.Triple( - shapeResource, - {prefix: "oryx", name: "ssnamespace"}, - new ERDF.Resource(stencilset.namespace()) - )); - - stencilset.extensions().keys().each(function(extension) { - DataManager.addTriple( new ERDF.Triple( - shapeResource, - {prefix: "oryx", name: "ssextension"}, - new ERDF.Literal(extension) - )); - }); - }); - - shapes.each(function(shape) { - DataManager.addTriple( new ERDF.Triple( - shapeResource, - {prefix: "oryx", name: "render"}, - new ERDF.Resource("#" + shape.resourceId) - )); - }); - }, + /** + * This triple array is meant to be the whole knowledge of the DataManager. + */ + _triples: [], - __counter: 0, - __provideId: function() { - - while($(RESOURCE_ID_PREFIX+DataManager.__counter)) - DataManager.__counter++; - - return RESOURCE_ID_PREFIX+DataManager.__counter; - }, - - serializeDOM: function(facade) { - - return DataManager.__persistDOM(facade); - }, - - syncGlobal: function(facade) { - - return DataManager.__syncglobal(facade); - }, - - /** - * This method is used to synchronize local DOM with remote resources. - * Local changes are commited to the server, and remote changes are - * performed to the local document. - * @param {Object} facade The facade of the editor that holds certain - * resource representations as shapes. - */ - __syncglobal: function(facade) { + /** + * This method is meant for callback from erdf parsing. It is not to be + * used in another way than to add triples to the triple store. + * @param {Object} triple the triple to add to the triple store. + */ + _registerTriple: function (triple) { + DataManager._triples.push(triple) + }, - // getChildShapes gets all shapes (nodes AND edges), deep flag - // makes it return a flattened child hierarchy. - - var canvas = facade.getCanvas(); - var shapes = canvas.getChildShapes(true); + /** + * The __synclocal method is for internal usage only. + * It performs synchronization with the local document, that is, the triple + * store is adjustet to the content of the document, which could have been + * changed by any other applications running on the same page. + */ + __synclocal: function () { + DataManager._triples = []; + ERDF.run(); + }, - // create dummy resource representations in the dom - // for all shapes that were newly created. + /** + * Makes the shape passed into this method synchronize itself with the DOM. + * This method returns the shapes resource object for further manipulation. + * @param {Object} shape + */ + __synchronizeShape: function (shape) { + + var r = ResourceManager.getResource(shape.resourceId); + var serialize = shape.serialize(); + + // store all serialize values + serialize.each(function (ser) { + + var resource = (ser.type == 'resource'); + var _triple = new ERDF.Triple( + new ERDF.Resource(shape.resourceId), + {prefix: ser.prefix, name: ser.name}, + resource ? + new ERDF.Resource(ser.value) : + new ERDF.Literal(ser.value) + ); + DataManager.setObject(_triple); + }); - shapes.select( function(shape) { + return r; + }, - // select shapes without resource id. + __storeShape: function (shape) { - return !($(shape.resourceId)); + // first synchronize the shape, + var resource = DataManager.__synchronizeShape(shape); - }).each( function(shape) { + // then save the synchronized dom. + resource.save(); + }, - // create new resources for them. - if(USE_ARESS_WORKAROUNDS) { - - /* - * This is a workaround due to a bug in aress. Resources are - * ignoring changes to raziel:type property once they are - * created. As long as this is not fixed, the resource is now - * being created using a randomly guessed id, this temporary id - * is then used in references and the appropriate div is being - * populated with properties. - * - * AFTER THIS PHASE THE DATA IS INCONSISTENT AS REFERENCES POINT - * TO IDS THAT ARE UNKNOWN TO THE BACK END. - * - * After the resource is actually created in aress, it gets an id - * that is persistent. All shapes are then being populated with the - * correct id references and stored on the server. - * - * AFTER THE SAVE PROCESS HAS RETURNED, THE DATA IS CONSISTENT - * REGARDING THE ID REFERENCES AGAIN. - */ - - var razielType = shape.properties['raziel-type']; - - var div = '
' + - ''+razielType+'
'; - - var r = ResourceManager.__createResource(div); - shape.resourceId = r.id(); - - } else { - - var r = ResourceManager.__createResource(); - shape.resourceId = r.id(); - } + __forceExistance: function (shape) { - }); + if (!$(shape.resourceId)) { - shapes.each( function(shape) { - - // store all shapes. - DataManager.__storeShape(shape); - }); - }, - - /** - * This method serializes a single div into a string that satisfies the - * client/server communication protocol. It ingnores all elements that have - * an attribute named class that includes 'transient'. - * @param {Object} node the element to serialize. - * @param {Object} preserveNamespace whether to preserve the parent's - * namespace. If you are not sure about namespaces, provide - * just the element to be serialized. - */ - serialize: function(node, preserveNamespace) { - - if (node.nodeType == node.ELEMENT_NODE) { - // serialize an element node. - - var children = $A(node.childNodes); - var attributes = $A(node.attributes); - var clazz = new String(node.getAttribute('class')); - var ignore = clazz.split(' ').member('transient'); - - // ignore transients. - - if(ignore) - return ''; - - // start serialization. - - var result = '<' + node.nodeName; - - // preserve namespace? - if(!preserveNamespace) - result += ' xmlns="' + (node.namespaceURI ? node.namespaceURI : XMLNS.XHTML) + '" xmlns:oryx="http://oryx-editor.org"'; - - // add all attributes. - - attributes.each(function(attribute) { - result += ' ' + attribute.nodeName + '="' + - attribute.nodeValue + '"';}); - - // close if no children. - - if(children.length == 0) - result += '/>'; - - else { - - // serialize all children. - - result += '>'; - children.each(function(_node) { - result += DataManager.serialize(_node, true)}); - result += '' - } + if (!$$('.' + PROCESSDATA_REF)[0]) + DataManager.graft(XMLNS.XHTML, + document.getElementsByTagNameNS(XMLNS.XHTML, 'body').item(0), ['div', { + 'class': PROCESSDATA_REF, + 'style': 'display:none;' + }]); - return result; - - } else if (node.nodeType == node.TEXT_NODE) { - - // serialize a text node. - return node.nodeValue; - } - - //TODO serialize cdata areas also. - //TODO work on namespace awareness. - }, + // object is literal + DataManager.graft(XMLNS.XHTML, + $$('.' + PROCESSDATA_REF)[0], [ - addTriple: function(triple) { - - // assert the subject is a resource - - if(!triple.subject.type == ERDF.LITERAL) - throw 'Cannot add the triple ' + triple.toString() + - ' because the subject is not a resource.' - - // get the element which represents this triple's subject. - var elementId = ERDF.__stripHashes(triple.subject.value); - var element = $(elementId); - - // assert the subject is inside this document. - if(!element) - throw 'Cannot add the triple ' + triple.toString() + - ' because the subject "'+elementId+'" is not in the document.'; - - if(triple.object.type == ERDF.LITERAL) - - // object is literal - DataManager.graft(XMLNS.XHTML, element, [ - 'span', {'class': (triple.predicate.prefix + "-" + - triple.predicate.name)}, triple.object.value.escapeHTML() - ]); - - else { - - // object is resource - DataManager.graft(XMLNS.XHTML, element, [ - 'a', {'rel': (triple.predicate.prefix + "-" + - triple.predicate.name), 'href': triple.object.value} - ]); - - } + 'div', { + 'id': shape.resourceId, + //This should be done in a more dynamic way!!!!! + 'class': (shape instanceof ORYX.Core.Canvas) ? "-oryx-canvas" : undefined + } + ]); - return true; - }, - - removeTriples: function(triples) { + } else { + var resource = $(shape.resourceId) + var children = $A(resource.childNodes) + children.each(function (child) { + resource.removeChild(child); + }); + } + ; + }, - // alert('Removing ' +triples.length+' triples.'); + __persistShape: function (shape) { - // from all the triples select those ... - var removed = triples.select( + // a shape serialization. + var shapeData = shape.serialize(); - function(triple) { - - // TODO remove also from triple store. - // ... that were actually removed. - return DataManager.__removeTriple(triple); - }); - - // sync and return removed triples. - // DataManager.__synclocal(); - return removed; - }, - - removeTriple: function(triple) { - - // remember whether the triple was actually removed. - var result = DataManager.__removeTriple(triple); - - // sync and return removed triples. - // DataManager.__synclocal(); - return result; - }, + // initialize a triple array and construct a shape resource + // to be used in triple generation. + var triplesArray = []; + var shapeResource = new ERDF.Resource(shape.resourceId); - __removeTriple: function(triple) { - - // assert the subject is a resource - if(!triple.subject.type == ERDF.LITERAL) - - throw 'Cannot remove the triple ' + triple.toString() + - ' because the subject is not a resource.'; - - // get the element which represents this triple's subject. - var elementId = ERDF.__stripHashes(triple.subject.value); - var element = $(elementId); - - // assert the subject is inside this document. - if(!element) - - throw 'Cannot remove the triple ' + triple.toString() + - ' because the subject is not in the document.'; - - if(triple.object.type == ERDF.LITERAL) { - - // continue searching actively for the triple. - var result = DataManager.__removeTripleRecursively(triple, element); - return result; - } - }, + // remove all triples for this particular shape's resource + DataManager.removeTriples(DataManager.query( + shapeResource, undefined, undefined)); - __removeTripleRecursively: function(triple, continueFrom) { - - // return when this node is not an element node. - if(continueFrom.nodeType != continueFrom.ELEMENT_NODE) - return false; - - var classes = new String(continueFrom.getAttribute('class')); - var children = $A(continueFrom.childNodes); - - if(classes.include(triple.predicate.prefix + '-' + triple.predicate.name)) { - - var content = continueFrom.textContent; - if( (triple.object.type == ERDF.LITERAL) && - (triple.object.value == content)) - - continueFrom.parentNode.removeChild(continueFrom); - - return true; - - } else { - - children.each(function(_node) { - DataManager.__removeTripleRecursively(triple, _node)}); - return false; - } + // for each data set in the shape's serialization + shapeData.each(function (data) { - }, + // construct a triple's value + var value = (data.type == 'resource') ? + new ERDF.Resource(data.value) : + new ERDF.Literal(data.value); - /** - * graft() function - * Originally by Sean M. Burke from interglacial.com, altered for usage with - * SVG and namespace (xmlns) support. Be sure you understand xmlns before - * using this funtion, as it creates all grafted elements in the xmlns - * provided by you and all element's attribures in default xmlns. If you - * need to graft elements in a certain xmlns and wish to assign attributes - * in both that and another xmlns, you will need to do stepwise grafting, - * adding non-default attributes yourself or you'll have to enhance this - * function. Latter, I would appreciate: martin???apfelfabrik.de - * @param {Object} namespace The namespace in which - * elements should be grafted. - * @param {Object} parent The element that should contain the grafted - * structure after the function returned. - * @param {Object} t the crafting structure. - * @param {Object} doc the document in which grafting is performed. - */ - graft: function(namespace, parent, t, doc) { - - doc = (doc || (parent && parent.ownerDocument) || document); - var e; - if(t === undefined) { - echo( "Can't graft an undefined value"); - } else if(t.constructor == String) { - e = doc.createTextNode( t ); - } else { - for(var i = 0; i < t.length; i++) { - if( i === 0 && t[i].constructor == String ) { - var snared = t[i].match( /^([a-z][a-z0-9]*)\.([^\s\.]+)$/i ); - if( snared ) { - e = doc.createElementNS(namespace, snared[1]); - e.setAttributeNS(null, 'class', snared[2] ); - continue; - } - snared = t[i].match( /^([a-z][a-z0-9]*)$/i ); - if( snared ) { - e = doc.createElementNS(namespace, snared[1]); // but no class - continue; - } - - // Otherwise: - e = doc.createElementNS(namespace, "span"); - e.setAttribute(null, "class", "namelessFromLOL" ); - } - - if( t[i] === undefined ) { - echo("Can't graft an undefined value in a list!"); - } else if( t[i].constructor == String || t[i].constructor == Array) { - this.graft(namespace, e, t[i], doc ); - } else if( t[i].constructor == Number ) { - this.graft(namespace, e, t[i].toString(), doc ); - } else if( t[i].constructor == Object ) { - // hash's properties => element's attributes - for(var k in t[i]) { e.setAttributeNS(null, k, t[i][k] ); } - } else if( t[i].constructor == Boolean ) { - this.graft(namespace, e, t[i] ? 'true' : 'false', doc ); - } else - throw "Object " + t[i] + " is inscrutable as an graft arglet."; - } - } - - if(parent) parent.appendChild(e); - - return Element.extend(e); // return the topmost created node - }, + // construct triple and add it to the DOM. + DataManager.addTriple(new ERDF.Triple( + shapeResource, + {prefix: data.prefix, name: data.name}, + value + )); + }); + }, - setObject: function(triple) { + __persistDOM: function (facade) { - /** - * Erwartungen von Arvid an diese Funktion: - * - Es existiert genau ein triple mit dem Subjekt und Praedikat, - * das uebergeben wurde, und dieses haelt uebergebenes Objekt. - */ + // getChildShapes gets all shapes (nodes AND edges), deep flag + // makes it return a flattened child hierarchy. - var triples = DataManager.query( - triple.subject, - triple.predicate, - undefined - ); - - DataManager.removeTriples(triples); + var canvas = facade.getCanvas(); + var shapes = canvas.getChildShapes(true); + var result = ''; - DataManager.addTriple(triple); + // persist all shapes. + shapes.each(function (shape) { + DataManager.__forceExistance(shape); + }); + //DataManager.__synclocal(); - return true; - }, - - query: function(subject, predicate, object) { + DataManager.__renderCanvas(facade); + result += DataManager.serialize( + $(ERDF.__stripHashes(facade.getCanvas().resourceId)), true); - /* - * Typical triple. - * {value: subject, type: subjectType}, - * {prefix: schema.prefix, name: property}, - * {value: object, type: objectType}); - */ - - return DataManager._triples.select(function(triple) { - - var select = ((subject) ? - (triple.subject.type == subject.type) && - (triple.subject.value == subject.value) : true); - if(predicate) { - select = select && ((predicate.prefix) ? - (triple.predicate.prefix == predicate.prefix) : true); - select = select && ((predicate.name) ? - (triple.predicate.name == predicate.name) : true); - } - select = select && ((object) ? - (triple.object.type == object.type) && - (triple.object.value == object.value) : true); - return select; - }); - } -} + shapes.each(function (shape) { -Kickstart.register(DataManager.init); + DataManager.__persistShape(shape); + result += DataManager.serialize( + $(ERDF.__stripHashes(shape.resourceId)), true); + }); -function assert(expr, m) { if(!expr) throw m; }; + //result += DataManager.__renderCanvas(facade); -function DMCommand(action, triple) { - - // store action and triple. - this.action = action; - this.triple = triple; - - this.toString = function() { - return 'Command('+action+', '+triple+')'; - }; -} + return result; + }, -function DMCommandHandler(nextHandler) { - - /** - * Private method to set the next handler in the Chain of Responsibility - * (see http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern for - * details). - * @param {DMCommandHandler} handler The handler that is next in the chain. - */ - this.__setNext = function(handler) { - var _next = this.__next; - this.__next = nextHandler; - return _next ? _next : true; - }; - this.__setNext(nextHandler); - - /** - * Invokes the next handler. If there is no next handler, this method - * returns false, otherwise it forwards the result of the handling. - * @param {Object} command The command object to be processed. - */ - this.__invokeNext = function(command) { - return this.__next ? this.__next.handle(command) : false; - }; - - /** - * Handles a command. The abstract method process() is called with the - * command object that has been passed. If the process method catches the - * command (returns true on completion), the handle() method returns true. - * If the process() method doesn't catch the command, the next handler will - * be invoked. - * @param {Object} command The command object to be processed. - */ - this.handle = function(command) { - return this.process(command) ? true : this.__invokeNext(command); - } - - /** - * Empty process() method returning false. If javascript knew abstract - * class members, this would be one. - * @param {Object} command The command object to process. - */ - this.process = function(command) { return false; }; -}; + __renderCanvas: function (facade) { + + var canvas = facade.getCanvas(); + var stencilSets = facade.getStencilSets(); + var shapes = canvas.getChildShapes(true); + + DataManager.__forceExistance(canvas); + + DataManager.__persistShape(canvas); + + var shapeResource = new ERDF.Resource(canvas.resourceId); + + // remove all triples for this particular shape's resource + DataManager.removeTriples(DataManager.query( + shapeResource, undefined, undefined)); + + DataManager.addTriple(new ERDF.Triple( + shapeResource, + {prefix: "oryx", name: "mode"}, + new ERDF.Literal("writable") + )); + + DataManager.addTriple(new ERDF.Triple( + shapeResource, + {prefix: "oryx", name: "mode"}, + new ERDF.Literal("fullscreen") + )); + + stencilSets.values().each(function (stencilset) { + DataManager.addTriple(new ERDF.Triple( + shapeResource, + {prefix: "oryx", name: "stencilset"}, + new ERDF.Resource(stencilset.source().replace(/&/g, "%26")) + )); + + DataManager.addTriple(new ERDF.Triple( + shapeResource, + {prefix: "oryx", name: "ssnamespace"}, + new ERDF.Resource(stencilset.namespace()) + )); + + stencilset.extensions().keys().each(function (extension) { + DataManager.addTriple(new ERDF.Triple( + shapeResource, + {prefix: "oryx", name: "ssextension"}, + new ERDF.Literal(extension) + )); + }); + }); -/** - * This Handler manages the addition and the removal of meta elements in the - * head of the document. - * @param {DMCommandHandler} next The handler that is next in the chain. - */ -function MetaTagHandler(next) { - - DMCommandHandler.apply(this, [next]); - this.process = function(command) { - - with(command.triple) { - - /* assert prerequisites */ - if( !( - (subject instanceof ERDF.Resource) && - (subject.isCurrentDocument()) && - (object instanceof ERDF.Literal) - )) return false; - } - - }; -}; + shapes.each(function (shape) { + DataManager.addTriple(new ERDF.Triple( + shapeResource, + {prefix: "oryx", name: "render"}, + new ERDF.Resource("#" + shape.resourceId) + )); + }); + }, -var chain = new MetaTagHandler(); -var command = new DMCommand(TRIPLE_ADD, new ERDF.Triple( - new ERDF.Resource(''), - 'rdf:tool', - new ERDF.Literal('') -)); + __counter: 0, + __provideId: function () { -/* -if(chain.handle(command)) - alert('Handled!'); -*/ + while ($(RESOURCE_ID_PREFIX + DataManager.__counter)) + DataManager.__counter++; -ResourceManager = { - - __corrupt: false, - __latelyCreatedResource: undefined, - __listeners: $H(), - __token: 1, - - addListener: function(listener, mask) { - - if(!(listener instanceof Function)) - throw 'Resource event listener is not a function!'; - if(!(mask)) - throw 'Invalid mask for resource event listener registration.'; - - // construct controller and token. - var controller = {listener: listener, mask: mask}; - var token = ResourceManager.__token++; - - // add new listener. - ResourceManager.__listeners[token] = controller; - - // return the token generated. - return token; - }, - - removeListener: function(token) { - - // remove the listener with the token and return it. - return ResourceManager.__listners.remove(token); - }, - - __Event: function(action, resourceId) { - this.action = action; - this.resourceId = resourceId; - }, - - __dispatchEvent: function(event) { - - // get all listeners. for each listener, ... - ResourceManager.__listeners.values().each(function(controller) { - - // .. if listener subscribed to this type of event ... - if(event.action & controller.mask) - return controller.listener(event); - }); - }, + return RESOURCE_ID_PREFIX + DataManager.__counter; + }, - getResource: function(id) { + serializeDOM: function (facade) { - // get all possible resources for this. - id = ERDF.__stripHashes(id); - var resources = DataManager.query( - new ERDF.Resource('#'+id), - {prefix: 'raziel', name: 'entry'}, - undefined - ); + return DataManager.__persistDOM(facade); + }, - // check for consistency. - if((resources.length == 1) && (resources[0].object.isResource())) { - var entryUrl = resources[0].object.value; - return new ResourceManager.__Resource(id, entryUrl); - } + syncGlobal: function (facade) { - // else throw an error message. - throw ('Resource with id ' +id+ ' not recognized as such. ' + - ((resources.length > 1) ? - ' There is more than one raziel:entry URL.' : - ' There is no raziel:entry URL.')); + return DataManager.__syncglobal(facade); + }, - return false; - }, + /** + * This method is used to synchronize local DOM with remote resources. + * Local changes are commited to the server, and remote changes are + * performed to the local document. + * @param {Object} facade The facade of the editor that holds certain + * resource representations as shapes. + */ + __syncglobal: function (facade) { - __createResource: function(alternativeDiv) { - - var collectionUrls = DataManager.query( - new ERDF.Resource(''), - // TODO This will become raziel:collection in near future. - {prefix: 'raziel', name: 'collection'}, - undefined - ); - - // check for consistency. - - if( (collectionUrls.length == 1) && - (collectionUrls[0].object.isResource())) { - - // get the collection url. - - var collectionUrl = collectionUrls[0].object.value; - var resource = undefined; - - // if there is an old id, serialize the dummy div from there, - // otherwise create a dummy div on the fly. - - var serialization = alternativeDiv? alternativeDiv : - '
'; - - ResourceManager.__request( - 'POST', collectionUrl, serialization, - - // on success - function() { - - // get div and id that have been generated by the server. - - var response = (this.responseXML); - var div = response.childNodes[0]; - var id = div.getAttribute('id'); - - // store div in DOM - if(!$$('.' + PROCESSDATA_REF)[0]) - DataManager.graft(XMLNS.XHTML, - document.getElementsByTagNameNS(XMLNS.XHTML, 'body').item(0), ['div', {'class': PROCESSDATA_REF, 'style':'display:none;'}]); - - $$('.' + PROCESSDATA_REF)[0].appendChild(div.cloneNode(true)); - - // parse local erdf data once more. - - DataManager.__synclocal(); - - // get new resource object. - - resource = new ResourceManager.getResource(id); - - // set up an action informing of the creation. - - ResourceManager.__resourceActionSucceeded( - this, RESOURCE_CREATED, undefined); - }, - - function() { ResourceManager.__resourceActionFailed( - this, RESOURCE_CREATED, undefined);}, - false - ); - - return resource; - } - - // else - throw 'Could not create resource! raziel:collection URL is missing!'; - return false; + // getChildShapes gets all shapes (nodes AND edges), deep flag + // makes it return a flattened child hierarchy. - }, - - __Resource: function(id, url) { - - this.__id = id; - this.__url = url; - - /* - * Process URL is no longer needed to refer to the shape element on the - * canvas. AReSS uses the id's to gather information on fireing - * behaviour now. - */ - -// // find the process url. -// var processUrl = undefined; -// -// var urls = DataManager.query( -// new ERDF.Resource('#'+this.__id), -// {prefix: 'raziel', name: 'process'}, -// undefined -// ); -// -// if(urls.length == 0) { throw 'The resource with the id ' +id+ ' has no process url.'}; -// -// urls.each( function(triple) { -// -// // if there are more urls, use the last one. -// processUrl = triple.object.value; -// }); -// -// this.__processUrl = processUrl; -// -// // convenience function for getting the process url. -// this.processUrl = function() { -// return this.__processUrl; -// } + var canvas = facade.getCanvas(); + var shapes = canvas.getChildShapes(true); + // create dummy resource representations in the dom + // for all shapes that were newly created. - // convenience finction for getting the id. - this.id = function() { - return this.__id; - } + shapes.select(function (shape) { - // convenience finction for getting the entry url. - this.url = function() { - return this.__url; - } - - this.reload = function() { - var _url = this.__url; - var _id = this.__id; - ResourceManager.__request( - 'GET', _url, null, - function() { ResourceManager.__resourceActionSucceeded( - this, RESOURCE_RELOADED, _id); }, - function() { ResourceManager.__resourceActionFailed( - this, RESURCE_RELOADED, _id); }, - USE_ASYNCHRONOUS_REQUESTS - ); - }; - - this.save = function(synchronize) { - var _url = this.__url; - var _id = this.__id; - data = DataManager.serialize($(_id)); - ResourceManager.__request( - 'PUT', _url, data, - function() { ResourceManager.__resourceActionSucceeded( - this, synchronize ? RESOURCE_SAVED | RESOURCE_SYNCHRONIZED : RESOURCE_SAVED, _id); }, - function() { ResourceManager.__resourceActionFailed( - this, synchronize ? RESOURCE_SAVED | RESOURCE_SYNCHRONIZED : RESOURCE.SAVED, _id); }, - USE_ASYNCHRONOUS_REQUESTS - ); - }; - - this.remove = function() { - var _url = this.__url; - var _id = this.__id; - ResourceManager.__request( - 'DELETE', _url, null, - function() { ResourceManager.__resourceActionSucceeded( - this, RESOURCE_REMOVED, _id); }, - function() { ResourceManager.__resourceActionFailed( - this, RESOURCE_REMOVED, _id);}, - USE_ASYNCHRONOUS_REQUESTS - ); - }; - }, + // select shapes without resource id. - request: function(url, requestOptions) { - - var options = { - method: 'get', - asynchronous: true, - parameters: {} - }; - - Object.extend(options, requestOptions || {}); - - var params = Hash.toQueryString(options.parameters); - if (params) - url += (url.include('?') ? '&' : '?') + params; - - return ResourceManager.__request( - options.method, - url, - options.data, - (options.onSuccess instanceof Function ? function() { options.onSuccess(this); } : undefined ), - (options.onFailure instanceof Function ? function() { options.onFailure(this); } : undefined ), - options.asynchronous && USE_ASYNCHRONOUS_REQUESTS, - options.headers); - }, - - __request: function(method, url, data, success, error, async, headers) { - - // get a request object - var httpRequest = Try.these( - - /* do the Mozilla/Safari/Opera stuff */ - function() { return new XMLHttpRequest(); }, - - /* do the IE stuff */ - function() { return new ActiveXObject("Msxml2.XMLHTTP"); }, - function() { return new ActiveXObject("Microsoft.XMLHTTP") } - ); - - // if there is no request object ... - if (!httpRequest) { - if(!this.__corrupt) - throw 'This browser does not provide any AJAX functionality. You will not be able to use the software provided with the page you are viewing. Please consider installing appropriate extensions.'; - this.__corrupt = true; - return false; - } - - if(success instanceof Function) - httpRequest.onload = success; - if(error instanceof Function) { - httpRequest.onerror = error; - } - - var h = $H(headers) - h.keys().each(function(key) { - - httpRequest.setRequestHeader(key, h[key]); - }); - - try { - - if(SHOW_DEBUG_ALERTS_WHEN_SAVING) - - alert(method + ' ' + url + '\n' + - SHOW_EXTENDED_DEBUG_INFORMATION ? data : ''); - - // TODO Remove synchronous calls to the server as soon as xenodot - // handles asynchronous requests without failure. - httpRequest.open(method, url, !async?false:true); - httpRequest.send(data); - - } catch(e) { - return false; - } - return true; - }, - - __resourceActionSucceeded: function(transport, action, id) { - - var status = transport.status; - var response = transport.responseText; - - if(SHOW_DEBUG_ALERTS_WHEN_SAVING) - - alert(status + ' ' + url + '\n' + - SHOW_EXTENDED_DEBUG_INFORMATION ? data : ''); - - // if the status code is not in 2xx, throw an error. - if(status >= 300) - throw 'The server responded with an error: ' + status + '\n' + (SHOW_EXTENDED_DEBUG_INFORMATION ? + data : 'If you need additional information here, including the data sent by the server, consider setting SHOW_EXTENDED_DEBUG_INFORMATION to true.'); - - switch(action) { - - case RESOURCE_REMOVED: - - // get div and id - var response = (transport.responseXML); - var div = response.childNodes[0]; - var id = div.getAttribute('id'); - - // remove the resource from DOM - var localDiv = document.getElementById(id); - localDiv.parentNode.removeChild(localDiv); - break; - - case RESOURCE_CREATED: - - // nothing remains to be done. - break; - - case RESOURCE_SAVED | RESOURCE_SYNCHRONIZED: - - DataManager.__synclocal(); - - case RESOURCE_SAVED: - - // nothing remains to be done. - break; - - case RESOURCE_RELOADED: - - // get div and id - var response = (transport.responseXML); - var div = response.childNodes[0]; - var id = div.getAttribute('id'); - - // remove the local resource representation from DOM - var localDiv = document.getElementById(id) - localDiv.parentNode.removeChild(localDiv); - - // store div in DOM - if(!$$(PROCESSDATA_REF)[0]) - DataManager.graft(XMLNS.XHTML, - document.getElementsByTagNameNS(XMLNS.XHTML, 'body').item(0), ['div', {'class': PROCESSDATA_REF, 'style':'display:none;'}]); - - $$(PROCESSDATA_REF)[0].appendChild(div.cloneNode(true)); - DataManager.__synclocal(); - break; - - default: - DataManager.__synclocal(); + return !($(shape.resourceId)); - } - - // dispatch to all listeners ... - ResourceManager.__dispatchEvent( + }).each(function (shape) { - // ... an event describing the change that happened here. - new ResourceManager.__Event(action, id) - ); - }, + // create new resources for them. + if (USE_ARESS_WORKAROUNDS) { - __resourceActionFailed: function(transport, action, id) { - throw "Fatal: Resource action failed. There is something horribly " + - "wrong with either the server, the transport protocol or your " + - "online status. Sure you're online?"; - } -}/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + /* + * This is a workaround due to a bug in aress. Resources are + * ignoring changes to raziel:type property once they are + * created. As long as this is not fixed, the resource is now + * being created using a randomly guessed id, this temporary id + * is then used in references and the appropriate div is being + * populated with properties. + * + * AFTER THIS PHASE THE DATA IS INCONSISTENT AS REFERENCES POINT + * TO IDS THAT ARE UNKNOWN TO THE BACK END. + * + * After the resource is actually created in aress, it gets an id + * that is persistent. All shapes are then being populated with the + * correct id references and stored on the server. + * + * AFTER THE SAVE PROCESS HAS RETURNED, THE DATA IS CONSISTENT + * REGARDING THE ID REFERENCES AGAIN. + */ -/** - * The super class for all classes in ORYX. Adds some OOP feeling to javascript. - * See article "Object Oriented Super Class Method Calling with JavaScript" on - * http://truecode.blogspot.com/2006/08/object-oriented-super-class-method.html - * for a documentation on this. Fairly good article that points out errors in - * Douglas Crockford's inheritance and super method calling approach. - * Worth reading. - * @class Clazz - */ -var Clazz = function() {}; + var razielType = shape.properties['raziel-type']; -/** - * Empty constructor. - * @methodOf Clazz.prototype - */ -Clazz.prototype.construct = function() {}; + var div = '
' + + '' + razielType + '
'; -/** - * Can be used to build up inheritances of classes. - * @example - * var MyClass = Clazz.extend({ - * construct: function(myParam){ - * // Do sth. - * } - * }); - * var MySubClass = MyClass.extend({ - * construct: function(myParam){ - * // Use this to call constructor of super class - * arguments.callee.$.construct.apply(this, arguments); - * // Do sth. - * } - * }); - * @param {Object} def The definition of the new class. - */ -Clazz.extend = function(def) { - var classDef = function() { - if (arguments[0] !== Clazz) { this.construct.apply(this, arguments); } - }; - - var proto = new this(Clazz); - var superClass = this.prototype; - - for (var n in def) { - var item = def[n]; - if (item instanceof Function) item.$ = superClass; - proto[n] = item; - } + var r = ResourceManager.__createResource(div); + shape.resourceId = r.id(); - classDef.prototype = proto; - - //Give this new class the same static extend method - classDef.extend = this.extend; - return classDef; -};/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + } else { -if(!ORYX) var ORYX = {}; + var r = ResourceManager.__createResource(); + shape.resourceId = r.id(); + } -if(!ORYX.CONFIG) ORYX.CONFIG = {}; + }); -/** - * This file contains URI constants that may be used for XMLHTTPRequests. - */ + shapes.each(function (shape) { -ORYX.CONFIG.ROOT_PATH = "editor/"; //TODO: Remove last slash!! -ORYX.CONFIG.EXPLORER_PATH = "explorer"; -ORYX.CONFIG.LIBS_PATH = "libs"; + // store all shapes. + DataManager.__storeShape(shape); + }); + }, -/** - * Regular Config - */ -ORYX.CONFIG.SERVER_HANDLER_ROOT = "service"; -ORYX.CONFIG.SERVER_EDITOR_HANDLER = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/editor"; -ORYX.CONFIG.SERVER_MODEL_HANDLER = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/model"; -ORYX.CONFIG.STENCILSET_HANDLER = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/editor_stencilset?embedsvg=true&url=true&namespace="; -ORYX.CONFIG.STENCIL_SETS_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/editor_stencilset"; - -ORYX.CONFIG.PLUGINS_CONFIG = "editor-app/plugins.xml"; -ORYX.CONFIG.SYNTAXCHECKER_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/syntaxchecker"; -ORYX.CONFIG.DEPLOY_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/model/deploy"; -ORYX.CONFIG.MODEL_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/models"; -ORYX.CONFIG.FORM_FLOW_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/formflows"; -ORYX.CONFIG.FORM_FLOW_IMAGE_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/formflow"; -ORYX.CONFIG.FORM_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/forms"; -ORYX.CONFIG.FORM_IMAGE_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/form"; -ORYX.CONFIG.SUB_PROCESS_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/subprocesses"; -ORYX.CONFIG.SUB_PROCESS_IMAGE_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/subprocess"; -ORYX.CONFIG.TEST_SERVICE_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/service/"; - -ORYX.CONFIG.SERVICE_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/services"; -ORYX.CONFIG.CONDITION_ELEMENT_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/conditionelements"; -ORYX.CONFIG.VARIABLEDEF_ELEMENT_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/variabledefinitionelements"; -ORYX.CONFIG.VALIDATOR_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/validators"; - -ORYX.CONFIG.SS_EXTENSIONS_FOLDER = ORYX.CONFIG.ROOT_PATH + "stencilsets/extensions/"; -ORYX.CONFIG.SS_EXTENSIONS_CONFIG = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/editor_ssextensions"; -ORYX.CONFIG.ORYX_NEW_URL = "/new"; -ORYX.CONFIG.BPMN_LAYOUTER = ORYX.CONFIG.ROOT_PATH + "bpmnlayouter"; - -ORYX.CONFIG.EXPRESSION_METADATA_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/expression-metadata"; -ORYX.CONFIG.DATASOURCE_METADATA_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/datasource-metadata";/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + /** + * This method serializes a single div into a string that satisfies the + * client/server communication protocol. It ingnores all elements that have + * an attribute named class that includes 'transient'. + * @param {Object} node the element to serialize. + * @param {Object} preserveNamespace whether to preserve the parent's + * namespace. If you are not sure about namespaces, provide + * just the element to be serialized. + */ + serialize: function (node, preserveNamespace) { -if(!ORYX) var ORYX = {}; + if (node.nodeType == node.ELEMENT_NODE) { + // serialize an element node. -if(!ORYX.CONFIG) ORYX.CONFIG = {}; + var children = $A(node.childNodes); + var attributes = $A(node.attributes); + var clazz = new String(node.getAttribute('class')); + var ignore = clazz.split(' ').member('transient'); -/** - * Signavio specific variables - */ -ORYX.CONFIG.BACKEND_SWITCH = true; -ORYX.CONFIG.PANEL_LEFT_WIDTH = 250; -ORYX.CONFIG.PANEL_RIGHT_COLLAPSED = true; -ORYX.CONFIG.PANEL_RIGHT_WIDTH = 300; -ORYX.CONFIG.APPNAME = 'KISBPM'; -ORYX.CONFIG.WEB_URL = "."; + // ignore transients. -ORYX.CONFIG.BLANK_IMAGE = ORYX.CONFIG.LIBS_PATH + '/ext-2.0.2/resources/images/default/s.gif'; + if (ignore) + return ''; -/* Specify offset of header */ -ORYX.CONFIG.OFFSET_HEADER = 61; + // start serialization. -/* Show grid line while dragging */ -ORYX.CONFIG.SHOW_GRIDLINE = true; + var result = '<' + node.nodeName; - /* Editor-Mode */ -ORYX.CONFIG.MODE_READONLY = "readonly"; -ORYX.CONFIG.MODE_FULLSCREEN = "fullscreen"; -ORYX.CONFIG.WINDOW_HEIGHT = 800; -ORYX.CONFIG.PREVENT_LOADINGMASK_AT_READY = false; + // preserve namespace? + if (!preserveNamespace) + result += ' xmlns="' + (node.namespaceURI ? node.namespaceURI : XMLNS.XHTML) + '" xmlns:oryx="http://oryx-editor.org"'; - /* Plugins */ -ORYX.CONFIG.PLUGINS_ENABLED = true; -ORYX.CONFIG.PLUGINS_FOLDER = "Plugins/"; + // add all attributes. -ORYX.CONFIG.BPMN20_SCHEMA_VALIDATION_ON = true; + attributes.each(function (attribute) { + result += ' ' + attribute.nodeName + '="' + + attribute.nodeValue + '"'; + }); - /* Namespaces */ -ORYX.CONFIG.NAMESPACE_ORYX = "http://www.b3mn.org/oryx"; -ORYX.CONFIG.NAMESPACE_SVG = "http://www.w3.org/2000/svg"; - - /* UI */ -ORYX.CONFIG.CANVAS_WIDTH = 1200; -ORYX.CONFIG.CANVAS_HEIGHT = 1050; -ORYX.CONFIG.CANVAS_RESIZE_INTERVAL = 100; -ORYX.CONFIG.CANVAS_MIN_WIDTH = 800; -ORYX.CONFIG.CANVAS_MIN_HEIGHT = 300; -ORYX.CONFIG.SELECTED_AREA_PADDING = 4; -ORYX.CONFIG.CANVAS_BACKGROUND_COLOR = "none"; -ORYX.CONFIG.GRID_DISTANCE = 30; -ORYX.CONFIG.GRID_ENABLED = true; -ORYX.CONFIG.ZOOM_OFFSET = 0.1; -ORYX.CONFIG.DEFAULT_SHAPE_MARGIN = 60; -ORYX.CONFIG.SCALERS_SIZE = 7; -ORYX.CONFIG.MINIMUM_SIZE = 20; -ORYX.CONFIG.MAXIMUM_SIZE = 10000; -ORYX.CONFIG.OFFSET_MAGNET = 15; -ORYX.CONFIG.OFFSET_EDGE_LABEL_TOP = 8; -ORYX.CONFIG.OFFSET_EDGE_LABEL_BOTTOM = 8; -ORYX.CONFIG.OFFSET_EDGE_BOUNDS = 5; -ORYX.CONFIG.COPY_MOVE_OFFSET = 30; - -ORYX.CONFIG.BORDER_OFFSET = 14; - -ORYX.CONFIG.MAX_NUM_SHAPES_NO_GROUP = 20; // Updated so the form editor shows all elements at once + // close if no children. -ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER = 30; -ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET = 45; + if (children.length == 0) + result += '/>'; - /* Shape-Menu Align */ -ORYX.CONFIG.SHAPEMENU_RIGHT = "Oryx_Right"; -ORYX.CONFIG.SHAPEMENU_BOTTOM = "Oryx_Bottom"; -ORYX.CONFIG.SHAPEMENU_LEFT = "Oryx_Left"; -ORYX.CONFIG.SHAPEMENU_TOP = "Oryx_Top"; - - - /* Morph-Menu Item */ -ORYX.CONFIG.MORPHITEM_DISABLED = "Oryx_MorphItem_disabled"; - - /* Property type names */ -ORYX.CONFIG.TYPE_STRING = "string"; -ORYX.CONFIG.TYPE_BOOLEAN = "boolean"; -ORYX.CONFIG.TYPE_INTEGER = "integer"; -ORYX.CONFIG.TYPE_FLOAT = "float"; -ORYX.CONFIG.TYPE_COLOR = "color"; -ORYX.CONFIG.TYPE_DATE = "date"; -ORYX.CONFIG.TYPE_CHOICE = "choice"; -ORYX.CONFIG.TYPE_URL = "url"; -ORYX.CONFIG.TYPE_DIAGRAM_LINK = "diagramlink"; -ORYX.CONFIG.TYPE_COMPLEX = "complex"; -ORYX.CONFIG.TYPE_MULTIPLECOMPLEX = "multiplecomplex"; -ORYX.CONFIG.TYPE_TEXT = "text"; -ORYX.CONFIG.TYPE_KISBPM_MULTIINSTANCE = "kisbpm-multiinstance"; -ORYX.CONFIG.TYPE_MODEL_LINK = "modellink"; -ORYX.CONFIG.TYPE_FORM_FLOW_LINK = "formflowlink"; -ORYX.CONFIG.TYPE_FORM_LINK = "formlink"; -ORYX.CONFIG.TYPE_SUB_PROCESS_LINK = "subprocesslink"; -ORYX.CONFIG.TYPE_SERVICE_LINK = "servicelink"; -ORYX.CONFIG.TYPE_CONDITIONS = "conditions"; -ORYX.CONFIG.TYPE_VARIABLES = "variables"; -ORYX.CONFIG.TYPE_LISTENER = "listener"; -ORYX.CONFIG.TYPE_EPC_FREQ = "epcfrequency"; -ORYX.CONFIG.TYPE_GLOSSARY_LINK = "glossarylink"; -ORYX.CONFIG.TYPE_EXPRESSION = "expression"; -ORYX.CONFIG.TYPE_DATASOURCE = "datasource"; -ORYX.CONFIG.TYPE_DATASOURCE_MINIMAL = "datasource-minimal"; -ORYX.CONFIG.TYPE_VALIDATORS = "validators"; - - - /* Vertical line distance of multiline labels */ -ORYX.CONFIG.LABEL_LINE_DISTANCE = 2; -ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT = 12; - - /* Open Morph Menu with Hover */ -ORYX.CONFIG.ENABLE_MORPHMENU_BY_HOVER = false; + else { + // serialize all children. - /* Editor constants come here */ -ORYX.CONFIG.EDITOR_ALIGN_BOTTOM = 0x01; -ORYX.CONFIG.EDITOR_ALIGN_MIDDLE = 0x02; -ORYX.CONFIG.EDITOR_ALIGN_TOP = 0x04; -ORYX.CONFIG.EDITOR_ALIGN_LEFT = 0x08; -ORYX.CONFIG.EDITOR_ALIGN_CENTER = 0x10; -ORYX.CONFIG.EDITOR_ALIGN_RIGHT = 0x20; -ORYX.CONFIG.EDITOR_ALIGN_SIZE = 0x30; - - /* Event types */ -ORYX.CONFIG.EVENT_MOUSEDOWN = "mousedown"; -ORYX.CONFIG.EVENT_MOUSEUP = "mouseup"; -ORYX.CONFIG.EVENT_MOUSEOVER = "mouseover"; -ORYX.CONFIG.EVENT_MOUSEOUT = "mouseout"; -ORYX.CONFIG.EVENT_MOUSEMOVE = "mousemove"; -ORYX.CONFIG.EVENT_DBLCLICK = "dblclick"; -ORYX.CONFIG.EVENT_KEYDOWN = "keydown"; -ORYX.CONFIG.EVENT_KEYUP = "keyup"; - -ORYX.CONFIG.EVENT_LOADED = "editorloaded"; -ORYX.CONFIG.EVENT_SAVED = "editorSaved"; - -ORYX.CONFIG.EVENT_EXECUTE_COMMANDS = "executeCommands"; -ORYX.CONFIG.EVENT_STENCIL_SET_LOADED = "stencilSetLoaded"; -ORYX.CONFIG.EVENT_SELECTION_CHANGED = "selectionchanged"; -ORYX.CONFIG.EVENT_SHAPEADDED = "shapeadded"; -ORYX.CONFIG.EVENT_SHAPEREMOVED = "shaperemoved"; -ORYX.CONFIG.EVENT_PROPERTY_CHANGED = "propertyChanged"; -ORYX.CONFIG.EVENT_DRAGDROP_START = "dragdrop.start"; -ORYX.CONFIG.EVENT_SHAPE_MENU_CLOSE = "shape.menu.close"; -ORYX.CONFIG.EVENT_DRAGDROP_END = "dragdrop.end"; -ORYX.CONFIG.EVENT_RESIZE_START = "resize.start"; -ORYX.CONFIG.EVENT_RESIZE_END = "resize.end"; -ORYX.CONFIG.EVENT_DRAGDOCKER_DOCKED = "dragDocker.docked"; -ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW = "highlight.showHighlight"; -ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE = "highlight.hideHighlight"; -ORYX.CONFIG.EVENT_LOADING_ENABLE = "loading.enable"; -ORYX.CONFIG.EVENT_LOADING_DISABLE = "loading.disable"; -ORYX.CONFIG.EVENT_LOADING_STATUS = "loading.status"; -ORYX.CONFIG.EVENT_OVERLAY_SHOW = "overlay.show"; -ORYX.CONFIG.EVENT_OVERLAY_HIDE = "overlay.hide"; -ORYX.CONFIG.EVENT_ARRANGEMENT_TOP = "arrangement.setToTop"; -ORYX.CONFIG.EVENT_ARRANGEMENT_BACK = "arrangement.setToBack"; -ORYX.CONFIG.EVENT_ARRANGEMENT_FORWARD = "arrangement.setForward"; -ORYX.CONFIG.EVENT_ARRANGEMENT_BACKWARD = "arrangement.setBackward"; -ORYX.CONFIG.EVENT_PROPWINDOW_PROP_CHANGED = "propertyWindow.propertyChanged"; -ORYX.CONFIG.EVENT_LAYOUT_ROWS = "layout.rows"; -ORYX.CONFIG.EVENT_LAYOUT_BPEL = "layout.BPEL"; -ORYX.CONFIG.EVENT_LAYOUT_BPEL_VERTICAL = "layout.BPEL.vertical"; -ORYX.CONFIG.EVENT_LAYOUT_BPEL_HORIZONTAL = "layout.BPEL.horizontal"; -ORYX.CONFIG.EVENT_LAYOUT_BPEL_SINGLECHILD = "layout.BPEL.singlechild"; -ORYX.CONFIG.EVENT_LAYOUT_BPEL_AUTORESIZE = "layout.BPEL.autoresize"; -ORYX.CONFIG.EVENT_AUTOLAYOUT_LAYOUT = "autolayout.layout"; -ORYX.CONFIG.EVENT_UNDO_EXECUTE = "undo.execute"; -ORYX.CONFIG.EVENT_UNDO_ROLLBACK = "undo.rollback"; -ORYX.CONFIG.EVENT_BUTTON_UPDATE = "toolbar.button.update"; -ORYX.CONFIG.EVENT_LAYOUT = "layout.dolayout"; -ORYX.CONFIG.EVENT_GLOSSARY_LINK_EDIT = "glossary.link.edit"; -ORYX.CONFIG.EVENT_GLOSSARY_SHOW = "glossary.show.info"; -ORYX.CONFIG.EVENT_GLOSSARY_NEW = "glossary.show.new"; -ORYX.CONFIG.EVENT_DOCKERDRAG = "dragTheDocker"; -ORYX.CONFIG.EVENT_CANVAS_SCROLL = "canvas.scroll"; - -ORYX.CONFIG.EVENT_SHOW_PROPERTYWINDOW = "propertywindow.show"; -ORYX.CONFIG.EVENT_ABOUT_TO_SAVE = "file.aboutToSave"; - - /* Selection Shapes Highlights */ -ORYX.CONFIG.SELECTION_HIGHLIGHT_SIZE = 5; -ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR = "#4444FF"; -ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR2 = "#9999FF"; - -ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_CORNER = "corner"; -ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE = "rectangle"; - -ORYX.CONFIG.SELECTION_VALID_COLOR = "#00FF00"; -ORYX.CONFIG.SELECTION_INVALID_COLOR = "#FF0000"; - - -ORYX.CONFIG.DOCKER_DOCKED_COLOR = "#00FF00"; -ORYX.CONFIG.DOCKER_UNDOCKED_COLOR = "#FF0000"; -ORYX.CONFIG.DOCKER_SNAP_OFFSET = 10; - - /* Copy & Paste */ -ORYX.CONFIG.EDIT_OFFSET_PASTE = 10; - - /* Key-Codes */ -ORYX.CONFIG.KEY_CODE_X = 88; -ORYX.CONFIG.KEY_CODE_C = 67; -ORYX.CONFIG.KEY_CODE_V = 86; -ORYX.CONFIG.KEY_CODE_DELETE = 46; -ORYX.CONFIG.KEY_CODE_META = 224; -ORYX.CONFIG.KEY_CODE_BACKSPACE = 8; -ORYX.CONFIG.KEY_CODE_LEFT = 37; -ORYX.CONFIG.KEY_CODE_RIGHT = 39; -ORYX.CONFIG.KEY_CODE_UP = 38; -ORYX.CONFIG.KEY_CODE_DOWN = 40; - - // TODO Determine where the lowercase constants are still used and remove them from here. -ORYX.CONFIG.KEY_Code_enter = 12; -ORYX.CONFIG.KEY_Code_left = 37; -ORYX.CONFIG.KEY_Code_right = 39; -ORYX.CONFIG.KEY_Code_top = 38; -ORYX.CONFIG.KEY_Code_bottom = 40; + result += '>'; + children.each(function (_node) { + result += DataManager.serialize(_node, true) + }); + result += '' + } -/* Supported Meta Keys */ - -ORYX.CONFIG.META_KEY_META_CTRL = "metactrl"; -ORYX.CONFIG.META_KEY_ALT = "alt"; -ORYX.CONFIG.META_KEY_SHIFT = "shift"; + return result; -/* Key Actions */ + } else if (node.nodeType == node.TEXT_NODE) { -ORYX.CONFIG.KEY_ACTION_DOWN = "down"; -ORYX.CONFIG.KEY_ACTION_UP = "up"; + // serialize a text node. + return node.nodeValue; + } + //TODO serialize cdata areas also. + //TODO work on namespace awareness. + }, -/* Form Rowlayouting */ -ORYX.CONFIG.FORM_ROW_WIDTH = 350; -ORYX.CONFIG.FORM_GROUP_MARGIN = 5; -ORYX.CONFIG.FORM_GROUP_EMPTY_HEIGHT = 100; + addTriple: function (triple) { -/* Form element types */ -ORYX.CONFIG.FORM_ELEMENT_ID_PREFIX = 'http://b3mn.org/stencilset/xforms'; -ORYX.CONFIG.FORM_ELEMENT_TYPE_ROOT = 'http://b3mn.org/stencilset/xforms#XForm'; -ORYX.CONFIG.FORM_ELEMENT_TYPE_GROUP = 'http://b3mn.org/stencilset/xforms#Group'; -ORYX.CONFIG.FORM_ELEMENT_TYPE_REPEATING_GROUP = 'http://b3mn.org/stencilset/xforms#RepeatingGroup'; -ORYX.CONFIG.FORM_ELEMENT_TYPE_LABEL_FIELD = 'http://b3mn.org/stencilset/xforms#LabelField'; - - /* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + // assert the subject is a resource -function printf() { - - var result = arguments[0]; - for (var i=1; i= ORYX_LOGLEVEL_TRACE) - ORYX.Log.__log('TRACE', arguments); }, - debug: function() { if(ORYX_LOGLEVEL >= ORYX_LOGLEVEL_DEBUG) - ORYX.Log.__log('DEBUG', arguments); }, - info: function() { if(ORYX_LOGLEVEL >= ORYX_LOGLEVEL_INFO) - ORYX.Log.__log('INFO', arguments); }, - warn: function() { if(ORYX_LOGLEVEL >= ORYX_LOGLEVEL_WARN) - ORYX.Log.__log('WARN', arguments); }, - error: function() { if(ORYX_LOGLEVEL >= ORYX_LOGLEVEL_ERROR) - ORYX.Log.__log('ERROR', arguments); }, - fatal: function() { if(ORYX_LOGLEVEL >= ORYX_LOGLEVEL_FATAL) - ORYX.Log.__log('FATAL', arguments); }, - - __log: function(prefix, messageParts) { - - messageParts[0] = (new Date()).getTime() + " " - + prefix + " " + messageParts[0]; - var message = printf.apply(null, messageParts); - - ORYX.Log.__appenders.each(function(appender) { - appender.append(message); - }); - }, - - addAppender: function(appender) { - ORYX.Log.__appenders.push(appender); - } - }, + // alert('Removing ' +triples.length+' triples.'); - /** - * First bootstrapping layer. The Oryx loading procedure begins. In this - * step, all preliminaries that are not in the responsibility of Oryx to be - * met have to be checked here, such as the existance of the prototpe - * library in the current execution environment. After that, the second - * bootstrapping layer is being invoked. Failing to ensure that any - * preliminary condition is not met has to fail with an error. - */ - load: function() { - - ORYX.Log.debug("Oryx begins loading procedure."); - - // check for prototype - if( (typeof Prototype=='undefined') || - (typeof Element == 'undefined') || - (typeof Element.Methods=='undefined') || - parseFloat(Prototype.Version.split(".")[0] + "." + - Prototype.Version.split(".")[1]) < 1.5) - - throw("Application requires the Prototype JavaScript framework >= 1.5.3"); - - ORYX.Log.debug("Prototype > 1.5 found."); - - // continue loading. - ORYX._load(); - }, + // from all the triples select those ... + var removed = triples.select( + function (triple) { - /** - * Second bootstrapping layer. The oryx configuration is checked. When not - * yet loaded, config.js is being requested from the server. A repeated - * error in retrieving the configuration will result in an error to be - * thrown after a certain time of retries. Once the configuration is there, - * all urls that are registered with oryx loading are being requested from - * the server. Once everything is loaded, the third layer is being invoked. - */ - _load: function() { - /* - // if configuration not there already, - if(!(ORYX.CONFIG)) { - - // if this is the first attempt... - if(ORYX.configrationRetries == 0) { - - // get the path and filename. - var configuration = ORYX.PATH + ORYX.CONFIGURATION; - - ORYX.Log.debug("Configuration not found, loading from '%0'.", - configuration); - - // require configuration file. - Kickstart.require(configuration); - - // else if attempts exceeded ... - } else if(ORYX.configrationRetries >= ORYX_CONFIGURATION_WAIT_ATTEMPTS) { - - throw "Tried to get configuration" + - ORYX_CONFIGURATION_WAIT_ATTEMPTS + - " times from '" + configuration + "'. Giving up." - - } else if(ORYX.configrationRetries > 0){ - - // point out how many attempts are left... - ORYX.Log.debug("Waiting once more (%0 attempts left)", - (ORYX_CONFIGURATION_WAIT_ATTEMPTS - - ORYX.configrationRetries)); + // TODO remove also from triple store. + // ... that were actually removed. + return DataManager.__removeTriple(triple); + }); - } - - // any case: continue in a moment with increased retry count. - ORYX.configrationRetries++; - window.setTimeout(ORYX._load, ORYX_CONFIGURATION_DELAY); - return; - } - - ORYX.Log.info("Configuration loaded."); - - // load necessary scripts. - ORYX.URLS.each(function(url) { - ORYX.Log.debug("Requireing '%0'", url); - Kickstart.require(ORYX.PATH + url) }); - */ - // configurate logging and load plugins. - ORYX.loadPlugins(); - }, + // sync and return removed triples. + // DataManager.__synclocal(); + return removed; + }, - /** - * Third bootstrapping layer. This is where first the plugin coniguration - * file is loaded into oryx, analyzed, and where all plugins are being - * requested by the server. Afterwards, all editor instances will be - * initialized. - */ - loadPlugins: function() { - - // load plugins if enabled. - if(ORYX.CONFIG.PLUGINS_ENABLED) - ORYX._loadPlugins() - else - ORYX.Log.warn("Ignoring plugins, loading Core only."); - - // init the editor instances. - init(); - }, - - _loadPlugins: function() { + removeTriple: function (triple) { - // load plugin configuration file. - var source = ORYX.CONFIG.PLUGINS_CONFIG; + // remember whether the triple was actually removed. + var result = DataManager.__removeTriple(triple); - ORYX.Log.debug("Loading plugin configuration from '%0'.", source); - - new Ajax.Request(source, { - asynchronous: false, - method: 'get', - onSuccess: function(result) { + // sync and return removed triples. + // DataManager.__synclocal(); + return result; + }, - /* - * This is the method that is being called when the plugin - * configuration was successfully loaded from the server. The - * file has to be processed and the contents need to be - * considered for further plugin requireation. - */ - - ORYX.Log.info("Plugin configuration file loaded."); - - // get plugins.xml content - var resultXml = result.responseXML; - - // TODO: Describe how properties are handled. - // Get the globale Properties - var globalProperties = []; - var preferences = $A(resultXml.getElementsByTagName("properties")); - preferences.each( function(p) { - - var props = $A(p.childNodes); - props.each( function(prop) { - var property = new Hash(); - - // get all attributes from the node and set to global properties - var attributes = $A(prop.attributes) - attributes.each(function(attr){property[attr.nodeName] = attr.nodeValue}); - if(attributes.length > 0) { globalProperties.push(property) }; - }); - }); + __removeTriple: function (triple) { - - // TODO Why are we using XML if we don't respect structure anyway? - // for each plugin element in the configuration.. - var plugin = resultXml.getElementsByTagName("plugin"); - $A(plugin).each( function(node) { - - // get all element's attributes. - // TODO: What about: var pluginData = $H(node.attributes) !? - var pluginData = new Hash(); - $A(node.attributes).each( function(attr){ - pluginData[attr.nodeName] = attr.nodeValue}); - - // ensure there's a name attribute. - if(!pluginData['name']) { - ORYX.Log.error("A plugin is not providing a name. Ingnoring this plugin."); - return; - } + // assert the subject is a resource + if (!triple.subject.type == ERDF.LITERAL) - // ensure there's a source attribute. - if(!pluginData['source']) { - ORYX.Log.error("Plugin with name '%0' doesn't provide a source attribute.", pluginData['name']); - return; - } - - // Get all private Properties - var propertyNodes = node.getElementsByTagName("property"); - var properties = []; - $A(propertyNodes).each(function(prop) { - var property = new Hash(); - - // Get all Attributes from the Node - var attributes = $A(prop.attributes) - attributes.each(function(attr){property[attr.nodeName] = attr.nodeValue}); - if(attributes.length > 0) { properties.push(property) }; - - }); - - // Set all Global-Properties to the Properties - properties = properties.concat(globalProperties); - - // Set Properties to Plugin-Data - pluginData['properties'] = properties; - - // Get the RequieredNodes - var requireNodes = node.getElementsByTagName("requires"); - var requires; - $A(requireNodes).each(function(req) { - var namespace = $A(req.attributes).find(function(attr){ return attr.name == "namespace"}) - if( namespace && namespace.nodeValue ){ - if( !requires ){ - requires = {namespaces:[]} - } - - requires.namespaces.push(namespace.nodeValue) - } - }); - - // Set Requires to the Plugin-Data, if there is one - if( requires ){ - pluginData['requires'] = requires; - } + throw 'Cannot remove the triple ' + triple.toString() + + ' because the subject is not a resource.'; + // get the element which represents this triple's subject. + var elementId = ERDF.__stripHashes(triple.subject.value); + var element = $(elementId); - // Get the RequieredNodes - var notUsesInNodes = node.getElementsByTagName("notUsesIn"); - var notUsesIn; - $A(notUsesInNodes).each(function(not) { - var namespace = $A(not.attributes).find(function(attr){ return attr.name == "namespace"}) - if( namespace && namespace.nodeValue ){ - if( !notUsesIn ){ - notUsesIn = {namespaces:[]} - } - - notUsesIn.namespaces.push(namespace.nodeValue) - } - }); - - // Set Requires to the Plugin-Data, if there is one - if( notUsesIn ){ - pluginData['notUsesIn'] = notUsesIn; - } - - - var url = ORYX.PATH + ORYX.CONFIG.PLUGINS_FOLDER + pluginData['source']; - - ORYX.Log.debug("Requireing '%0'", url); - - // Add the Script-Tag to the Site - //Kickstart.require(url); - - ORYX.Log.info("Plugin '%0' successfully loaded.", pluginData['name']); - - // Add the Plugin-Data to all available Plugins - ORYX.availablePlugins.push(pluginData); - - }); - - }, - onFailure:this._loadPluginsOnFails - }); + // assert the subject is inside this document. + if (!element) - }, + throw 'Cannot remove the triple ' + triple.toString() + + ' because the subject is not in the document.'; - _loadPluginsOnFails: function(result) { + if (triple.object.type == ERDF.LITERAL) { - ORYX.Log.error("Plugin configuration file not available."); - } -}); + // continue searching actively for the triple. + var result = DataManager.__removeTripleRecursively(triple, element); + return result; + } + }, + __removeTripleRecursively: function (triple, continueFrom) { -/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + // return when this node is not an element node. + if (continueFrom.nodeType != continueFrom.ELEMENT_NODE) + return false; -/** - * Init namespaces - */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} -if(!ORYX.Core.SVG) {ORYX.Core.SVG = {};} + var classes = new String(continueFrom.getAttribute('class')); + var children = $A(continueFrom.childNodes); + if (classes.include(triple.predicate.prefix + '-' + triple.predicate.name)) { -/** - * EditPathHandler - * - * Edit SVG paths' coordinates according to specified from-to movement and - * horizontal and vertical scaling factors. - * The resulting path's d attribute is stored in instance variable d. - * - * @constructor - */ -ORYX.Core.SVG.EditPathHandler = Clazz.extend({ - - construct: function() { - arguments.callee.$.construct.apply(this, arguments); - - this.x = 0; - this.y = 0; - this.oldX = 0; - this.oldY = 0; - this.deltaWidth = 1; - this.deltaHeight = 1; - - this.d = ""; - }, - - /** - * init - * - * @param {float} x Target point's x-coordinate - * @param {float} y Target point's y-coordinate - * @param {float} oldX Reference point's x-coordinate - * @param {float} oldY Reference point's y-coordinate - * @param {float} deltaWidth Horizontal scaling factor - * @param {float} deltaHeight Vertical scaling factor - */ - init: function(x, y, oldX, oldY, deltaWidth, deltaHeight) { - this.x = x; - this.y = y; - this.oldX = oldX; - this.oldY = oldY; - this.deltaWidth = deltaWidth; - this.deltaHeight = deltaHeight; - - this.d = ""; - }, + var content = continueFrom.textContent; + if ((triple.object.type == ERDF.LITERAL) && + (triple.object.value == content)) - /** - * editPointsAbs - * - * @param {Array} points Array of absolutePoints - */ - editPointsAbs: function(points) { - if(points instanceof Array) { - var newPoints = []; - var x, y; - for(var i = 0; i < points.length; i++) { - x = (parseFloat(points[i]) - this.oldX)*this.deltaWidth + this.x; - i++; - y = (parseFloat(points[i]) - this.oldY)*this.deltaHeight + this.y; - newPoints.push(x); - newPoints.push(y); - } - - return newPoints; - } else { - //TODO error - } - }, - - /** - * editPointsRel - * - * @param {Array} points Array of absolutePoints - */ - editPointsRel: function(points) { - if(points instanceof Array) { - var newPoints = []; - var x, y; - for(var i = 0; i < points.length; i++) { - x = parseFloat(points[i])*this.deltaWidth; - i++; - y = parseFloat(points[i])*this.deltaHeight; - newPoints.push(x); - newPoints.push(y); - } - - return newPoints; - } else { - //TODO error - } - }, + continueFrom.parentNode.removeChild(continueFrom); - /** - * arcAbs - A - * - * @param {Number} rx - * @param {Number} ry - * @param {Number} xAxisRotation - * @param {Boolean} largeArcFlag - * @param {Boolean} sweepFlag - * @param {Number} x - * @param {Number} y - */ - arcAbs: function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) { - var pointsAbs = this.editPointsAbs([x, y]); - var pointsRel = this.editPointsRel([rx, ry]); - - this.d = this.d.concat(" A" + pointsRel[0] + " " + pointsRel[1] + - " " + xAxisRotation + " " + largeArcFlag + - " " + sweepFlag + " " + pointsAbs[0] + " " + - pointsAbs[1] + " "); - }, + return true; - /** - * arcRel - a - * - * @param {Number} rx - * @param {Number} ry - * @param {Number} xAxisRotation - * @param {Boolean} largeArcFlag - * @param {Boolean} sweepFlag - * @param {Number} x - * @param {Number} y - */ - arcRel: function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) { - var pointsRel = this.editPointsRel([rx, ry, x, y]); - - this.d = this.d.concat(" a" + pointsRel[0] + " " + pointsRel[1] + - " " + xAxisRotation + " " + largeArcFlag + - " " + sweepFlag + " " + pointsRel[2] + " " + - pointsRel[3] + " "); - }, + } else { - /** - * curvetoCubicAbs - C - * - * @param {Number} x1 - * @param {Number} y1 - * @param {Number} x2 - * @param {Number} y2 - * @param {Number} x - * @param {Number} y - */ - curvetoCubicAbs: function(x1, y1, x2, y2, x, y) { - var pointsAbs = this.editPointsAbs([x1, y1, x2, y2, x, y]); - - this.d = this.d.concat(" C" + pointsAbs[0] + " " + pointsAbs[1] + - " " + pointsAbs[2] + " " + pointsAbs[3] + - " " + pointsAbs[4] + " " + pointsAbs[5] + " "); - }, + children.each(function (_node) { + DataManager.__removeTripleRecursively(triple, _node) + }); + return false; + } - /** - * curvetoCubicRel - c - * - * @param {Number} x1 - * @param {Number} y1 - * @param {Number} x2 - * @param {Number} y2 - * @param {Number} x - * @param {Number} y - */ - curvetoCubicRel: function(x1, y1, x2, y2, x, y) { - var pointsRel = this.editPointsRel([x1, y1, x2, y2, x, y]); - - this.d = this.d.concat(" c" + pointsRel[0] + " " + pointsRel[1] + - " " + pointsRel[2] + " " + pointsRel[3] + - " " + pointsRel[4] + " " + pointsRel[5] + " "); - }, + }, - /** - * linetoHorizontalAbs - H - * - * @param {Number} x - */ - linetoHorizontalAbs: function(x) { - var pointsAbs = this.editPointsAbs([x, 0]); - - this.d = this.d.concat(" H" + pointsAbs[0] + " "); - }, + /** + * graft() function + * Originally by Sean M. Burke from interglacial.com, altered for usage with + * SVG and namespace (xmlns) support. Be sure you understand xmlns before + * using this funtion, as it creates all grafted elements in the xmlns + * provided by you and all element's attribures in default xmlns. If you + * need to graft elements in a certain xmlns and wish to assign attributes + * in both that and another xmlns, you will need to do stepwise grafting, + * adding non-default attributes yourself or you'll have to enhance this + * function. Latter, I would appreciate: martin???apfelfabrik.de + * @param {Object} namespace The namespace in which + * elements should be grafted. + * @param {Object} parent The element that should contain the grafted + * structure after the function returned. + * @param {Object} t the crafting structure. + * @param {Object} doc the document in which grafting is performed. + */ + graft: function (namespace, parent, t, doc) { + + doc = (doc || (parent && parent.ownerDocument) || document); + var e; + if (t === undefined) { + echo("Can't graft an undefined value"); + } else if (t.constructor == String) { + e = doc.createTextNode(t); + } else { + for (var i = 0; i < t.length; i++) { + if (i === 0 && t[i].constructor == String) { + var snared = t[i].match(/^([a-z][a-z0-9]*)\.([^\s\.]+)$/i); + if (snared) { + e = doc.createElementNS(namespace, snared[1]); + e.setAttributeNS(null, 'class', snared[2]); + continue; + } + snared = t[i].match(/^([a-z][a-z0-9]*)$/i); + if (snared) { + e = doc.createElementNS(namespace, snared[1]); // but no class + continue; + } - /** - * linetoHorizontalRel - h - * - * @param {Number} x - */ - linetoHorizontalRel: function(x) { - var pointsRel = this.editPointsRel([x, 0]); - - this.d = this.d.concat(" h" + pointsRel[0] + " "); - }, + // Otherwise: + e = doc.createElementNS(namespace, "span"); + e.setAttribute(null, "class", "namelessFromLOL"); + } - /** - * linetoAbs - L - * - * @param {Number} x - * @param {Number} y - */ - linetoAbs: function(x, y) { - var pointsAbs = this.editPointsAbs([x, y]); - - this.d = this.d.concat(" L" + pointsAbs[0] + " " + pointsAbs[1] + " "); - }, + if (t[i] === undefined) { + echo("Can't graft an undefined value in a list!"); + } else if (t[i].constructor == String || t[i].constructor == Array) { + this.graft(namespace, e, t[i], doc); + } else if (t[i].constructor == Number) { + this.graft(namespace, e, t[i].toString(), doc); + } else if (t[i].constructor == Object) { + // hash's properties => element's attributes + for (var k in t[i]) { + e.setAttributeNS(null, k, t[i][k]); + } + } else if (t[i].constructor == Boolean) { + this.graft(namespace, e, t[i] ? 'true' : 'false', doc); + } else + throw "Object " + t[i] + " is inscrutable as an graft arglet."; + } + } - /** - * linetoRel - l - * - * @param {Number} x - * @param {Number} y - */ - linetoRel: function(x, y) { - var pointsRel = this.editPointsRel([x, y]); - - this.d = this.d.concat(" l" + pointsRel[0] + " " + pointsRel[1] + " "); - }, + if (parent) parent.appendChild(e); - /** - * movetoAbs - M - * - * @param {Number} x - * @param {Number} y - */ - movetoAbs: function(x, y) { - var pointsAbs = this.editPointsAbs([x, y]); - - this.d = this.d.concat(" M" + pointsAbs[0] + " " + pointsAbs[1] + " "); - }, + return Element.extend(e); // return the topmost created node + }, - /** - * movetoRel - m - * - * @param {Number} x - * @param {Number} y - */ - movetoRel: function(x, y) { - var pointsRel; - if(this.d === "") { - pointsRel = this.editPointsAbs([x, y]); - } else { - pointsRel = this.editPointsRel([x, y]); - } - - this.d = this.d.concat(" m" + pointsRel[0] + " " + pointsRel[1] + " "); - }, + setObject: function (triple) { - /** - * curvetoQuadraticAbs - Q - * - * @param {Number} x1 - * @param {Number} y1 - * @param {Number} x - * @param {Number} y - */ - curvetoQuadraticAbs: function(x1, y1, x, y) { - var pointsAbs = this.editPointsAbs([x1, y1, x, y]); - - this.d = this.d.concat(" Q" + pointsAbs[0] + " " + pointsAbs[1] + " " + - pointsAbs[2] + " " + pointsAbs[3] + " "); - }, + /** + * Erwartungen von Arvid an diese Funktion: + * - Es existiert genau ein triple mit dem Subjekt und Praedikat, + * das uebergeben wurde, und dieses haelt uebergebenes Objekt. + */ - /** - * curvetoQuadraticRel - q - * - * @param {Number} x1 - * @param {Number} y1 - * @param {Number} x - * @param {Number} y - */ - curvetoQuadraticRel: function(x1, y1, x, y) { - var pointsRel = this.editPointsRel([x1, y1, x, y]); - - this.d = this.d.concat(" q" + pointsRel[0] + " " + pointsRel[1] + " " + - pointsRel[2] + " " + pointsRel[3] + " "); - }, + var triples = DataManager.query( + triple.subject, + triple.predicate, + undefined + ); - /** - * curvetoCubicSmoothAbs - S - * - * @param {Number} x2 - * @param {Number} y2 - * @param {Number} x - * @param {Number} y - */ - curvetoCubicSmoothAbs: function(x2, y2, x, y) { - var pointsAbs = this.editPointsAbs([x2, y2, x, y]); - - this.d = this.d.concat(" S" + pointsAbs[0] + " " + pointsAbs[1] + " " + - pointsAbs[2] + " " + pointsAbs[3] + " "); - }, + DataManager.removeTriples(triples); - /** - * curvetoCubicSmoothRel - s - * - * @param {Number} x2 - * @param {Number} y2 - * @param {Number} x - * @param {Number} y - */ - curvetoCubicSmoothRel: function(x2, y2, x, y) { - var pointsRel = this.editPointsRel([x2, y2, x, y]); - - this.d = this.d.concat(" s" + pointsRel[0] + " " + pointsRel[1] + " " + - pointsRel[2] + " " + pointsRel[3] + " "); - }, + DataManager.addTriple(triple); - /** - * curvetoQuadraticSmoothAbs - T - * - * @param {Number} x - * @param {Number} y - */ - curvetoQuadraticSmoothAbs: function(x, y) { - var pointsAbs = this.editPointsAbs([x, y]); - - this.d = this.d.concat(" T" + pointsAbs[0] + " " + pointsAbs[1] + " "); - }, + return true; + }, - /** - * curvetoQuadraticSmoothRel - t - * - * @param {Number} x - * @param {Number} y - */ - curvetoQuadraticSmoothRel: function(x, y) { - var pointsRel = this.editPointsRel([x, y]); - - this.d = this.d.concat(" t" + pointsRel[0] + " " + pointsRel[1] + " "); - }, + query: function (subject, predicate, object) { - /** - * linetoVerticalAbs - V - * - * @param {Number} y - */ - linetoVerticalAbs: function(y) { - var pointsAbs = this.editPointsAbs([0, y]); - - this.d = this.d.concat(" V" + pointsAbs[1] + " "); - }, + /* + * Typical triple. + * {value: subject, type: subjectType}, + * {prefix: schema.prefix, name: property}, + * {value: object, type: objectType}); + */ - /** - * linetoVerticalRel - v - * - * @param {Number} y - */ - linetoVerticalRel: function(y) { - var pointsRel = this.editPointsRel([0, y]); - - this.d = this.d.concat(" v" + pointsRel[1] + " "); - }, + return DataManager._triples.select(function (triple) { - /** - * closePath - z or Z - */ - closePath: function() { - this.d = this.d.concat(" z"); - } + var select = ((subject) ? + (triple.subject.type == subject.type) && + (triple.subject.value == subject.value) : true); + if (predicate) { + select = select && ((predicate.prefix) ? + (triple.predicate.prefix == predicate.prefix) : true); + select = select && ((predicate.name) ? + (triple.predicate.name == predicate.name) : true); + } + select = select && ((object) ? + (triple.object.type == object.type) && + (triple.object.value == object.value) : true); + return select; + }); + } +} -});/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ +Kickstart.register(DataManager.init); -/** - * Init namespaces - */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} -if(!ORYX.Core.SVG) {ORYX.Core.SVG = {};} +function assert(expr, m) { + if (!expr) throw m; +}; +function DMCommand(action, triple) { -/** - * MinMaxPathHandler - * - * Determine the minimum and maximum of a SVG path's absolute coordinates. - * For relative coordinates the absolute value is computed for consideration. - * The values are stored in attributes minX, minY, maxX, and maxY. - * - * @constructor - */ -ORYX.Core.SVG.MinMaxPathHandler = Clazz.extend({ - - construct: function() { - arguments.callee.$.construct.apply(this, arguments); - - this.minX = undefined; - this.minY = undefined; - this.maxX = undefined; - this.maxY = undefined; - - this._lastAbsX = undefined; - this._lastAbsY = undefined; - }, + // store action and triple. + this.action = action; + this.triple = triple; - /** - * Store minimal and maximal coordinates of passed points to attributes minX, maxX, minY, maxY - * - * @param {Array} points Array of absolutePoints - */ - calculateMinMax: function(points) { - if(points instanceof Array) { - var x, y; - for(var i = 0; i < points.length; i++) { - x = parseFloat(points[i]); - i++; - y = parseFloat(points[i]); - - this.minX = (this.minX !== undefined) ? Math.min(this.minX, x) : x; - this.maxX = (this.maxX !== undefined) ? Math.max(this.maxX, x) : x; - this.minY = (this.minY !== undefined) ? Math.min(this.minY, y) : y; - this.maxY = (this.maxY !== undefined) ? Math.max(this.maxY, y) : y; - - this._lastAbsX = x; - this._lastAbsY = y; - } - } else { - //TODO error - } - }, + this.toString = function () { + return 'Command(' + action + ', ' + triple + ')'; + }; +} - /** - * arcAbs - A - * - * @param {Number} rx - * @param {Number} ry - * @param {Number} xAxisRotation - * @param {Boolean} largeArcFlag - * @param {Boolean} sweepFlag - * @param {Number} x - * @param {Number} y - */ - arcAbs: function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) { - this.calculateMinMax([x, y]); - }, +function DMCommandHandler(nextHandler) { - /** - * arcRel - a - * - * @param {Number} rx - * @param {Number} ry - * @param {Number} xAxisRotation - * @param {Boolean} largeArcFlag - * @param {Boolean} sweepFlag - * @param {Number} x - * @param {Number} y - */ - arcRel: function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) { - this.calculateMinMax([this._lastAbsX + x, this._lastAbsY + y]); - }, + /** + * Private method to set the next handler in the Chain of Responsibility + * (see http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern for + * details). + * @param {DMCommandHandler} handler The handler that is next in the chain. + */ + this.__setNext = function (handler) { + var _next = this.__next; + this.__next = nextHandler; + return _next ? _next : true; + }; + this.__setNext(nextHandler); - /** - * curvetoCubicAbs - C - * - * @param {Number} x1 - * @param {Number} y1 - * @param {Number} x2 - * @param {Number} y2 - * @param {Number} x - * @param {Number} y - */ - curvetoCubicAbs: function(x1, y1, x2, y2, x, y) { - this.calculateMinMax([x1, y1, x2, y2, x, y]); - }, + /** + * Invokes the next handler. If there is no next handler, this method + * returns false, otherwise it forwards the result of the handling. + * @param {Object} command The command object to be processed. + */ + this.__invokeNext = function (command) { + return this.__next ? this.__next.handle(command) : false; + }; - /** - * curvetoCubicRel - c - * - * @param {Number} x1 - * @param {Number} y1 - * @param {Number} x2 - * @param {Number} y2 - * @param {Number} x - * @param {Number} y - */ - curvetoCubicRel: function(x1, y1, x2, y2, x, y) { - this.calculateMinMax([this._lastAbsX + x1, this._lastAbsY + y1, - this._lastAbsX + x2, this._lastAbsY + y2, - this._lastAbsX + x, this._lastAbsY + y]); - }, + /** + * Handles a command. The abstract method process() is called with the + * command object that has been passed. If the process method catches the + * command (returns true on completion), the handle() method returns true. + * If the process() method doesn't catch the command, the next handler will + * be invoked. + * @param {Object} command The command object to be processed. + */ + this.handle = function (command) { + return this.process(command) ? true : this.__invokeNext(command); + } - /** - * linetoHorizontalAbs - H - * - * @param {Number} x - */ - linetoHorizontalAbs: function(x) { - this.calculateMinMax([x, this._lastAbsY]); - }, + /** + * Empty process() method returning false. If javascript knew abstract + * class members, this would be one. + * @param {Object} command The command object to process. + */ + this.process = function (command) { + return false; + }; +}; - /** - * linetoHorizontalRel - h - * - * @param {Number} x - */ - linetoHorizontalRel: function(x) { - this.calculateMinMax([this._lastAbsX + x, this._lastAbsY]); - }, +/** + * This Handler manages the addition and the removal of meta elements in the + * head of the document. + * @param {DMCommandHandler} next The handler that is next in the chain. + */ +function MetaTagHandler(next) { - /** - * linetoAbs - L - * - * @param {Number} x - * @param {Number} y - */ - linetoAbs: function(x, y) { - this.calculateMinMax([x, y]); - }, + DMCommandHandler.apply(this, [next]); + this.process = function (command) { - /** - * linetoRel - l - * - * @param {Number} x - * @param {Number} y - */ - linetoRel: function(x, y) { - this.calculateMinMax([this._lastAbsX + x, this._lastAbsY + y]); - }, + with (command.triple) { - /** - * movetoAbs - M - * - * @param {Number} x - * @param {Number} y - */ - movetoAbs: function(x, y) { - this.calculateMinMax([x, y]); - }, + /* assert prerequisites */ + if (!( + (subject instanceof ERDF.Resource) && + (subject.isCurrentDocument()) && + (object instanceof ERDF.Literal) + )) return false; + } - /** - * movetoRel - m - * - * @param {Number} x - * @param {Number} y - */ - movetoRel: function(x, y) { - if(this._lastAbsX && this._lastAbsY) { - this.calculateMinMax([this._lastAbsX + x, this._lastAbsY + y]); - } else { - this.calculateMinMax([x, y]); - } - }, + }; +}; - /** - * curvetoQuadraticAbs - Q - * - * @param {Number} x1 - * @param {Number} y1 - * @param {Number} x - * @param {Number} y - */ - curvetoQuadraticAbs: function(x1, y1, x, y) { - this.calculateMinMax([x1, y1, x, y]); - }, +var chain = new MetaTagHandler(); +var command = new DMCommand(TRIPLE_ADD, new ERDF.Triple( + new ERDF.Resource(''), + 'rdf:tool', + new ERDF.Literal('') +)); - /** - * curvetoQuadraticRel - q - * - * @param {Number} x1 - * @param {Number} y1 - * @param {Number} x - * @param {Number} y - */ - curvetoQuadraticRel: function(x1, y1, x, y) { - this.calculateMinMax([this._lastAbsX + x1, this._lastAbsY + y1, this._lastAbsX + x, this._lastAbsY + y]); - }, +/* +if(chain.handle(command)) + alert('Handled!'); +*/ - /** - * curvetoCubicSmoothAbs - S - * - * @param {Number} x2 - * @param {Number} y2 - * @param {Number} x - * @param {Number} y - */ - curvetoCubicSmoothAbs: function(x2, y2, x, y) { - this.calculateMinMax([x2, y2, x, y]); - }, +ResourceManager = { - /** - * curvetoCubicSmoothRel - s - * - * @param {Number} x2 - * @param {Number} y2 - * @param {Number} x - * @param {Number} y - */ - curvetoCubicSmoothRel: function(x2, y2, x, y) { - this.calculateMinMax([this._lastAbsX + x2, this._lastAbsY + y2, this._lastAbsX + x, this._lastAbsY + y]); - }, + __corrupt: false, + __latelyCreatedResource: undefined, + __listeners: $H(), + __token: 1, - /** - * curvetoQuadraticSmoothAbs - T - * - * @param {Number} x - * @param {Number} y - */ - curvetoQuadraticSmoothAbs: function(x, y) { - this.calculateMinMax([x, y]); - }, + addListener: function (listener, mask) { - /** - * curvetoQuadraticSmoothRel - t - * - * @param {Number} x - * @param {Number} y - */ - curvetoQuadraticSmoothRel: function(x, y) { - this.calculateMinMax([this._lastAbsX + x, this._lastAbsY + y]); - }, + if (!(listener instanceof Function)) + throw 'Resource event listener is not a function!'; + if (!(mask)) + throw 'Invalid mask for resource event listener registration.'; - /** - * linetoVerticalAbs - V - * - * @param {Number} y - */ - linetoVerticalAbs: function(y) { - this.calculateMinMax([this._lastAbsX, y]); - }, + // construct controller and token. + var controller = {listener: listener, mask: mask}; + var token = ResourceManager.__token++; - /** - * linetoVerticalRel - v - * - * @param {Number} y - */ - linetoVerticalRel: function(y) { - this.calculateMinMax([this._lastAbsX, this._lastAbsY + y]); - }, + // add new listener. + ResourceManager.__listeners[token] = controller; - /** - * closePath - z or Z - */ - closePath: function() { - return;// do nothing - } + // return the token generated. + return token; + }, -});/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + removeListener: function (token) { -/** - * Init namespaces - */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} -if(!ORYX.Core.SVG) {ORYX.Core.SVG = {};} + // remove the listener with the token and return it. + return ResourceManager.__listners.remove(token); + }, + __Event: function (action, resourceId) { + this.action = action; + this.resourceId = resourceId; + }, -/** - * PathHandler - * - * Determine absolute points of a SVG path. The coordinates are stored - * sequentially in the attribute points (x-coordinates at even indices, - * y-coordinates at odd indices). - * - * @constructor - */ -ORYX.Core.SVG.PointsPathHandler = Clazz.extend({ - - construct: function() { - arguments.callee.$.construct.apply(this, arguments); - - this.points = []; - - this._lastAbsX = undefined; - this._lastAbsY = undefined; - }, - - /** - * addPoints - * - * @param {Array} points Array of absolutePoints - */ - addPoints: function(points) { - if(points instanceof Array) { - var x, y; - for(var i = 0; i < points.length; i++) { - x = parseFloat(points[i]); - i++; - y = parseFloat(points[i]); - - this.points.push(x); - this.points.push(y); - //this.points.push({x:x, y:y}); - - this._lastAbsX = x; - this._lastAbsY = y; - } - } else { - //TODO error - } - }, - - /** - * arcAbs - A - * - * @param {Number} rx - * @param {Number} ry - * @param {Number} xAxisRotation - * @param {Boolean} largeArcFlag - * @param {Boolean} sweepFlag - * @param {Number} x - * @param {Number} y - */ - arcAbs: function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) { - this.addPoints([x, y]); - }, + __dispatchEvent: function (event) { - /** - * arcRel - a - * - * @param {Number} rx - * @param {Number} ry - * @param {Number} xAxisRotation - * @param {Boolean} largeArcFlag - * @param {Boolean} sweepFlag - * @param {Number} x - * @param {Number} y - */ - arcRel: function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) { - this.addPoints([this._lastAbsX + x, this._lastAbsY + y]); - }, + // get all listeners. for each listener, ... + ResourceManager.__listeners.values().each(function (controller) { - /** - * curvetoCubicAbs - C - * - * @param {Number} x1 - * @param {Number} y1 - * @param {Number} x2 - * @param {Number} y2 - * @param {Number} x - * @param {Number} y - */ - curvetoCubicAbs: function(x1, y1, x2, y2, x, y) { - this.addPoints([x, y]); - }, + // .. if listener subscribed to this type of event ... + if (event.action & controller.mask) + return controller.listener(event); + }); + }, - /** - * curvetoCubicRel - c - * - * @param {Number} x1 - * @param {Number} y1 - * @param {Number} x2 - * @param {Number} y2 - * @param {Number} x - * @param {Number} y - */ - curvetoCubicRel: function(x1, y1, x2, y2, x, y) { - this.addPoints([this._lastAbsX + x, this._lastAbsY + y]); - }, + getResource: function (id) { - /** - * linetoHorizontalAbs - H - * - * @param {Number} x - */ - linetoHorizontalAbs: function(x) { - this.addPoints([x, this._lastAbsY]); - }, + // get all possible resources for this. + id = ERDF.__stripHashes(id); + var resources = DataManager.query( + new ERDF.Resource('#' + id), + {prefix: 'raziel', name: 'entry'}, + undefined + ); - /** - * linetoHorizontalRel - h - * - * @param {Number} x - */ - linetoHorizontalRel: function(x) { - this.addPoints([this._lastAbsX + x, this._lastAbsY]); - }, + // check for consistency. + if ((resources.length == 1) && (resources[0].object.isResource())) { + var entryUrl = resources[0].object.value; + return new ResourceManager.__Resource(id, entryUrl); + } - /** - * linetoAbs - L - * - * @param {Number} x - * @param {Number} y - */ - linetoAbs: function(x, y) { - this.addPoints([x, y]); - }, + // else throw an error message. + throw ('Resource with id ' + id + ' not recognized as such. ' + + ((resources.length > 1) ? + ' There is more than one raziel:entry URL.' : + ' There is no raziel:entry URL.')); - /** - * linetoRel - l - * - * @param {Number} x - * @param {Number} y - */ - linetoRel: function(x, y) { - this.addPoints([this._lastAbsX + x, this._lastAbsY + y]); - }, + return false; + }, - /** - * movetoAbs - M - * - * @param {Number} x - * @param {Number} y - */ - movetoAbs: function(x, y) { - this.addPoints([x, y]); - }, + __createResource: function (alternativeDiv) { - /** - * movetoRel - m - * - * @param {Number} x - * @param {Number} y - */ - movetoRel: function(x, y) { - if(this._lastAbsX && this._lastAbsY) { - this.addPoints([this._lastAbsX + x, this._lastAbsY + y]); - } else { - this.addPoints([x, y]); - } - }, + var collectionUrls = DataManager.query( + new ERDF.Resource(''), + // TODO This will become raziel:collection in near future. + {prefix: 'raziel', name: 'collection'}, + undefined + ); - /** - * curvetoQuadraticAbs - Q - * - * @param {Number} x1 - * @param {Number} y1 - * @param {Number} x - * @param {Number} y - */ - curvetoQuadraticAbs: function(x1, y1, x, y) { - this.addPoints([x, y]); - }, + // check for consistency. - /** - * curvetoQuadraticRel - q - * - * @param {Number} x1 - * @param {Number} y1 - * @param {Number} x - * @param {Number} y - */ - curvetoQuadraticRel: function(x1, y1, x, y) { - this.addPoints([this._lastAbsX + x, this._lastAbsY + y]); - }, + if ((collectionUrls.length == 1) && + (collectionUrls[0].object.isResource())) { - /** - * curvetoCubicSmoothAbs - S - * - * @param {Number} x2 - * @param {Number} y2 - * @param {Number} x - * @param {Number} y - */ - curvetoCubicSmoothAbs: function(x2, y2, x, y) { - this.addPoints([x, y]); - }, + // get the collection url. - /** - * curvetoCubicSmoothRel - s - * - * @param {Number} x2 - * @param {Number} y2 - * @param {Number} x - * @param {Number} y - */ - curvetoCubicSmoothRel: function(x2, y2, x, y) { - this.addPoints([this._lastAbsX + x, this._lastAbsY + y]); - }, + var collectionUrl = collectionUrls[0].object.value; + var resource = undefined; - /** - * curvetoQuadraticSmoothAbs - T - * - * @param {Number} x - * @param {Number} y - */ - curvetoQuadraticSmoothAbs: function(x, y) { - this.addPoints([x, y]); - }, + // if there is an old id, serialize the dummy div from there, + // otherwise create a dummy div on the fly. - /** - * curvetoQuadraticSmoothRel - t - * - * @param {Number} x - * @param {Number} y - */ - curvetoQuadraticSmoothRel: function(x, y) { - this.addPoints([this._lastAbsX + x, this._lastAbsY + y]); - }, + var serialization = alternativeDiv ? alternativeDiv : + '
'; - /** - * linetoVerticalAbs - V - * - * @param {Number} y - */ - linetoVerticalAbs: function(y) { - this.addPoints([this._lastAbsX, y]); - }, + ResourceManager.__request( + 'POST', collectionUrl, serialization, - /** - * linetoVerticalRel - v - * - * @param {Number} y - */ - linetoVerticalRel: function(y) { - this.addPoints([this._lastAbsX, this._lastAbsY + y]); - }, + // on success + function () { - /** - * closePath - z or Z - */ - closePath: function() { - return;// do nothing - } + // get div and id that have been generated by the server. -});/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + var response = (this.responseXML); + var div = response.childNodes[0]; + var id = div.getAttribute('id'); -/** - * - * Config variables - */ -NAMESPACE_ORYX = "http://www.b3mn.org/oryx"; -NAMESPACE_SVG = "http://www.w3.org/2000/svg/"; + // store div in DOM + if (!$$('.' + PROCESSDATA_REF)[0]) + DataManager.graft(XMLNS.XHTML, + document.getElementsByTagNameNS(XMLNS.XHTML, 'body').item(0), ['div', { + 'class': PROCESSDATA_REF, + 'style': 'display:none;' + }]); -/** - * @classDescription This class wraps the manipulation of a SVG marker. - * @namespace ORYX.Core.SVG - * uses Inheritance (Clazz) - * uses Prototype 1.5.0 - * - */ + $$('.' + PROCESSDATA_REF)[0].appendChild(div.cloneNode(true)); -/** - * Init package - */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} -if(!ORYX.Core.SVG) {ORYX.Core.SVG = {};} + // parse local erdf data once more. -ORYX.Core.SVG.SVGMarker = Clazz.extend({ + DataManager.__synclocal(); - /** - * Constructor - * @param markerElement {SVGMarkerElement} - */ - construct: function(markerElement) { - arguments.callee.$.construct.apply(this, arguments); - - this.id = undefined; - this.element = markerElement; - this.refX = undefined; - this.refY = undefined; - this.markerWidth = undefined; - this.markerHeight = undefined; - this.oldRefX = undefined; - this.oldRefY = undefined; - this.oldMarkerWidth = undefined; - this.oldMarkerHeight = undefined; - this.optional = false; - this.enabled = true; - this.minimumLength = undefined; - this.resize = false; - - this.svgShapes = []; - - this._init(); //initialisation of all the properties declared above. - }, + // get new resource object. - /** - * Initializes the values that are defined in the constructor. - */ - _init: function() { - //check if this.element is a SVGMarkerElement - if(!( this.element == "[object SVGMarkerElement]")) { - throw "SVGMarker: Argument is not an instance of SVGMarkerElement."; - } + resource = new ResourceManager.getResource(id); - this.id = this.element.getAttributeNS(null, "id"); - - //init svg marker attributes - var refXValue = this.element.getAttributeNS(null, "refX"); - if(refXValue) { - this.refX = parseFloat(refXValue); - } else { - this.refX = 0; - } - var refYValue = this.element.getAttributeNS(null, "refY"); - if(refYValue) { - this.refY = parseFloat(refYValue); - } else { - this.refY = 0; - } - var markerWidthValue = this.element.getAttributeNS(null, "markerWidth"); - if(markerWidthValue) { - this.markerWidth = parseFloat(markerWidthValue); - } else { - this.markerWidth = 3; - } - var markerHeightValue = this.element.getAttributeNS(null, "markerHeight"); - if(markerHeightValue) { - this.markerHeight = parseFloat(markerHeightValue); - } else { - this.markerHeight = 3; - } + // set up an action informing of the creation. - this.oldRefX = this.refX; - this.oldRefY = this.refY; - this.oldMarkerWidth = this.markerWidth; - this.oldMarkerHeight = this.markerHeight; + ResourceManager.__resourceActionSucceeded( + this, RESOURCE_CREATED, undefined); + }, - //init oryx attributes - var optionalAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "optional"); - if(optionalAttr) { - optionalAttr = optionalAttr.strip(); - this.optional = (optionalAttr.toLowerCase() === "yes"); - } else { - this.optional = false; - } + function () { + ResourceManager.__resourceActionFailed( + this, RESOURCE_CREATED, undefined); + }, + false + ); - var enabledAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "enabled"); - if(enabledAttr) { - enabledAttr = enabledAttr.strip(); - this.enabled = !(enabledAttr.toLowerCase() === "no"); - } else { - this.enabled = true; - } + return resource; + } - var minLengthAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "minimumLength"); - if(minLengthAttr) { - this.minimumLength = parseFloat(minLengthAttr); - } + // else + throw 'Could not create resource! raziel:collection URL is missing!'; + return false; - var resizeAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "resize"); - if(resizeAttr) { - resizeAttr = resizeAttr.strip(); - this.resize = (resizeAttr.toLowerCase() === "yes"); - } else { - this.resize = false; - } + }, - //init SVGShape objects - //this.svgShapes = this._getSVGShapes(this.element); - }, + __Resource: function (id, url) { - /** - * - */ - _getSVGShapes: function(svgElement) { - if(svgElement.hasChildNodes) { - var svgShapes = []; - var me = this; - $A(svgElement.childNodes).each(function(svgChild) { - try { - var svgShape = new ORYX.Core.SVG.SVGShape(svgChild); - svgShapes.push(svgShape); - } catch (e) { - svgShapes = svgShapes.concat(me._getSVGShapes(svgChild)); - } - }); - return svgShapes; - } - }, + this.__id = id; + this.__url = url; - /** - * Writes the changed values into the SVG marker. - */ - update: function() { - //TODO mache marker resizebar!!! aber erst wenn der rest der connectingshape funzt! + /* + * Process URL is no longer needed to refer to the shape element on the + * canvas. AReSS uses the id's to gather information on fireing + * behaviour now. + */ -// //update marker attributes -// if(this.refX != this.oldRefX) { -// this.element.setAttributeNS(null, "refX", this.refX); -// } -// if(this.refY != this.oldRefY) { -// this.element.setAttributeNS(null, "refY", this.refY); -// } -// if(this.markerWidth != this.oldMarkerWidth) { -// this.element.setAttributeNS(null, "markerWidth", this.markerWidth); -// } -// if(this.markerHeight != this.oldMarkerHeight) { -// this.element.setAttributeNS(null, "markerHeight", this.markerHeight); -// } +// // find the process url. +// var processUrl = undefined; // -// //update SVGShape objects -// var widthDelta = this.markerWidth / this.oldMarkerWidth; -// var heightDelta = this.markerHeight / this.oldMarkerHeight; -// if(widthDelta != 1 && heightDelta != 1) { -// this.svgShapes.each(function(svgShape) { +// var urls = DataManager.query( +// new ERDF.Resource('#'+this.__id), +// {prefix: 'raziel', name: 'process'}, +// undefined +// ); // -// }); +// if(urls.length == 0) { throw 'The resource with the id ' +id+ ' has no process url.'}; +// +// urls.each( function(triple) { +// +// // if there are more urls, use the last one. +// processUrl = triple.object.value; +// }); +// +// this.__processUrl = processUrl; +// +// // convenience function for getting the process url. +// this.processUrl = function() { +// return this.__processUrl; // } - //update old values to prepare the next update - this.oldRefX = this.refX; - this.oldRefY = this.refY; - this.oldMarkerWidth = this.markerWidth; - this.oldMarkerHeight = this.markerHeight; - }, - - toString: function() { return (this.element) ? "SVGMarker " + this.element.id : "SVGMarker " + this.element;} - });/* + + // convenience finction for getting the id. + this.id = function () { + return this.__id; + } + + // convenience finction for getting the entry url. + this.url = function () { + return this.__url; + } + + this.reload = function () { + var _url = this.__url; + var _id = this.__id; + ResourceManager.__request( + 'GET', _url, null, + function () { + ResourceManager.__resourceActionSucceeded( + this, RESOURCE_RELOADED, _id); + }, + function () { + ResourceManager.__resourceActionFailed( + this, RESURCE_RELOADED, _id); + }, + USE_ASYNCHRONOUS_REQUESTS + ); + }; + + this.save = function (synchronize) { + var _url = this.__url; + var _id = this.__id; + data = DataManager.serialize($(_id)); + ResourceManager.__request( + 'PUT', _url, data, + function () { + ResourceManager.__resourceActionSucceeded( + this, synchronize ? RESOURCE_SAVED | RESOURCE_SYNCHRONIZED : RESOURCE_SAVED, _id); + }, + function () { + ResourceManager.__resourceActionFailed( + this, synchronize ? RESOURCE_SAVED | RESOURCE_SYNCHRONIZED : RESOURCE.SAVED, _id); + }, + USE_ASYNCHRONOUS_REQUESTS + ); + }; + + this.remove = function () { + var _url = this.__url; + var _id = this.__id; + ResourceManager.__request( + 'DELETE', _url, null, + function () { + ResourceManager.__resourceActionSucceeded( + this, RESOURCE_REMOVED, _id); + }, + function () { + ResourceManager.__resourceActionFailed( + this, RESOURCE_REMOVED, _id); + }, + USE_ASYNCHRONOUS_REQUESTS + ); + }; + }, + + request: function (url, requestOptions) { + + var options = { + method: 'get', + asynchronous: true, + parameters: {} + }; + + Object.extend(options, requestOptions || {}); + + var params = Hash.toQueryString(options.parameters); + if (params) + url += (url.include('?') ? '&' : '?') + params; + + return ResourceManager.__request( + options.method, + url, + options.data, + (options.onSuccess instanceof Function ? function () { + options.onSuccess(this); + } : undefined), + (options.onFailure instanceof Function ? function () { + options.onFailure(this); + } : undefined), + options.asynchronous && USE_ASYNCHRONOUS_REQUESTS, + options.headers); + }, + + __request: function (method, url, data, success, error, async, headers) { + + // get a request object + var httpRequest = Try.these( + /* do the Mozilla/Safari/Opera stuff */ + function () { + return new XMLHttpRequest(); + }, + + /* do the IE stuff */ + function () { + return new ActiveXObject("Msxml2.XMLHTTP"); + }, + function () { + return new ActiveXObject("Microsoft.XMLHTTP") + } + ); + + // if there is no request object ... + if (!httpRequest) { + if (!this.__corrupt) + throw 'This browser does not provide any AJAX functionality. You will not be able to use the software provided with the page you are viewing. Please consider installing appropriate extensions.'; + this.__corrupt = true; + return false; + } + + if (success instanceof Function) + httpRequest.onload = success; + if (error instanceof Function) { + httpRequest.onerror = error; + } + + var h = $H(headers) + h.keys().each(function (key) { + + httpRequest.setRequestHeader(key, h[key]); + }); + + try { + + if (SHOW_DEBUG_ALERTS_WHEN_SAVING) + + alert(method + ' ' + url + '\n' + + SHOW_EXTENDED_DEBUG_INFORMATION ? data : ''); + + // TODO Remove synchronous calls to the server as soon as xenodot + // handles asynchronous requests without failure. + httpRequest.open(method, url, !async ? false : true); + httpRequest.send(data); + + } catch (e) { + return false; + } + return true; + }, + + __resourceActionSucceeded: function (transport, action, id) { + + var status = transport.status; + var response = transport.responseText; + + if (SHOW_DEBUG_ALERTS_WHEN_SAVING) + + alert(status + ' ' + url + '\n' + + SHOW_EXTENDED_DEBUG_INFORMATION ? data : ''); + + // if the status code is not in 2xx, throw an error. + if (status >= 300) + throw 'The server responded with an error: ' + status + '\n' + (SHOW_EXTENDED_DEBUG_INFORMATION ? +data : 'If you need additional information here, including the data sent by the server, consider setting SHOW_EXTENDED_DEBUG_INFORMATION to true.'); + + switch (action) { + + case RESOURCE_REMOVED: + + // get div and id + var response = (transport.responseXML); + var div = response.childNodes[0]; + var id = div.getAttribute('id'); + + // remove the resource from DOM + var localDiv = document.getElementById(id); + localDiv.parentNode.removeChild(localDiv); + break; + + case RESOURCE_CREATED: + + // nothing remains to be done. + break; + + case RESOURCE_SAVED | RESOURCE_SYNCHRONIZED: + + DataManager.__synclocal(); + + case RESOURCE_SAVED: + + // nothing remains to be done. + break; + + case RESOURCE_RELOADED: + + // get div and id + var response = (transport.responseXML); + var div = response.childNodes[0]; + var id = div.getAttribute('id'); + + // remove the local resource representation from DOM + var localDiv = document.getElementById(id) + localDiv.parentNode.removeChild(localDiv); + + // store div in DOM + if (!$$(PROCESSDATA_REF)[0]) + DataManager.graft(XMLNS.XHTML, + document.getElementsByTagNameNS(XMLNS.XHTML, 'body').item(0), ['div', { + 'class': PROCESSDATA_REF, + 'style': 'display:none;' + }]); + + $$(PROCESSDATA_REF)[0].appendChild(div.cloneNode(true)); + DataManager.__synclocal(); + break; + + default: + DataManager.__synclocal(); + + } + + // dispatch to all listeners ... + ResourceManager.__dispatchEvent( + // ... an event describing the change that happened here. + new ResourceManager.__Event(action, id) + ); + }, + + __resourceActionFailed: function (transport, action, id) { + throw "Fatal: Resource action failed. There is something horribly " + + "wrong with either the server, the transport protocol or your " + + "online status. Sure you're online?"; + } +}/* * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. * License rights for this program may be obtained from Alfresco Software, Ltd. * pursuant to a written agreement and any use of this program without such an @@ -3547,3052 +1764,1121 @@ ORYX.Core.SVG.SVGMarker = Clazz.extend({ */ /** - * - * Config variables + * The super class for all classes in ORYX. Adds some OOP feeling to javascript. + * See article "Object Oriented Super Class Method Calling with JavaScript" on + * http://truecode.blogspot.com/2006/08/object-oriented-super-class-method.html + * for a documentation on this. Fairly good article that points out errors in + * Douglas Crockford's inheritance and super method calling approach. + * Worth reading. + * @class Clazz */ -NAMESPACE_ORYX = "http://www.b3mn.org/oryx"; -NAMESPACE_SVG = "http://www.w3.org/2000/svg/"; +var Clazz = function () { +}; /** - * @classDescription This class wraps the manipulation of a SVG basic shape or a path. - * @namespace ORYX.Core.SVG - * uses Inheritance (Clazz) - * uses Prototype 1.5.0 - * uses PathParser by Kevin Lindsey (http://kevlindev.com/) - * uses MinMaxPathHandler - * uses EditPathHandler - * + * Empty constructor. + * @methodOf Clazz.prototype */ +Clazz.prototype.construct = function () { +}; -//init package -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} -if(!ORYX.Core.SVG) {ORYX.Core.SVG = {};} - -ORYX.Core.SVG.SVGShape = Clazz.extend({ - - /** - * Constructor - * @param svgElem {SVGElement} An SVGElement that is a basic shape or a path. - */ - construct: function(svgElem) { - arguments.callee.$.construct.apply(this, arguments); - - this.type; - this.element = svgElem; - this.x = undefined; - this.y = undefined; - this.width = undefined; - this.height = undefined; - this.oldX = undefined; - this.oldY = undefined; - this.oldWidth = undefined; - this.oldHeight = undefined; - this.radiusX = undefined; - this.radiusY = undefined; - this.isHorizontallyResizable = false; - this.isVerticallyResizable = false; - //this.anchors = []; - this.anchorLeft = false; - this.anchorRight = false; - this.anchorTop = false; - this.anchorBottom = false; - - //attributes of path elements of edge objects - this.allowDockers = true; - this.resizeMarkerMid = false; - - this.editPathParser; - this.editPathHandler; - - this.init(); //initialisation of all the properties declared above. - }, - - /** - * Initializes the values that are defined in the constructor. - */ - init: function() { - - /**initialize position and size*/ - if(ORYX.Editor.checkClassType(this.element, SVGRectElement) || ORYX.Editor.checkClassType(this.element, SVGImageElement)) { - this.type = "Rect"; - - var xAttr = this.element.getAttributeNS(null, "x"); - if(xAttr) { - this.oldX = parseFloat(xAttr); - } else { - throw "Missing attribute in element " + this.element; - } - var yAttr = this.element.getAttributeNS(null, "y"); - if(yAttr) { - this.oldY = parseFloat(yAttr); - } else { - throw "Missing attribute in element " + this.element; - } - var widthAttr = this.element.getAttributeNS(null, "width"); - if(widthAttr) { - this.oldWidth = parseFloat(widthAttr); - } else { - throw "Missing attribute in element " + this.element; - } - var heightAttr = this.element.getAttributeNS(null, "height"); - if(heightAttr) { - this.oldHeight = parseFloat(heightAttr); - } else { - throw "Missing attribute in element " + this.element; - } +/** + * Can be used to build up inheritances of classes. + * @example + * var MyClass = Clazz.extend({ + * construct: function(myParam){ + * // Do sth. + * } + * }); + * var MySubClass = MyClass.extend({ + * construct: function(myParam){ + * // Use this to call constructor of super class + * arguments.callee.$.construct.apply(this, arguments); + * // Do sth. + * } + * }); + * @param {Object} def The definition of the new class. + */ +Clazz.extend = function (def) { + var classDef = function () { + if (arguments[0] !== Clazz) { + this.construct.apply(this, arguments); + } + }; - } else if(ORYX.Editor.checkClassType(this.element, SVGCircleElement)) { - this.type = "Circle"; - - var cx = undefined; - var cy = undefined; - //var r = undefined; + var proto = new this(Clazz); + var superClass = this.prototype; - var cxAttr = this.element.getAttributeNS(null, "cx"); - if(cxAttr) { - cx = parseFloat(cxAttr); - } else { - throw "Missing attribute in element " + this.element; - } - var cyAttr = this.element.getAttributeNS(null, "cy"); - if(cyAttr) { - cy = parseFloat(cyAttr); - } else { - throw "Missing attribute in element " + this.element; - } - var rAttr = this.element.getAttributeNS(null, "r"); - if(rAttr) { - //r = parseFloat(rAttr); - this.radiusX = parseFloat(rAttr); - } else { - throw "Missing attribute in element " + this.element; - } - this.oldX = cx - this.radiusX; - this.oldY = cy - this.radiusX; - this.oldWidth = 2*this.radiusX; - this.oldHeight = 2*this.radiusX; - - } else if(ORYX.Editor.checkClassType(this.element, SVGEllipseElement)) { - this.type = "Ellipse"; - - var cx = undefined; - var cy = undefined; - //var rx = undefined; - //var ry = undefined; - var cxAttr = this.element.getAttributeNS(null, "cx"); - if(cxAttr) { - cx = parseFloat(cxAttr); - } else { - throw "Missing attribute in element " + this.element; - } - var cyAttr = this.element.getAttributeNS(null, "cy"); - if(cyAttr) { - cy = parseFloat(cyAttr); - } else { - throw "Missing attribute in element " + this.element; - } - var rxAttr = this.element.getAttributeNS(null, "rx"); - if(rxAttr) { - this.radiusX = parseFloat(rxAttr); - } else { - throw "Missing attribute in element " + this.element; - } - var ryAttr = this.element.getAttributeNS(null, "ry"); - if(ryAttr) { - this.radiusY = parseFloat(ryAttr); - } else { - throw "Missing attribute in element " + this.element; - } - this.oldX = cx - this.radiusX; - this.oldY = cy - this.radiusY; - this.oldWidth = 2*this.radiusX; - this.oldHeight = 2*this.radiusY; - - } else if(ORYX.Editor.checkClassType(this.element, SVGLineElement)) { - this.type = "Line"; - - var x1 = undefined; - var y1 = undefined; - var x2 = undefined; - var y2 = undefined; - var x1Attr = this.element.getAttributeNS(null, "x1"); - if(x1Attr) { - x1 = parseFloat(x1Attr); - } else { - throw "Missing attribute in element " + this.element; - } - var y1Attr = this.element.getAttributeNS(null, "y1"); - if(y1Attr) { - y1 = parseFloat(y1Attr); - } else { - throw "Missing attribute in element " + this.element; - } - var x2Attr = this.element.getAttributeNS(null, "x2"); - if(x2Attr) { - x2 = parseFloat(x2Attr); - } else { - throw "Missing attribute in element " + this.element; - } - var y2Attr = this.element.getAttributeNS(null, "y2"); - if(y2Attr) { - y2 = parseFloat(y2Attr); - } else { - throw "Missing attribute in element " + this.element; - } - this.oldX = Math.min(x1,x2); - this.oldY = Math.min(y1,y2); - this.oldWidth = Math.abs(x1-x2); - this.oldHeight = Math.abs(y1-y2); - - } else if(ORYX.Editor.checkClassType(this.element, SVGPolylineElement) || ORYX.Editor.checkClassType(this.element, SVGPolygonElement)) { - this.type = "Polyline"; - - var pointsArray = []; - if (this.element.points&&this.element.points.numberOfItems){ - for(var i=0, size=this.element.points.numberOfItems; i 1) { - var minX = parseFloat(pointsArray[0]); - var minY = parseFloat(pointsArray[1]); - var maxX = parseFloat(pointsArray[0]); - var maxY = parseFloat(pointsArray[1]); - - for(var i = 0; i < pointsArray.length; i++) { - minX = Math.min(minX, parseFloat(pointsArray[i])); - maxX = Math.max(maxX, parseFloat(pointsArray[i])); - i++; - minY = Math.min(minY, parseFloat(pointsArray[i])); - maxY = Math.max(maxY, parseFloat(pointsArray[i])); - } - - this.oldX = minX; - this.oldY = minY; - this.oldWidth = maxX-minX; - this.oldHeight = maxY-minY; - } else { - throw "Missing attribute in element " + this.element; - } + for (var n in def) { + var item = def[n]; + if (item instanceof Function) item.$ = superClass; + proto[n] = item; + } - } else if(ORYX.Editor.checkClassType(this.element, SVGPathElement)) { - this.type = "Path"; - - this.editPathParser = new PathParser(); - this.editPathHandler = new ORYX.Core.SVG.EditPathHandler(); - this.editPathParser.setHandler(this.editPathHandler); - - var parser = new PathParser(); - var handler = new ORYX.Core.SVG.MinMaxPathHandler(); - parser.setHandler(handler); - parser.parsePath(this.element); - - this.oldX = handler.minX; - this.oldY = handler.minY; - this.oldWidth = handler.maxX - handler.minX; - this.oldHeight = handler.maxY - handler.minY; - - delete parser; - delete handler; - } else { - throw "Element is not a shape."; - } + classDef.prototype = proto; - /** initialize attributes of oryx namespace */ - //resize - var resizeAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "resize"); - if(resizeAttr) { - resizeAttr = resizeAttr.toLowerCase(); - if(resizeAttr.match(/horizontal/)) { - this.isHorizontallyResizable = true; - } else { - this.isHorizontallyResizable = false; - } - if(resizeAttr.match(/vertical/)) { - this.isVerticallyResizable = true; - } else { - this.isVerticallyResizable = false; - } - } else { - this.isHorizontallyResizable = false; - this.isVerticallyResizable = false; - } + //Give this new class the same static extend method + classDef.extend = this.extend; + return classDef; +};/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ - //anchors - var anchorAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "anchors"); - if(anchorAttr) { - anchorAttr = anchorAttr.replace("/,/g", " "); - var anchors = anchorAttr.split(" ").without(""); - - for(var i = 0; i < anchors.length; i++) { - switch(anchors[i].toLowerCase()) { - case "left": - this.anchorLeft = true; - break; - case "right": - this.anchorRight = true; - break; - case "top": - this.anchorTop = true; - break; - case "bottom": - this.anchorBottom = true; - break; - } - } - } - - //allowDockers and resizeMarkerMid - if(ORYX.Editor.checkClassType(this.element, SVGPathElement)) { - var allowDockersAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "allowDockers"); - if(allowDockersAttr) { - if(allowDockersAttr.toLowerCase() === "no") { - this.allowDockers = false; - } else { - this.allowDockers = true; - } - } - - var resizeMarkerMidAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "resizeMarker-mid"); - if(resizeMarkerMidAttr) { - if(resizeMarkerMidAttr.toLowerCase() === "yes") { - this.resizeMarkerMid = true; - } else { - this.resizeMarkerMid = false; - } - } - } - - this.x = this.oldX; - this.y = this.oldY; - this.width = this.oldWidth; - this.height = this.oldHeight; - }, +if (!ORYX) var ORYX = {}; - /** - * Writes the changed values into the SVG element. - */ - update: function() { - - if(this.x !== this.oldX || this.y !== this.oldY || this.width !== this.oldWidth || this.height !== this.oldHeight) { - switch(this.type) { - case "Rect": - if(this.x !== this.oldX) this.element.setAttributeNS(null, "x", this.x); - if(this.y !== this.oldY) this.element.setAttributeNS(null, "y", this.y); - if(this.width !== this.oldWidth) this.element.setAttributeNS(null, "width", this.width); - if(this.height !== this.oldHeight) this.element.setAttributeNS(null, "height", this.height); - break; - case "Circle": - //calculate the radius - //var r; -// if(this.width/this.oldWidth <= this.height/this.oldHeight) { -// this.radiusX = ((this.width > this.height) ? this.width : this.height)/2.0; -// } else { - this.radiusX = ((this.width < this.height) ? this.width : this.height)/2.0; - //} - - this.element.setAttributeNS(null, "cx", this.x + this.width/2.0); - this.element.setAttributeNS(null, "cy", this.y + this.height/2.0); - this.element.setAttributeNS(null, "r", this.radiusX); - break; - case "Ellipse": - this.radiusX = this.width/2; - this.radiusY = this.height/2; - - this.element.setAttributeNS(null, "cx", this.x + this.radiusX); - this.element.setAttributeNS(null, "cy", this.y + this.radiusY); - this.element.setAttributeNS(null, "rx", this.radiusX); - this.element.setAttributeNS(null, "ry", this.radiusY); - break; - case "Line": - if(this.x !== this.oldX) - this.element.setAttributeNS(null, "x1", this.x); - - if(this.y !== this.oldY) - this.element.setAttributeNS(null, "y1", this.y); - - if(this.x !== this.oldX || this.width !== this.oldWidth) - this.element.setAttributeNS(null, "x2", this.x + this.width); - - if(this.y !== this.oldY || this.height !== this.oldHeight) - this.element.setAttributeNS(null, "y2", this.y + this.height); - break; - case "Polyline": - var points = this.element.getAttributeNS(null, "points"); - if(points) { - points = points.replace(/,/g, " ").split(" ").without(""); - - if(points && points.length && points.length > 1) { - - //TODO what if oldWidth == 0? - var widthDelta = (this.oldWidth === 0) ? 0 : this.width / this.oldWidth; - var heightDelta = (this.oldHeight === 0) ? 0 : this.height / this.oldHeight; - - var updatedPoints = ""; - for(var i = 0; i < points.length; i++) { - var x = (parseFloat(points[i])-this.oldX)*widthDelta + this.x; - i++; - var y = (parseFloat(points[i])-this.oldY)*heightDelta + this.y; - updatedPoints += x + " " + y + " "; - } - this.element.setAttributeNS(null, "points", updatedPoints); - } else { - //TODO error - } - } else { - //TODO error - } - break; - case "Path": - //calculate scaling delta - //TODO what if oldWidth == 0? - var widthDelta = (this.oldWidth === 0) ? 0 : this.width / this.oldWidth; - var heightDelta = (this.oldHeight === 0) ? 0 : this.height / this.oldHeight; - - //use path parser to edit each point of the path - this.editPathHandler.init(this.x, this.y, this.oldX, this.oldY, widthDelta, heightDelta); - this.editPathParser.parsePath(this.element); - - //change d attribute of path - this.element.setAttributeNS(null, "d", this.editPathHandler.d); - break; - } +if (!ORYX.CONFIG) ORYX.CONFIG = {}; - this.oldX = this.x; - this.oldY = this.y; - this.oldWidth = this.width; - this.oldHeight = this.height; - } - - // Remove cached variables - delete this.visible; - delete this.handler; - }, - - isPointIncluded: function(pointX, pointY) { +/** + * This file contains URI constants that may be used for XMLHTTPRequests. + */ - // Check if there are the right arguments and if the node is visible - if(!pointX || !pointY || !this.isVisible()) { - return false; - } +ORYX.CONFIG.ROOT_PATH = "editor/"; //TODO: Remove last slash!! +ORYX.CONFIG.EXPLORER_PATH = "explorer"; +ORYX.CONFIG.LIBS_PATH = "libs"; - switch(this.type) { - case "Rect": - return (pointX >= this.x && pointX <= this.x + this.width && - pointY >= this.y && pointY <= this.y+this.height); - break; - case "Circle": - //calculate the radius -// var r; -// if(this.width/this.oldWidth <= this.height/this.oldHeight) { -// r = ((this.width > this.height) ? this.width : this.height)/2.0; -// } else { -// r = ((this.width < this.height) ? this.width : this.height)/2.0; -// } - return ORYX.Core.Math.isPointInEllipse(pointX, pointY, this.x + this.width/2.0, this.y + this.height/2.0, this.radiusX, this.radiusX); - break; - case "Ellipse": - return ORYX.Core.Math.isPointInEllipse(pointX, pointY, this.x + this.radiusX, this.y + this.radiusY, this.radiusX, this.radiusY); - break; - case "Line": - return ORYX.Core.Math.isPointInLine(pointX, pointY, this.x, this.y, this.x + this.width, this.y + this.height); - break; - case "Polyline": - var points = this.element.getAttributeNS(null, "points"); - - if(points) { - points = points.replace(/,/g , " ").split(" ").without(""); - - points = points.collect(function(n) { - return parseFloat(n); - }); - - return ORYX.Core.Math.isPointInPolygone(pointX, pointY, points); - } else { - return false; - } - break; - case "Path": - - // Cache Path handler - if (!this.handler) { - var parser = new PathParser(); - this.handler = new ORYX.Core.SVG.PointsPathHandler(); - parser.setHandler(this.handler); - parser.parsePath(this.element); - } - - return ORYX.Core.Math.isPointInPolygone(pointX, pointY, this.handler.points); - - break; - default: - return false; - } - }, +/** + * Regular Config + */ +ORYX.CONFIG.SERVER_HANDLER_ROOT = "service"; +ORYX.CONFIG.SERVER_EDITOR_HANDLER = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/editor"; +ORYX.CONFIG.SERVER_MODEL_HANDLER = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/model"; +ORYX.CONFIG.STENCILSET_HANDLER = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/editor_stencilset?embedsvg=true&url=true&namespace="; +ORYX.CONFIG.STENCIL_SETS_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/editor_stencilset"; + +ORYX.CONFIG.PLUGINS_CONFIG = "editor-app/plugins.xml"; +ORYX.CONFIG.SYNTAXCHECKER_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/syntaxchecker"; +ORYX.CONFIG.DEPLOY_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/model/deploy"; +ORYX.CONFIG.MODEL_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/models"; +ORYX.CONFIG.FORM_FLOW_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/formflows"; +ORYX.CONFIG.FORM_FLOW_IMAGE_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/formflow"; +ORYX.CONFIG.FORM_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/forms"; +ORYX.CONFIG.FORM_IMAGE_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/form"; +ORYX.CONFIG.SUB_PROCESS_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/subprocesses"; +ORYX.CONFIG.SUB_PROCESS_IMAGE_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/subprocess"; +ORYX.CONFIG.TEST_SERVICE_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/service/"; + +ORYX.CONFIG.SERVICE_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/services"; +ORYX.CONFIG.CONDITION_ELEMENT_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/conditionelements"; +ORYX.CONFIG.VARIABLEDEF_ELEMENT_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/variabledefinitionelements"; +ORYX.CONFIG.VALIDATOR_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/validators"; + +ORYX.CONFIG.SS_EXTENSIONS_FOLDER = ORYX.CONFIG.ROOT_PATH + "stencilsets/extensions/"; +ORYX.CONFIG.SS_EXTENSIONS_CONFIG = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/editor_ssextensions"; +ORYX.CONFIG.ORYX_NEW_URL = "/new"; +ORYX.CONFIG.BPMN_LAYOUTER = ORYX.CONFIG.ROOT_PATH + "bpmnlayouter"; + +ORYX.CONFIG.EXPRESSION_METADATA_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/expression-metadata"; +ORYX.CONFIG.DATASOURCE_METADATA_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/datasource-metadata";/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ - /** - * Returns true if the element is visible - * @param {SVGElement} elem - * @return boolean - */ - isVisible: function(elem) { - - if (this.visible !== undefined){ - return this.visible; - } - - if (!elem) { - elem = this.element; - } +if (!ORYX) var ORYX = {}; - var hasOwnerSVG = false; - try { - hasOwnerSVG = !!elem.ownerSVGElement; - } catch(e){} - - // Is SVG context - if ( hasOwnerSVG ) { - // IF G-Element - if (ORYX.Editor.checkClassType(elem, SVGGElement)) { - if (elem.className && elem.className.baseVal == "me") { - this.visible = true; - return this.visible; - } - } +if (!ORYX.CONFIG) ORYX.CONFIG = {}; - // Check if fill or stroke is set - var fill = elem.getAttributeNS(null, "fill"); - var stroke = elem.getAttributeNS(null, "stroke"); - if (fill && fill == "none" && stroke && stroke == "none") { - this.visible = false; - } else { - // Check if displayed - var attr = elem.getAttributeNS(null, "display"); - if(!attr) - this.visible = this.isVisible(elem.parentNode); - else if (attr == "none") - this.visible = false; - else - this.visible = true; - } - } else { - this.visible = true; - } - - return this.visible; - }, +/** + * Signavio specific variables + */ +ORYX.CONFIG.BACKEND_SWITCH = true; +ORYX.CONFIG.PANEL_LEFT_WIDTH = 250; +ORYX.CONFIG.PANEL_RIGHT_COLLAPSED = true; +ORYX.CONFIG.PANEL_RIGHT_WIDTH = 300; +ORYX.CONFIG.APPNAME = 'KISBPM'; +ORYX.CONFIG.WEB_URL = "."; - toString: function() { return (this.element) ? "SVGShape " + this.element.id : "SVGShape " + this.element;} - });/* +ORYX.CONFIG.BLANK_IMAGE = ORYX.CONFIG.LIBS_PATH + '/ext-2.0.2/resources/images/default/s.gif'; + +/* Specify offset of header */ +ORYX.CONFIG.OFFSET_HEADER = 61; + +/* Show grid line while dragging */ +ORYX.CONFIG.SHOW_GRIDLINE = true; + +/* Editor-Mode */ +ORYX.CONFIG.MODE_READONLY = "readonly"; +ORYX.CONFIG.MODE_FULLSCREEN = "fullscreen"; +ORYX.CONFIG.WINDOW_HEIGHT = 800; +ORYX.CONFIG.PREVENT_LOADINGMASK_AT_READY = false; + +/* Plugins */ +ORYX.CONFIG.PLUGINS_ENABLED = true; +ORYX.CONFIG.PLUGINS_FOLDER = "Plugins/"; + +ORYX.CONFIG.BPMN20_SCHEMA_VALIDATION_ON = true; + +/* Namespaces */ +ORYX.CONFIG.NAMESPACE_ORYX = "http://www.b3mn.org/oryx"; +ORYX.CONFIG.NAMESPACE_SVG = "http://www.w3.org/2000/svg"; + +/* UI */ +ORYX.CONFIG.CANVAS_WIDTH = 1200; +ORYX.CONFIG.CANVAS_HEIGHT = 1050; +ORYX.CONFIG.CANVAS_RESIZE_INTERVAL = 100; +ORYX.CONFIG.CANVAS_MIN_WIDTH = 800; +ORYX.CONFIG.CANVAS_MIN_HEIGHT = 300; +ORYX.CONFIG.SELECTED_AREA_PADDING = 4; +ORYX.CONFIG.CANVAS_BACKGROUND_COLOR = "none"; +ORYX.CONFIG.GRID_DISTANCE = 30; +ORYX.CONFIG.GRID_ENABLED = true; +ORYX.CONFIG.ZOOM_OFFSET = 0.1; +ORYX.CONFIG.DEFAULT_SHAPE_MARGIN = 60; +ORYX.CONFIG.SCALERS_SIZE = 7; +ORYX.CONFIG.MINIMUM_SIZE = 20; +ORYX.CONFIG.MAXIMUM_SIZE = 10000; +ORYX.CONFIG.OFFSET_MAGNET = 15; +ORYX.CONFIG.OFFSET_EDGE_LABEL_TOP = 8; +ORYX.CONFIG.OFFSET_EDGE_LABEL_BOTTOM = 8; +ORYX.CONFIG.OFFSET_EDGE_BOUNDS = 5; +ORYX.CONFIG.COPY_MOVE_OFFSET = 30; + +ORYX.CONFIG.BORDER_OFFSET = 14; + +ORYX.CONFIG.MAX_NUM_SHAPES_NO_GROUP = 20; // Updated so the form editor shows all elements at once + +ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER = 30; +ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET = 45; + +/* Shape-Menu Align */ +ORYX.CONFIG.SHAPEMENU_RIGHT = "Oryx_Right"; +ORYX.CONFIG.SHAPEMENU_BOTTOM = "Oryx_Bottom"; +ORYX.CONFIG.SHAPEMENU_LEFT = "Oryx_Left"; +ORYX.CONFIG.SHAPEMENU_TOP = "Oryx_Top"; + + +/* Morph-Menu Item */ +ORYX.CONFIG.MORPHITEM_DISABLED = "Oryx_MorphItem_disabled"; + +/* Property type names */ +ORYX.CONFIG.TYPE_STRING = "string"; +ORYX.CONFIG.TYPE_BOOLEAN = "boolean"; +ORYX.CONFIG.TYPE_INTEGER = "integer"; +ORYX.CONFIG.TYPE_FLOAT = "float"; +ORYX.CONFIG.TYPE_COLOR = "color"; +ORYX.CONFIG.TYPE_DATE = "date"; +ORYX.CONFIG.TYPE_CHOICE = "choice"; +ORYX.CONFIG.TYPE_URL = "url"; +ORYX.CONFIG.TYPE_DIAGRAM_LINK = "diagramlink"; +ORYX.CONFIG.TYPE_COMPLEX = "complex"; +ORYX.CONFIG.TYPE_MULTIPLECOMPLEX = "multiplecomplex"; +ORYX.CONFIG.TYPE_TEXT = "text"; +ORYX.CONFIG.TYPE_KISBPM_MULTIINSTANCE = "kisbpm-multiinstance"; +ORYX.CONFIG.TYPE_MODEL_LINK = "modellink"; +ORYX.CONFIG.TYPE_FORM_FLOW_LINK = "formflowlink"; +ORYX.CONFIG.TYPE_FORM_LINK = "formlink"; +ORYX.CONFIG.TYPE_SUB_PROCESS_LINK = "subprocesslink"; +ORYX.CONFIG.TYPE_SERVICE_LINK = "servicelink"; +ORYX.CONFIG.TYPE_CONDITIONS = "conditions"; +ORYX.CONFIG.TYPE_VARIABLES = "variables"; +ORYX.CONFIG.TYPE_LISTENER = "listener"; +ORYX.CONFIG.TYPE_EPC_FREQ = "epcfrequency"; +ORYX.CONFIG.TYPE_GLOSSARY_LINK = "glossarylink"; +ORYX.CONFIG.TYPE_EXPRESSION = "expression"; +ORYX.CONFIG.TYPE_DATASOURCE = "datasource"; +ORYX.CONFIG.TYPE_DATASOURCE_MINIMAL = "datasource-minimal"; +ORYX.CONFIG.TYPE_VALIDATORS = "validators"; + + +/* Vertical line distance of multiline labels */ +ORYX.CONFIG.LABEL_LINE_DISTANCE = 2; +ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT = 12; + +/* Open Morph Menu with Hover */ +ORYX.CONFIG.ENABLE_MORPHMENU_BY_HOVER = false; + + +/* Editor constants come here */ +ORYX.CONFIG.EDITOR_ALIGN_BOTTOM = 0x01; +ORYX.CONFIG.EDITOR_ALIGN_MIDDLE = 0x02; +ORYX.CONFIG.EDITOR_ALIGN_TOP = 0x04; +ORYX.CONFIG.EDITOR_ALIGN_LEFT = 0x08; +ORYX.CONFIG.EDITOR_ALIGN_CENTER = 0x10; +ORYX.CONFIG.EDITOR_ALIGN_RIGHT = 0x20; +ORYX.CONFIG.EDITOR_ALIGN_SIZE = 0x30; + +/* Event types */ +ORYX.CONFIG.EVENT_MOUSEDOWN = "mousedown"; +ORYX.CONFIG.EVENT_MOUSEUP = "mouseup"; +ORYX.CONFIG.EVENT_MOUSEOVER = "mouseover"; +ORYX.CONFIG.EVENT_MOUSEOUT = "mouseout"; +ORYX.CONFIG.EVENT_MOUSEMOVE = "mousemove"; +ORYX.CONFIG.EVENT_DBLCLICK = "dblclick"; +ORYX.CONFIG.EVENT_KEYDOWN = "keydown"; +ORYX.CONFIG.EVENT_KEYUP = "keyup"; + +ORYX.CONFIG.EVENT_LOADED = "editorloaded"; +ORYX.CONFIG.EVENT_SAVED = "editorSaved"; + +ORYX.CONFIG.EVENT_EXECUTE_COMMANDS = "executeCommands"; +ORYX.CONFIG.EVENT_STENCIL_SET_LOADED = "stencilSetLoaded"; +ORYX.CONFIG.EVENT_SELECTION_CHANGED = "selectionchanged"; +ORYX.CONFIG.EVENT_SHAPEADDED = "shapeadded"; +ORYX.CONFIG.EVENT_SHAPEREMOVED = "shaperemoved"; +ORYX.CONFIG.EVENT_PROPERTY_CHANGED = "propertyChanged"; +ORYX.CONFIG.EVENT_DRAGDROP_START = "dragdrop.start"; +ORYX.CONFIG.EVENT_SHAPE_MENU_CLOSE = "shape.menu.close"; +ORYX.CONFIG.EVENT_DRAGDROP_END = "dragdrop.end"; +ORYX.CONFIG.EVENT_RESIZE_START = "resize.start"; +ORYX.CONFIG.EVENT_RESIZE_END = "resize.end"; +ORYX.CONFIG.EVENT_DRAGDOCKER_DOCKED = "dragDocker.docked"; +ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW = "highlight.showHighlight"; +ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE = "highlight.hideHighlight"; +ORYX.CONFIG.EVENT_LOADING_ENABLE = "loading.enable"; +ORYX.CONFIG.EVENT_LOADING_DISABLE = "loading.disable"; +ORYX.CONFIG.EVENT_LOADING_STATUS = "loading.status"; +ORYX.CONFIG.EVENT_OVERLAY_SHOW = "overlay.show"; +ORYX.CONFIG.EVENT_OVERLAY_HIDE = "overlay.hide"; +ORYX.CONFIG.EVENT_ARRANGEMENT_TOP = "arrangement.setToTop"; +ORYX.CONFIG.EVENT_ARRANGEMENT_BACK = "arrangement.setToBack"; +ORYX.CONFIG.EVENT_ARRANGEMENT_FORWARD = "arrangement.setForward"; +ORYX.CONFIG.EVENT_ARRANGEMENT_BACKWARD = "arrangement.setBackward"; +ORYX.CONFIG.EVENT_PROPWINDOW_PROP_CHANGED = "propertyWindow.propertyChanged"; +ORYX.CONFIG.EVENT_LAYOUT_ROWS = "layout.rows"; +ORYX.CONFIG.EVENT_LAYOUT_BPEL = "layout.BPEL"; +ORYX.CONFIG.EVENT_LAYOUT_BPEL_VERTICAL = "layout.BPEL.vertical"; +ORYX.CONFIG.EVENT_LAYOUT_BPEL_HORIZONTAL = "layout.BPEL.horizontal"; +ORYX.CONFIG.EVENT_LAYOUT_BPEL_SINGLECHILD = "layout.BPEL.singlechild"; +ORYX.CONFIG.EVENT_LAYOUT_BPEL_AUTORESIZE = "layout.BPEL.autoresize"; +ORYX.CONFIG.EVENT_AUTOLAYOUT_LAYOUT = "autolayout.layout"; +ORYX.CONFIG.EVENT_UNDO_EXECUTE = "undo.execute"; +ORYX.CONFIG.EVENT_UNDO_ROLLBACK = "undo.rollback"; +ORYX.CONFIG.EVENT_BUTTON_UPDATE = "toolbar.button.update"; +ORYX.CONFIG.EVENT_LAYOUT = "layout.dolayout"; +ORYX.CONFIG.EVENT_GLOSSARY_LINK_EDIT = "glossary.link.edit"; +ORYX.CONFIG.EVENT_GLOSSARY_SHOW = "glossary.show.info"; +ORYX.CONFIG.EVENT_GLOSSARY_NEW = "glossary.show.new"; +ORYX.CONFIG.EVENT_DOCKERDRAG = "dragTheDocker"; +ORYX.CONFIG.EVENT_CANVAS_SCROLL = "canvas.scroll"; + +ORYX.CONFIG.EVENT_SHOW_PROPERTYWINDOW = "propertywindow.show"; +ORYX.CONFIG.EVENT_ABOUT_TO_SAVE = "file.aboutToSave"; + +/* Selection Shapes Highlights */ +ORYX.CONFIG.SELECTION_HIGHLIGHT_SIZE = 5; +ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR = "#4444FF"; +ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR2 = "#9999FF"; + +ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_CORNER = "corner"; +ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE = "rectangle"; + +ORYX.CONFIG.SELECTION_VALID_COLOR = "#00FF00"; +ORYX.CONFIG.SELECTION_INVALID_COLOR = "#FF0000"; + + +ORYX.CONFIG.DOCKER_DOCKED_COLOR = "#00FF00"; +ORYX.CONFIG.DOCKER_UNDOCKED_COLOR = "#FF0000"; +ORYX.CONFIG.DOCKER_SNAP_OFFSET = 10; + +/* Copy & Paste */ +ORYX.CONFIG.EDIT_OFFSET_PASTE = 10; + +/* Key-Codes */ +ORYX.CONFIG.KEY_CODE_X = 88; +ORYX.CONFIG.KEY_CODE_C = 67; +ORYX.CONFIG.KEY_CODE_V = 86; +ORYX.CONFIG.KEY_CODE_DELETE = 46; +ORYX.CONFIG.KEY_CODE_META = 224; +ORYX.CONFIG.KEY_CODE_BACKSPACE = 8; +ORYX.CONFIG.KEY_CODE_LEFT = 37; +ORYX.CONFIG.KEY_CODE_RIGHT = 39; +ORYX.CONFIG.KEY_CODE_UP = 38; +ORYX.CONFIG.KEY_CODE_DOWN = 40; + +// TODO Determine where the lowercase constants are still used and remove them from here. +ORYX.CONFIG.KEY_Code_enter = 12; +ORYX.CONFIG.KEY_Code_left = 37; +ORYX.CONFIG.KEY_Code_right = 39; +ORYX.CONFIG.KEY_Code_top = 38; +ORYX.CONFIG.KEY_Code_bottom = 40; + +/* Supported Meta Keys */ + +ORYX.CONFIG.META_KEY_META_CTRL = "metactrl"; +ORYX.CONFIG.META_KEY_ALT = "alt"; +ORYX.CONFIG.META_KEY_SHIFT = "shift"; + +/* Key Actions */ + +ORYX.CONFIG.KEY_ACTION_DOWN = "down"; +ORYX.CONFIG.KEY_ACTION_UP = "up"; + + +/* Form Rowlayouting */ +ORYX.CONFIG.FORM_ROW_WIDTH = 350; +ORYX.CONFIG.FORM_GROUP_MARGIN = 5; +ORYX.CONFIG.FORM_GROUP_EMPTY_HEIGHT = 100; + +/* Form element types */ +ORYX.CONFIG.FORM_ELEMENT_ID_PREFIX = 'http://b3mn.org/stencilset/xforms'; +ORYX.CONFIG.FORM_ELEMENT_TYPE_ROOT = 'http://b3mn.org/stencilset/xforms#XForm'; +ORYX.CONFIG.FORM_ELEMENT_TYPE_GROUP = 'http://b3mn.org/stencilset/xforms#Group'; +ORYX.CONFIG.FORM_ELEMENT_TYPE_REPEATING_GROUP = 'http://b3mn.org/stencilset/xforms#RepeatingGroup'; +ORYX.CONFIG.FORM_ELEMENT_TYPE_LABEL_FIELD = 'http://b3mn.org/stencilset/xforms#LabelField'; + +/* * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. * License rights for this program may be obtained from Alfresco Software, Ltd. * pursuant to a written agreement and any use of this program without such an * agreement is prohibited. */ + /* * All code Copyright 2013 KIS Consultancy all rights reserved */ -/** - * Init namespaces - */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} -if(!ORYX.Core.SVG) {ORYX.Core.SVG = {};} +function printf() { -/** - * @classDescription Class for adding text to a shape. - * - */ -ORYX.Core.SVG.Label = Clazz.extend({ - - _characterSets:[ - "%W", - "@", - "m", - "wDGMOQ?????#+=<>~^", - "ABCHKNRSUVXZ??????????&", - "bdghnopqux???????????ETY1234567890?????_????${}*????`???????????", - "aeksvyz?????FLP????????????????", - "c-", - "rtJ\"/()[]:;!|\\", - "fjI., ", - "'", - "il" - ], - _characterSetValues:[15,14,13,11,10,9,8,7,6,5,4,3], - - /** - * Constructor - * @param options {Object} : - * textElement - * - */ - construct: function(options) { - arguments.callee.$.construct.apply(this, arguments); - - if(!options.textElement) { - throw "Label: No parameter textElement." - } else if (!ORYX.Editor.checkClassType( options.textElement, SVGTextElement ) ) { - throw "Label: Parameter textElement is not an SVGTextElement." - } - - this.invisibleRenderPoint = -5000; - - this.node = options.textElement; - - - this.node.setAttributeNS(null, 'stroke-width', '0pt'); - this.node.setAttributeNS(null, 'letter-spacing', '-0.01px'); - - this.shapeId = options.shapeId; - - this.id; - - this.fitToElemId; - - this.edgePosition; - - this.x; - this.y; - this.oldX; - this.oldY; - - this.isVisible = true; - - this._text; - this._verticalAlign; - this._horizontalAlign; - this._rotate; - this._rotationPoint; - - //this.anchors = []; - this.anchorLeft; - this.anchorRight; - this.anchorTop; - this.anchorBottom; - - this._isChanged = true; - - //if the text element already has an id, don't change it. - var _id = this.node.getAttributeNS(null, 'id'); - if(_id) { - this.id = _id; - } - - //initialization - - //set referenced element the text is fit to - this.fitToElemId = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'fittoelem'); - if(this.fitToElemId) - this.fitToElemId = this.shapeId + this.fitToElemId; - - //set alignment - var alignValues = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'align'); - if(alignValues) { - alignValues = alignValues.replace(/,/g, " "); - alignValues = alignValues.split(" "); - alignValues = alignValues.without(""); - - alignValues.each((function(alignValue) { - switch (alignValue) { - case 'top': - case 'middle': - case 'bottom': - if(!this._verticalAlign){this._originVerticalAlign = this._verticalAlign = alignValue;} - break; - case 'left': - case 'center': - case 'right': - if(!this._horizontalAlign){this._originHorizontalAlign = this._horizontalAlign = alignValue;} - break; - } - }).bind(this)); - } - - //set edge position (only in case the label belongs to an edge) - this.edgePosition = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'edgePosition'); - if(this.edgePosition) { - this.originEdgePosition = this.edgePosition = this.edgePosition.toLowerCase(); - } - - - //get offset top - this.offsetTop = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'offsetTop') || ORYX.CONFIG.OFFSET_EDGE_LABEL_TOP; - if(this.offsetTop) { - this.offsetTop = parseInt(this.offsetTop); - } - - //get offset top - this.offsetBottom = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'offsetBottom') || ORYX.CONFIG.OFFSET_EDGE_LABEL_BOTTOM; - if(this.offsetBottom) { - this.offsetBottom = parseInt(this.offsetBottom); - } - - - //set rotation - var rotateValue = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'rotate'); - if(rotateValue) { - try { - this._rotate = parseFloat(rotateValue); - } catch (e) { - this._rotate = 0; - } - } else { - this._rotate = 0; - } - - //anchors - var anchorAttr = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "anchors"); - if(anchorAttr) { - anchorAttr = anchorAttr.replace("/,/g", " "); - var anchors = anchorAttr.split(" ").without(""); - - for(var i = 0; i < anchors.length; i++) { - switch(anchors[i].toLowerCase()) { - case "left": - this.originAnchorLeft = this.anchorLeft = true; - break; - case "right": - this.originAnchorRight = this.anchorRight = true; - break; - case "top": - this.originAnchorTop = this.anchorTop = true; - break; - case "bottom": - this.originAnchorBottom = this.anchorBottom = true; - break; - } - } - } - - //if no alignment defined, set default alignment - if(!this._verticalAlign) { this._verticalAlign = 'bottom'; } - if(!this._horizontalAlign) { this._horizontalAlign = 'left'; } - - var xValue = this.node.getAttributeNS(null, 'x'); - if(xValue) { - this.oldX = this.x = parseFloat(xValue); - } else { - //TODO error - } - - var yValue = this.node.getAttributeNS(null, 'y'); - if(yValue) { - this.oldY = this.y = parseFloat(yValue); - } else { - //TODO error - } - - //set initial text - this.text(this.node.textContent); - }, - - /** - * Reset the anchor position to the original value - * which was specified in the stencil set - * - */ - resetAnchorPosition: function(){ - this.anchorLeft = this.originAnchorLeft || false; - this.anchorRight = this.originAnchorRight || false; - this.anchorTop = this.originAnchorTop || false; - this.anchorBottom = this.originAnchorBottom || false; - }, - - isOriginAnchorLeft: function(){ return this.originAnchorLeft || false; }, - isOriginAnchorRight: function(){ return this.originAnchorRight || false; }, - isOriginAnchorTop: function(){ return this.originAnchorTop || false; }, - isOriginAnchorBottom: function(){ return this.originAnchorBottom || false; }, - - - isAnchorLeft: function(){ return this.anchorLeft || false; }, - isAnchorRight: function(){ return this.anchorRight || false; }, - isAnchorTop: function(){ return this.anchorTop || false; }, - isAnchorBottom: function(){ return this.anchorBottom || false; }, - - /** - * Returns the x coordinate - * @return {number} - */ - getX: function(){ - try { - var x = this.node.x.baseVal.getItem(0).value; - switch(this.horizontalAlign()){ - case "left": return x; - case "center": return x - (this.getWidth()/2); - case "right": return x - this.getWidth(); - } - return this.node.getBBox().x; - } catch(e){ - return this.x; - } - }, - - setX: function(x){ - if (this.position) - this.position.x = x; - else - this.setOriginX(x); - }, - - - /** - * Returns the y coordinate - * @return {number} - */ - getY: function(){ - try { - return this.node.getBBox().y; - } catch(e){ - return this.y; - } - }, - - setY: function(y){ - if (this.position) - this.position.y = y; - else - this.setOriginY(y); - }, - - setOriginX: function(x){ - this.x = x; - }, - - setOriginY: function(y){ - this.y = y; - }, + var result = arguments[0]; + for (var i = 1; i < arguments.length; i++) + result = result.replace('%' + (i - 1), arguments[i]); + return result; +} - - /** - * Returns the width of the label - * @return {number} - */ - getWidth: function(){ - try { - try { - var width, cn = this.node.childNodes; - if (cn.length == 0) { - width = this.node.getBBox().width; - } else { - for (var i = 0, size = cn.length; i < size; ++i) { - var w = cn[i].getComputedTextLength(); - if ("undefined" == typeof width || width < w) { - width = w; - } - } - } - return width+(width%2==0?0:1); - } catch (ee) { - return this.node.getBBox().width; - } - } catch(e){ - return 0; - } - }, - - getOriginUpperLeft: function(){ - var x = this.x, y = this.y; - switch (this._horizontalAlign){ - case 'center' : - x -= this.getWidth()/2; - break; - case 'right' : - x -= this.getWidth(); - break; - } - switch (this._verticalAlign){ - case 'middle' : - y -= this.getHeight()/2; - break; - case 'bottom' : - y -= this.getHeight(); - break; - } - return {x:x, y:y}; - }, - - /** - * Returns the height of the label - * @return {number} - */ - getHeight: function(){ - try { - return this.node.getBBox().height; - } catch(e){ - return 0; - } - }, - - /** - * Returns the relative center position of the label - * to its parent shape. - * @return {Object} - */ - getCenter: function(){ - var up = {x: this.getX(), y: this.getY()}; - up.x += this.getWidth()/2; - up.y += this.getHeight()/2; - return up; - }, - - /** - * Sets the position of a label relative to the parent. - * @param {Object} position - */ - setPosition: function(position){ - if (!position || position.x === undefined || position.y === undefined) { - delete this.position; - } else { - this.position = position; - } - - if (this.position){ - delete this._referencePoint; - delete this.edgePosition; - } - - this._isChanged = true; - this.update(); - }, - - /** - * Return the position - */ - getPosition: function(){ - return this.position; - }, - - setReferencePoint: function(ref){ - if (ref) { - this._referencePoint = ref; - } else { - delete this._referencePoint; - } - if (this._referencePoint){ - delete this.position; - } - }, - - getReferencePoint: function(){ - return this._referencePoint || undefined; - }, - - changed: function() { - this._isChanged = true; - }, - - /** - * Register a callback which will be called if the label - * was rendered. - * @param {Object} fn - */ - registerOnChange: function(fn){ - if (!this.changeCallbacks){ - this.changeCallbacks = []; - } - if (fn instanceof Function && !this.changeCallbacks.include(fn)){ - this.changeCallbacks.push(fn); - } - }, - - /** - * Unregister the callback for changes. - * @param {Object} fn - */ - unregisterOnChange: function(fn){ - if (this.changeCallbacks && fn instanceof Function && this.changeCallbacks.include(fn)){ - this.changeCallbacks = this.changeCallbacks.without(fn); - } - }, - - /** - * Returns TRUE if the labe is currently in - * the update mechanism. - * @return {Boolean} - */ - isUpdating: function(){ - return !!this._isUpdating; - }, - - - getOriginEdgePosition: function(){ - return this.originEdgePosition; - }, - - /** - * Returns the edgeposition. - * - * @return {String} "starttop", "startmiddle", "startbottom", - * "midtop", "midbottom", "endtop", "endbottom" or null - */ - getEdgePosition: function(){ - return this.edgePosition || null; - }, - - /** - * Set the edge position, must be one of the valid - * edge positions (see getEdgePosition). - * Removes the reference point and the absolute position as well. - * - * @param {Object} position - */ - setEdgePosition: function(position){ - if (["starttop", "startmiddle", "startbottom", - "midtop", "midbottom", "endtop", "endbottom"].include(position)){ - this.edgePosition = position; - delete this.position; - delete this._referencePoint; - } else { - delete this.edgePosition; - } - }, - - /** - * Update the SVG text element. - */ - update: function(force) { - - var x = this.x, y = this.y; - if (this.position){ - x = this.position.x; - y = this.position.y; - } - x = Math.floor(x); y = Math.floor(y); - - if(this._isChanged || x !== this.oldX || y !== this.oldY || force === true) { - if (this.isVisible) { - this._isChanged = false; - this._isUpdating = true; - - this.node.setAttributeNS(null, 'x', x); - this.node.setAttributeNS(null, 'y', y); - this.node.removeAttributeNS(null, "fill-opacity"); - - //this.node.setAttributeNS(null, 'font-size', this._fontSize); - //this.node.setAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'align', this._horizontalAlign + " " + this._verticalAlign); - - this.oldX = x; - this.oldY = y; - - //set rotation - if (!this.position && !this.getReferencePoint()) { - if (this._rotate !== undefined) { - if (this._rotationPoint) - this.node.setAttributeNS(null, 'transform', 'rotate(' + this._rotate + ' ' + Math.floor(this._rotationPoint.x) + ' ' + Math.floor(this._rotationPoint.y) + ')'); - else - this.node.setAttributeNS(null, 'transform', 'rotate(' + this._rotate + ' ' + Math.floor(x) + ' ' + Math.floor(y) + ')'); - } - } else { - this.node.removeAttributeNS(null, 'transform'); - } - - var textLines = this._text.split("\n"); - while (textLines.last() == "") - textLines.pop(); - - - if (this.node.ownerDocument) { - // Only reset the tspans if the text - // has changed or has to be wrapped - if (this.fitToElemId || this._textHasChanged){ - this.node.textContent = ""; // Remove content - textLines.each((function(textLine, index){ - var tspan = this.node.ownerDocument.createElementNS(ORYX.CONFIG.NAMESPACE_SVG, 'tspan'); - tspan.textContent = textLine.trim(); - if (this.fitToElemId) { - tspan.setAttributeNS(null, 'x', this.invisibleRenderPoint); - tspan.setAttributeNS(null, 'y', this.invisibleRenderPoint); - } - - /* - * Chrome's getBBox() method fails, if a text node contains an empty tspan element. - * So, we add a whitespace to such a tspan element. - */ - if(tspan.textContent === "") { - tspan.textContent = " "; - } - - //append tspan to text node - this.node.appendChild(tspan); - }).bind(this)); - delete this._textHasChanged; - delete this.indices; - } - - //Work around for Mozilla bug 293581 - if (this.isVisible && this.fitToElemId) { - this.node.setAttributeNS(null, 'visibility', 'hidden'); - } - - if (this.fitToElemId) { - window.setTimeout(this._checkFittingToReferencedElem.bind(this), 0); - //this._checkFittingToReferencedElem(); - } else { - window.setTimeout(this._positionText.bind(this), 0); - //this._positionText(); - } - } - } else { - this.node.textContent = ""; - //this.node.setAttributeNS(null, "fill-opacity", "0.2"); - } - } - }, - - _checkFittingToReferencedElem: function() { - try { - var tspans = $A(this.node.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'tspan')); - - //only do this in firefox 3. all other browsers do not support word wrapping!!!!! - //if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent) && new Number(RegExp.$1)>=3) { - var newtspans = []; - - var refNode = this.node.ownerDocument.getElementById(this.fitToElemId); - - if (refNode) { - var refbb = refNode.getBBox(); - - var fontSize = this.getFontSize(); - - for (var j = 0; j < tspans.length; j++) { - var tspan = tspans[j]; - - var textLength = this._getRenderedTextLength(tspan, undefined, undefined, fontSize); - - var refBoxLength = (this._rotate != 0 - && this._rotate % 180 != 0 - && this._rotate % 90 == 0 ? - refbb.height : refbb.width); - - if (textLength > refBoxLength) { - - var startIndex = 0; - var lastSeperatorIndex = 0; - - var numOfChars = this.getTrimmedTextLength(tspan.textContent); - for (var i = 0; i < numOfChars; i++) { - var sslength = this._getRenderedTextLength(tspan, startIndex, i-startIndex, fontSize); - - if (sslength > refBoxLength - 2) { - var newtspan = this.node.ownerDocument.createElementNS(ORYX.CONFIG.NAMESPACE_SVG, 'tspan'); - if (lastSeperatorIndex <= startIndex) { - lastSeperatorIndex = (i == 0) ? i : i-1; - newtspan.textContent = tspan.textContent.slice(startIndex, lastSeperatorIndex).trim(); - //lastSeperatorIndex = i; - } - else { - newtspan.textContent = tspan.textContent.slice(startIndex, ++lastSeperatorIndex).trim(); - } - - newtspan.setAttributeNS(null, 'x', this.invisibleRenderPoint); - newtspan.setAttributeNS(null, 'y', this.invisibleRenderPoint); - - //insert tspan to text node - //this.node.insertBefore(newtspan, tspan); - newtspans.push(newtspan); - - startIndex = lastSeperatorIndex; - } - else { - var curChar = tspan.textContent.charAt(i); - if (curChar == ' ' || - curChar == '-' || - curChar == "." || - curChar == "," || - curChar == ";" || - curChar == ":") { - lastSeperatorIndex = i; - } - } - } - - tspan.textContent = tspan.textContent.slice(startIndex).trim(); - } - - newtspans.push(tspan); - } - - while (this.node.hasChildNodes()) - this.node.removeChild(this.node.childNodes[0]); - - while (newtspans.length > 0) { - this.node.appendChild(newtspans.shift()); - } - } - //} - } catch (e) { - ORYX.Log.fatal("Error " + e); - } - window.setTimeout(this._positionText.bind(this), 0); - //this._positionText(); - }, - - /** - * This is a work around method for Mozilla bug 293581. - * Before the method getComputedTextLength works, the text has to be rendered. - */ - _positionText: function() { - try { - - var tspans = this.node.childNodes; - - var fontSize = this.getFontSize(this.node); - - var invalidTSpans = []; - - var x = this.x, y = this.y; - if (this.position){ - x = this.position.x; - y = this.position.y; - } - x = Math.floor(x); y = Math.floor(y); - - var i = 0, indic = []; // Cache indices if the _positionText is called again, before update is called - var is =(this.indices || $R(0,tspans.length-1).toArray()); - var length = is.length; - is.each((function (index) { - if ("undefined" == typeof index){ - return; - } - - var tspan = tspans[i++]; - - if(tspan.textContent.trim() === "") { - invalidTSpans.push(tspan); - } else { - //set vertical position - var dy = 0; - switch (this._verticalAlign) { - case 'bottom': - dy = -(length - index - 1) * (fontSize); - break; - case 'middle': - dy = -(length / 2.0 - index - 1) * (fontSize); - dy -= ORYX.CONFIG.LABEL_LINE_DISTANCE / 2; - break; - case 'top': - dy = index * (fontSize); - dy += fontSize; - break; - } - tspan.setAttributeNS(null, 'dy', Math.floor(dy)); - - tspan.setAttributeNS(null, 'x', x); - tspan.setAttributeNS(null, 'y', y); - indic.push(index); - } - - }).bind(this)); - - indic.length = tspans.length; - this.indices = this.indices || indic; - - invalidTSpans.each(function(tspan) { - this.node.removeChild(tspan) - }.bind(this)); - - //set horizontal alignment - switch (this._horizontalAlign) { - case 'left': - this.node.setAttributeNS(null, 'text-anchor', 'start'); - break; - case 'center': - this.node.setAttributeNS(null, 'text-anchor', 'middle'); - break; - case 'right': - this.node.setAttributeNS(null, 'text-anchor', 'end'); - break; - } - - } catch(e) { - //console.log(e); - this._isChanged = true; - } - - - if(this.isVisible) { - this.node.removeAttributeNS(null, 'visibility'); - } - - - // Finished - delete this._isUpdating; - - // Raise change event - (this.changeCallbacks||[]).each(function(fn){ - fn.apply(fn); - }) - - }, - - /** - * Returns the text length of the text content of an SVG tspan element. - * For all browsers but Firefox 3 the values are estimated. - * @param {TSpanSVGElement} tspan - * @param {int} startIndex Optional, for sub strings - * @param {int} endIndex Optional, for sub strings - */ - _getRenderedTextLength: function(tspan, startIndex, endIndex, fontSize) { - //if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent) && new Number(RegExp.$1) >= 3) { - if(startIndex === undefined) { -//test string: abcdefghijklmnopqrstuvwxyz????????????????,.-#+ 1234567890?????ABCDEFGHIJKLMNOPQRSTUVWXYZ;:_'*???????????????!"????$%&/()=?[]{}|<>'~????`\^?????????@????????????????? -// for(var i = 0; i < tspan.textContent.length; i++) { -// console.log(tspan.textContent.charAt(i), tspan.getSubStringLength(i,1), this._estimateCharacterWidth(tspan.textContent.charAt(i))*(fontSize/14.0)); -// } - return tspan.getComputedTextLength(); - } else { - return tspan.getSubStringLength(startIndex, endIndex); - } - /*} else { - if(startIndex === undefined) { - return this._estimateTextWidth(tspan.textContent, fontSize); - } else { - return this._estimateTextWidth(tspan.textContent.substr(startIndex, endIndex).trim(), fontSize); - } - }*/ - }, - - /** - * Estimates the text width for a string. - * Used for word wrapping in all browser but FF3. - * @param {Object} text - */ - _estimateTextWidth: function(text, fontSize) { - var sum = 0.0; - for(var i = 0; i < text.length; i++) { - sum += this._estimateCharacterWidth(text.charAt(i)); - } - - return sum*(fontSize/14.0); - }, - - /** - * Estimates the width of a single character for font size 14. - * Used for word wrapping in all browser but FF3. - * @param {Object} character - */ - _estimateCharacterWidth: function(character) { - for(var i = 0; i < this._characterSets.length; i++) { - if(this._characterSets[i].indexOf(character) >= 0) { - return this._characterSetValues[i]; - } - } - return 9; - }, - - getReferencedElementWidth: function() { - var refNode = this.node.ownerDocument.getElementById(this.fitToElemId); - - if(refNode) { - var refbb = refNode.getBBox(); - - if(refbb) { - return (this._rotate != 0 - && this._rotate % 180 != 0 - && this._rotate % 90 == 0 ? - refbb.height : refbb.width); - } - } - - return undefined; - }, - - /** - * If no parameter is provided, this method returns the current text. - * @param text {String} Optional. Replaces the old text with this one. - */ - text: function() { - switch (arguments.length) { - case 0: - return this._text - break; - - case 1: - var oldText = this._text; - if(arguments[0]) { - // Filter out multiple spaces to fix issue in chrome for line-wrapping - this._text = arguments[0].toString(); - if(this._text != null && this._text != undefined) { - this._text = this._text.replace(/ {2,}/g,' '); - } - } else { - this._text = ""; - } - if(oldText !== this._text) { - this._isChanged = true; - this._textHasChanged = true; - } - break; - - default: - //TODO error - break; - } - }, - - getOriginVerticalAlign: function(){ - return this._originVerticalAlign; - }, - - verticalAlign: function() { - switch(arguments.length) { - case 0: - return this._verticalAlign; - case 1: - if(['top', 'middle', 'bottom'].member(arguments[0])) { - var oldValue = this._verticalAlign; - this._verticalAlign = arguments[0]; - if(this._verticalAlign !== oldValue) { - this._isChanged = true; - } - } - break; - - default: - //TODO error - break; - } - }, - - getOriginHorizontalAlign: function(){ - return this._originHorizontalAlign; - }, - - horizontalAlign: function() { - switch(arguments.length) { - case 0: - return this._horizontalAlign; - case 1: - if(['left', 'center', 'right'].member(arguments[0])) { - var oldValue = this._horizontalAlign; - this._horizontalAlign = arguments[0]; - if(this._horizontalAlign !== oldValue) { - this._isChanged = true; - } - } - break; - - default: - //TODO error - break; - } - }, - - rotate: function() { - switch(arguments.length) { - case 0: - return this._rotate; - case 1: - if (this._rotate != arguments[0]) { - this._rotate = arguments[0]; - this._rotationPoint = undefined; - this._isChanged = true; - } - case 2: - if(this._rotate != arguments[0] || - !this._rotationPoint || - this._rotationPoint.x != arguments[1].x || - this._rotationPoint.y != arguments[1].y) { - this._rotate = arguments[0]; - this._rotationPoint = arguments[1]; - this._isChanged = true; - } - - } - }, - - hide: function() { - if(this.isVisible) { - this.isVisible = false; - this._isChanged = true; - } - }, - - show: function() { - if(!this.isVisible) { - this.isVisible = true; - this._isChanged = true; - - // Since text is removed from the tspan when "hidden", mark - // the text as changed to get it redrawn - this._textHasChanged = true; - } - }, - - /** - * iterates parent nodes till it finds a SVG font-size - * attribute. - * @param {SVGElement} node - */ - getInheritedFontSize: function(node) { - if(!node || !node.getAttributeNS) - return; - - var attr = node.getAttributeNS(null, "font-size"); - if(attr) { - return parseFloat(attr); - } else if(!ORYX.Editor.checkClassType(node, SVGSVGElement)) { - return this.getInheritedFontSize(node.parentNode); - } - }, - - getFontSize: function(node) { - var tspans = this.node.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'tspan'); - - //trying to get an inherited font-size attribute - //NO CSS CONSIDERED! - var fontSize = this.getInheritedFontSize(this.node); - - if (!fontSize) { - //because this only works in firefox 3, all other browser use the default line height - if (tspans[0] && /Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent) && new Number(RegExp.$1) >= 3) { - fontSize = tspans[0].getExtentOfChar(0).height; - } - else { - fontSize = ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT; - } - - //handling of unsupported method in webkit - if (fontSize <= 0) { - fontSize = ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT; - } - } - - if(fontSize) - this.node.setAttribute("oryx:fontSize", fontSize); - - return fontSize; - }, - - /** - * Get trimmed text length for use with - * getExtentOfChar and getSubStringLength. - * @param {String} text - */ - getTrimmedTextLength: function(text) { - text = text.strip().gsub(' ', ' '); - - var oldLength; - do { - oldLength = text.length; - text = text.gsub(' ', ' '); - } while (oldLength > text.length); - - return text.length; - }, - - /** - * Returns the offset from - * edge to the label which is - * positioned under the edge - * @return {int} - */ - getOffsetBottom: function(){ - return this.offsetBottom; - }, - - - /** - * Returns the offset from - * edge to the label which is - * positioned over the edge - * @return {int} - */ - getOffsetTop: function(){ - return this.offsetTop; - }, - - /** - * - * @param {Object} obj - */ - deserialize: function(obj, shape){ - if (obj && "undefined" != typeof obj.x && "undefined" != typeof obj.y){ - this.setPosition({x:obj.x, y:obj.y}); - - if ("undefined" != typeof obj.distance){ - var from = shape.dockers[obj.from]; - var to = shape.dockers[obj.to]; - if (from && to){ - this.setReferencePoint({ - dirty : true, - distance : obj.distance, - intersection : {x: obj.x, y: obj.y}, - orientation : obj.orientation, - segment: { - from: from, - fromIndex: obj.from, - fromPosition: from.bounds.center(), - to: to, - toIndex: obj.to, - toPosition: to.bounds.center() - } - }) - } - } - - if (obj.left) this.anchorLeft = true; - if (obj.right) this.anchorRight = true; - if (obj.top) this.anchorTop = true; - if (obj.bottom) this.anchorBottom = true; - if (obj.valign) this.verticalAlign(obj.valign); - if (obj.align) this.horizontalAlign(obj.align); - - } else if (obj && "undefined" != typeof obj.edge){ - this.setEdgePosition(obj.edge); - } - }, +// oryx constants. +var ORYX_LOGLEVEL_TRACE = 5; +var ORYX_LOGLEVEL_DEBUG = 4; +var ORYX_LOGLEVEL_INFO = 3; +var ORYX_LOGLEVEL_WARN = 2; +var ORYX_LOGLEVEL_ERROR = 1; +var ORYX_LOGLEVEL_FATAL = 0; +var ORYX_LOGLEVEL = 3; +var ORYX_CONFIGURATION_DELAY = 100; +var ORYX_CONFIGURATION_WAIT_ATTEMPTS = 10; - /** - * - * @return {Object} - */ - serialize: function(){ - - // On edge position - if (this.getEdgePosition()){ - if (this.getOriginEdgePosition() !== this.getEdgePosition()){ - return {edge: this.getEdgePosition()}; - } else { - return null; - } - } - - // On self defined position - if (this.position){ - var pos = {x: this.position.x, y: this.position.y}; - if (this.isAnchorLeft() && this.isAnchorLeft() !== this.isOriginAnchorLeft()){ - pos.left = true; - } - if (this.isAnchorRight() && this.isAnchorRight() !== this.isOriginAnchorRight()){ - pos.right = true; - } - if (this.isAnchorTop() && this.isAnchorTop() !== this.isOriginAnchorTop()){ - pos.top = true; - } - if (this.isAnchorBottom() && this.isAnchorBottom() !== this.isOriginAnchorBottom()){ - pos.bottom = true; - } - - if (this.getOriginVerticalAlign() !== this.verticalAlign()){ - pos.valign = this.verticalAlign(); - } - if (this.getOriginHorizontalAlign() !== this.horizontalAlign()){ - pos.align = this.horizontalAlign(); - } - - return pos; - } - - // On reference point which is interesting for edges - if (this.getReferencePoint()){ - var ref = this.getReferencePoint(); - return { - distance : ref.distance, - x : ref.intersection.x, - y : ref.intersection.y, - from : ref.segment.fromIndex, - to : ref.segment.toIndex, - orientation : ref.orientation, - valign : this.verticalAlign(), - align : this.horizontalAlign() - } - } - return null; - }, - - toString: function() { return "Label " + this.id } - });/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ +if (!ORYX) var ORYX = {}; -/** - * Init namespaces - */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} -if(!ORYX.Core.Math) {ORYX.Core.Math = {};} - -/** - * Calculate the middle point between two given points - * @param {x:double, y:double} point1 - * @param {x:double, y:double} point2 - * @return the middle point - */ -ORYX.Core.Math.midPoint = function(point1, point2) { - return { - x: (point1.x + point2.x) / 2.0, - y: (point1.y + point2.y) / 2.0 - } -} - -/** - * Returns a TRUE if the point is over a line (defined by - * point1 and point 2). In Addition a threshold can be set, - * which defines the weight of those line. - * - * @param {int} pointX - Point X - * @param {int} pointY - Point Y - * @param {int} lPoint1X - Line first Point X - * @param {int} lPoint1Y - Line first Point Y - * @param {int} lPoint2X - Line second Point X - * @param {int} lPoint2Y - Line second Point y - * @param {int} offset {optional} - maximal distance to line - * @class ORYX.Core.Math.prototype - */ -ORYX.Core.Math.isPointInLine = function (pointX, pointY, lPoint1X, lPoint1Y, lPoint2X, lPoint2Y, offset) { +ORYX = Object.extend(ORYX, { - offset = offset ? Math.abs(offset) : 1; - - // Check if the edge is vertical - if(Math.abs(lPoint1X-lPoint2X)<=offset && Math.abs(pointX-lPoint1X)<=offset && pointY-Math.max(lPoint1Y, lPoint2Y)<=offset && Math.min(lPoint1Y, lPoint2Y)-pointY<=offset) { - return true - } - - // Check if the edge is horizontal - if(Math.abs(lPoint1Y-lPoint2Y)<=offset && Math.abs(pointY-lPoint1Y)<=offset && pointX-Math.max(lPoint1X, lPoint2X)<=offset && Math.min(lPoint1X, lPoint2X)-pointX<=offset) { - return true - } - - if(pointX > Math.max(lPoint1X, lPoint2X) || pointX < Math.min(lPoint1X, lPoint2X)) { - return false - } - - if(pointY > Math.max(lPoint1Y, lPoint2Y) || pointY < Math.min(lPoint1Y, lPoint2Y)) { - return false - } - - var s = (lPoint1Y - lPoint2Y) / (lPoint1X - lPoint2X); - - return Math.abs(pointY - ((s * pointX) + lPoint1Y - s * lPoint1X)) < offset -} + //set the path in the config.js file!!!! + PATH: ORYX.CONFIG.ROOT_PATH, + //CONFIGURATION: "config.js", -/** - * Get a boolean if the point is in the polygone - * - */ -ORYX.Core.Math.isPointInEllipse = function (pointX, pointY, cx, cy, rx, ry) { + URLS: [], - if(cx === undefined || cy === undefined || rx === undefined || ry === undefined) { - throw "ORYX.Core.Math.isPointInEllipse needs a ellipse with these properties: x, y, radiusX, radiusY" - } - - var tx = (pointX - cx) / rx; - var ty = (pointY - cy) / ry; - - return tx * tx + ty * ty < 1.0; -} - -/** - * Get a boolean if the point is in the polygone - * @param {int} pointX - * @param {int} pointY - * @param {[int]} Cornerpoints of the Polygone (x,y,x,y,...) - */ -ORYX.Core.Math.isPointInPolygone = function(pointX, pointY, polygone){ - - if (arguments.length < 3) { - throw "ORYX.Core.Math.isPointInPolygone needs two arguments" - } - - var lastIndex = polygone.length-1; - - if (polygone[0] !== polygone[lastIndex - 1] || polygone[1] !== polygone[lastIndex]) { - polygone.push(polygone[0]); - polygone.push(polygone[1]); - } - - var crossings = 0; - - var x1, y1, x2, y2, d; - - for (var i = 0; i < polygone.length - 3; ) { - x1=polygone[i]; - y1=polygone[++i]; - x2=polygone[++i]; - y2=polygone[i+1]; - d=(pointY - y1) * (x2 - x1) - (pointX - x1) * (y2 - y1); + alreadyLoaded: [], - if ((y1 >= pointY) != (y2 >= pointY)) { - crossings += y2 - y1 >= 0 ? d >= 0 : d <= 0; - } - if (!d && Math.min(x1,x2) <= pointX && pointX <= Math.max(x1,x2) - && Math.min(y1,y2) <= pointY && pointY <= Math.max(y1,y2)) { - return true; - } - } - return (crossings%2)?true:false; -} + configrationRetries: 0, -/** - * Calculates the distance between a point and a line. It is also testable, if - * the distance orthogonal to the line, matches the segment of the line. - * - * @param {float} lineP1 - * The starting point of the line segment - * @param {float} lineP2 - * The end point of the line segment - * @param {Point} point - * The point to calculate the distance to. - * @param {boolean} toSegmentOnly - * Flag to signal if only the segment of the line shell be evaluated. - */ -ORYX.Core.Math.distancePointLinie = function( - lineP1, - lineP2, - point, - toSegmentOnly) { - - var intersectionPoint = - ORYX.Core.Math.getPointOfIntersectionPointLine(lineP1, - lineP2, - point, - toSegmentOnly); - - if(!intersectionPoint) { - return null; - } - - return ORYX.Core.Math.getDistancePointToPoint(point, intersectionPoint); -}; + Version: '0.1.1', -/** - * Calculates the distance between two points. - * - * @param {point} point1 - * @param {point} point2 - */ -ORYX.Core.Math.getDistancePointToPoint = function(point1, point2) { - return Math.sqrt(Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2)); -}; + availablePlugins: [], -/** - * Calculates the relative distance of a point which is between two other points. - * - * @param {point} between1 - * @param {point} between2 - * @param {point} point - */ -ORYX.Core.Math.getDistanceBetweenTwoPoints = function(between1, between2, point) { - return ORYX.Core.Math.getDistancePointToPoint(point, between1) / - ORYX.Core.Math.getDistancePointToPoint(between1, between2); -}; + /** + * The ORYX.Log logger. + */ + Log: { + __appenders: [ + { + append: function (message) { + if (typeof (console) !== "undefined" && console.log !== undefined) { + } + } + } + ], -/** - * Returns true, if the point is of the left hand - * side of the regarding the line. - * - * @param {point} lineP1 Line first point - * @param {point} lineP2 Line second point - * @param {point} point - */ -ORYX.Core.Math.pointIsLeftOfLine = function(lineP1, lineP2, point){ - - var vec1 = ORYX.Core.Math.getVector(lineP1, lineP2); - var vec2 = ORYX.Core.Math.getVector(lineP1, point); - // if the cross produkt is more than 0 - return ((vec1.x*vec2.y) - (vec2.x*vec1.y)) > 0 -}; + trace: function () { + if (ORYX_LOGLEVEL >= ORYX_LOGLEVEL_TRACE) + ORYX.Log.__log('TRACE', arguments); + }, + debug: function () { + if (ORYX_LOGLEVEL >= ORYX_LOGLEVEL_DEBUG) + ORYX.Log.__log('DEBUG', arguments); + }, + info: function () { + if (ORYX_LOGLEVEL >= ORYX_LOGLEVEL_INFO) + ORYX.Log.__log('INFO', arguments); + }, + warn: function () { + if (ORYX_LOGLEVEL >= ORYX_LOGLEVEL_WARN) + ORYX.Log.__log('WARN', arguments); + }, + error: function () { + if (ORYX_LOGLEVEL >= ORYX_LOGLEVEL_ERROR) + ORYX.Log.__log('ERROR', arguments); + }, + fatal: function () { + if (ORYX_LOGLEVEL >= ORYX_LOGLEVEL_FATAL) + ORYX.Log.__log('FATAL', arguments); + }, -/** - * Calculates the a point which is relatively between two other points. - * - * @param {point} point1 - * @param {point} point2 - * @param {number} relative Relative which is between 0 and 1 - */ -ORYX.Core.Math.getPointBetweenTwoPoints = function(point1, point2, relative) { - relative = Math.max(Math.min(relative || 0, 1), 0); - - if (relative === 0){ - return point1; - } else if (relative === 1){ - return point2; - } - - return { - x: point1.x + ((point2.x - point1.x) * relative), - y: point1.y + ((point2.y - point1.y) * relative) - } -}; + __log: function (prefix, messageParts) { + messageParts[0] = (new Date()).getTime() + " " + + prefix + " " + messageParts[0]; + var message = printf.apply(null, messageParts); -/** - * Returns the vector of the both points - * - * @param {point} point1 - * @param {point} point2 - */ -ORYX.Core.Math.getVector = function(point1, point2){ - return { - x: point2.x - point1.x, - y: point2.y - point1.y - } -} + ORYX.Log.__appenders.each(function (appender) { + appender.append(message); + }); + }, -/** - * Returns the an identity vector of the given vector, - * which has the length ot one. - * - * @param {point} vector - * or - * @param {point} point1 - * @param {point} point2 - */ -ORYX.Core.Math.getIdentityVector = function(vector){ - - if (arguments.length == 2){ - vector = ORYX.Core.Math.getVector(arguments[0], arguments[1]); - } - - var length = Math.sqrt((vector.x*vector.x)+(vector.y*vector.y)) - return { - x: vector.x / (length || 1), - y: vector.y / (length || 1) - } -} + addAppender: function (appender) { + ORYX.Log.__appenders.push(appender); + } + }, + /** + * First bootstrapping layer. The Oryx loading procedure begins. In this + * step, all preliminaries that are not in the responsibility of Oryx to be + * met have to be checked here, such as the existance of the prototpe + * library in the current execution environment. After that, the second + * bootstrapping layer is being invoked. Failing to ensure that any + * preliminary condition is not met has to fail with an error. + */ + load: function () { -ORYX.Core.Math.getOrthogonalIdentityVector = function(point1, point2){ - var vec = arguments.length == 1 ? point1 : ORYX.Core.Math.getIdentityVector(point1, point2); - return { - x: vec.y, - y: -vec.x - } -} + ORYX.Log.debug("Oryx begins loading procedure."); + // check for prototype + if ((typeof Prototype == 'undefined') || + (typeof Element == 'undefined') || + (typeof Element.Methods == 'undefined') || + parseFloat(Prototype.Version.split(".")[0] + "." + + Prototype.Version.split(".")[1]) < 1.5) -/** - * Returns the intersection point of a line and a point that defines a line - * orthogonal to the given line. - * - * @param {float} lineP1 - * The starting point of the line segment - * @param {float} lineP2 - * The end point of the line segment - * @param {Point} point - * The point to calculate the distance to. - * @param {boolean} onSegmentOnly - * Flag to signal if only the segment of the line shell be evaluated. - */ -ORYX.Core.Math.getPointOfIntersectionPointLine = function( - lineP1, - lineP2, - point, - onSegmentOnly) { + throw("Application requires the Prototype JavaScript framework >= 1.5.3"); - /* - * [P3 - P1 - u(P2 - P1)] dot (P2 - P1) = 0 - * u =((x3-x1)(x2-x1)+(y3-y1)(y2-y1))/(p2-p1)?? - */ - var denominator = Math.pow(lineP2.x - lineP1.x, 2) - + Math.pow(lineP2.y - lineP1.y, 2); - if(denominator == 0) { - return undefined; - } - - var u = ((point.x - lineP1.x) * (lineP2.x - lineP1.x) - + (point.y - lineP1.y) * (lineP2.y - lineP1.y)) - / denominator; - - if(onSegmentOnly) { - if (!(0 <= u && u <= 1)) { - return undefined; - } - } - - pointOfIntersection = new Object(); - pointOfIntersection.x = lineP1.x + u * (lineP2.x - lineP1.x); - pointOfIntersection.y = lineP1.y + u * (lineP2.y - lineP1.y); - - return pointOfIntersection; -}; + ORYX.Log.debug("Prototype > 1.5 found."); -/** - * Translated the point with the given matrix. - * @param {Point} point - * @param {Matrix} matrix - * @return {Object} Includes x, y - */ -ORYX.Core.Math.getTranslatedPoint = function(point, matrix){ - var x = matrix.a*point.x+matrix.c*point.y+matrix.e*1; - var y = matrix.b*point.x+matrix.d*point.y+matrix.f*1; - return {x:x, y:y} -} + // continue loading. + ORYX._load(); + }, + /** + * Second bootstrapping layer. The oryx configuration is checked. When not + * yet loaded, config.js is being requested from the server. A repeated + * error in retrieving the configuration will result in an error to be + * thrown after a certain time of retries. Once the configuration is there, + * all urls that are registered with oryx loading are being requested from + * the server. Once everything is loaded, the third layer is being invoked. + */ + _load: function () { + /* + // if configuration not there already, + if(!(ORYX.CONFIG)) { -/** - * Returns the inverse matrix of the given SVG transformation matrix - * @param {SVGTransformationMatrix} matrix - * @return {Matrix} - */ -ORYX.Core.Math.getInverseMatrix = function(matrix){ - - var det = ORYX.Core.Math.getDeterminant(matrix), m = matrix; - // +- -+ - // | a c e | - // | b d f | - // | 0 0 1 | - // +- -+ - return { - a: det * ((m.d*1)-(m.f*0)), - b: det * ((m.f*0)-(m.b*1)), - c: det * ((m.e*0)-(m.c*1)), - d: det * ((m.a*1)-(m.e*0)), - e: det * ((m.c*m.f)-(m.e*m.d)), - f: det * ((m.e*m.b)-(m.a*m.f)) - } -} + // if this is the first attempt... + if(ORYX.configrationRetries == 0) { -/** - * Returns the determinant of the svg transformation matrix - * @param {SVGTranformationMatrix} matrix - * @return {Number} - * - */ -ORYX.Core.Math.getDeterminant = function(m){ - // a11a22a33+a12a23a31+a13a21a32-a13a22a31-a12a21a33-a11a23a32 - return (m.a*m.d*1)+(m.c*m.f*0)+(m.e*m.b*0)-(m.e*m.d*0)-(m.c*m.b*1)-(m.a*m.f*0); -} + // get the path and filename. + var configuration = ORYX.PATH + ORYX.CONFIGURATION; -/** - * Returns the bounding box of the given node. Translates the - * origin bounding box with the tranlation matrix. - * @param {SVGElement} node - * @return {Object} Includes x, y, width, height - */ -ORYX.Core.Math.getTranslatedBoundingBox = function(node){ - var matrix = node.getCTM(); - var bb = node.getBBox(); - var ul = ORYX.Core.Math.getTranslatedPoint({x:bb.x, y:bb.y}, matrix); - var ll = ORYX.Core.Math.getTranslatedPoint({x:bb.x, y:bb.y+bb.height}, matrix); - var ur = ORYX.Core.Math.getTranslatedPoint({x:bb.x+bb.width, y:bb.y}, matrix); - var lr = ORYX.Core.Math.getTranslatedPoint({x:bb.x+bb.width, y:bb.y+bb.height}, matrix); - - var minPoint = { - x: Math.min(ul.x, ll.x, ur.x, lr.x), - y: Math.min(ul.y, ll.y, ur.y, lr.y) - } - var maxPoint = { - x: Math.max(ul.x, ll.x, ur.x, lr.x), - y: Math.max(ul.y, ll.y, ur.y, lr.y) - } - return { - x: minPoint.x, - y: minPoint.y, - width: maxPoint.x - minPoint.x, - height: maxPoint.y - minPoint.y - } -}; + ORYX.Log.debug("Configuration not found, loading from '%0'.", + configuration); + // require configuration file. + Kickstart.require(configuration); -/** - * Returns the angle of the given line, which is representated by the two points - * @param {Point} p1 - * @param {Point} p2 - * @return {Number} 0 <= x <= 359.99999 - */ -ORYX.Core.Math.getAngle = function(p1, p2){ - if(p1.x == p2.x && p1.y == p2.y) - return 0; - - var angle = Math.asin(Math.sqrt(Math.pow(p1.y-p2.y, 2)) - /(Math.sqrt(Math.pow(p2.x-p1.x, 2)+Math.pow(p1.y-p2.y, 2)))) - *180/Math.PI; - - if(p2.x >= p1.x && p2.y <= p1.y) - return angle; - else if(p2.x < p1.x && p2.y <= p1.y) - return 180 - angle; - else if(p2.x < p1.x && p2.y > p1.y) - return 180 + angle; - else - return 360 - angle; -}; + // else if attempts exceeded ... + } else if(ORYX.configrationRetries >= ORYX_CONFIGURATION_WAIT_ATTEMPTS) { + throw "Tried to get configuration" + + ORYX_CONFIGURATION_WAIT_ATTEMPTS + + " times from '" + configuration + "'. Giving up." -/** - * Implementation of the cohen-sutherland algorithm - */ -new function(){ - - var RIGHT = 2, TOP = 8, BOTTOM = 4, LEFT = 1; - - function computeOutCode (x, y, xmin, ymin, xmax, ymax) { - var code = 0; - if (y > ymax) - code |= TOP; - else if (y < ymin) - code |= BOTTOM; - if (x > xmax) - code |= RIGHT; - else if (x < xmin) - code |= LEFT; - return code; - } - - /** - * Returns TRUE if the rectangle is over the edge and has intersection points or includes it - * @param {Object} x1 Point A of the line - * @param {Object} y1 - * @param {Object} x2 Point B of the line - * @param {Object} y2 - * @param {Object} xmin Point A of the rectangle - * @param {Object} ymin - * @param {Object} xmax Point B of the rectangle - * @param {Object} ymax - */ - ORYX.Core.Math.isRectOverLine = function(x1, y1, x2, y2, xmin, ymin, xmax, ymax){ - return !!ORYX.Core.Math.clipLineOnRect.apply(ORYX.Core.Math, arguments); - } - - /** - * Returns the clipped line on the given rectangle. If there is - * no intersection, it will return NULL. - * - * @param {Object} x1 Point A of the line - * @param {Object} y1 - * @param {Object} x2 Point B of the line - * @param {Object} y2 - * @param {Object} xmin Point A of the rectangle - * @param {Object} ymin - * @param {Object} xmax Point B of the rectangle - * @param {Object} ymax - */ - ORYX.Core.Math.clipLineOnRect = function(x1, y1, x2, y2, xmin, ymin, xmax, ymax){ - //Outcodes for P0, P1, and whatever point lies outside the clip rectangle - var outcode0, outcode1, outcodeOut, hhh = 0; - var accept = false, done = false; - - //compute outcodes - outcode0 = computeOutCode(x1, y1, xmin, ymin, xmax, ymax); - outcode1 = computeOutCode(x2, y2, xmin, ymin, xmax, ymax); - - do { - if ((outcode0 | outcode1) == 0 ){ - accept = true; - done = true; - } else if ( (outcode0 & outcode1) > 0 ) { - done = true; - } else { - //failed both tests, so calculate the line segment to clip - //from an outside point to an intersection with clip edge - var x = 0, y = 0; - //At least one endpoint is outside the clip rectangle; pick it. - outcodeOut = outcode0 != 0 ? outcode0: outcode1; - //Now find the intersection point; - //use formulas y = y0 + slope * (x - x0), x = x0 + (1/slope)* (y - y0) - if ( (outcodeOut & TOP) > 0 ) { - x = x1 + (x2 - x1) * (ymax - y1)/(y2 - y1); - y = ymax; - } else if ((outcodeOut & BOTTOM) > 0 ) { - x = x1 + (x2 - x1) * (ymin - y1)/(y2 - y1); - y = ymin; - } else if ((outcodeOut & RIGHT)> 0) { - y = y1 + (y2 - y1) * (xmax - x1)/(x2 - x1); - x = xmax; - } else if ((outcodeOut & LEFT) > 0) { - y = y1 + (y2 - y1) * (xmin - x1)/(x2 - x1); - x = xmin; - } - - //Now we move outside point to intersection point to clip - //and get ready for next pass. - if (outcodeOut == outcode0) { - x1 = x; - y1 = y; - outcode0 = computeOutCode (x1, y1, xmin, ymin, xmax, ymax); - } else { - x2 = x; - y2 = y; - outcode1 = computeOutCode (x2, y2, xmin, ymin, xmax, ymax); - } - } - hhh ++; - } while (done != true && hhh < 5000); - - if(accept) { - return {a:{x:x1, y:y1}, b:{x:x2, y:y2}}; - } - return null; - } -}(); + } else if(ORYX.configrationRetries > 0){ + // point out how many attempts are left... + ORYX.Log.debug("Waiting once more (%0 attempts left)", + (ORYX_CONFIGURATION_WAIT_ATTEMPTS - + ORYX.configrationRetries)); -/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + } -/** - * Init namespace - */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} -if(!ORYX.Core.StencilSet) {ORYX.Core.StencilSet = {};} + // any case: continue in a moment with increased retry count. + ORYX.configrationRetries++; + window.setTimeout(ORYX._load, ORYX_CONFIGURATION_DELAY); + return; + } -/** - * Class Stencil - * uses Prototpye 1.5.0 - * uses Inheritance - * - * This class represents one stencil of a stencil set. - */ -ORYX.Core.StencilSet.Stencil = { + ORYX.Log.info("Configuration loaded."); - /** - * Constructor - */ - construct: function(jsonStencil, namespace, source, stencilSet, propertyPackages, defaultPosition) { - arguments.callee.$.construct.apply(this, arguments); // super(); - - // check arguments and set defaults. - if(!jsonStencil) throw "Stencilset seems corrupt."; - if(!namespace) throw "Stencil does not provide namespace."; - if(!source) throw "Stencil does not provide SVG source."; - if(!stencilSet) throw "Fatal internal error loading stencilset."; - //if(!propertyPackages) throw "Fatal internal error loading stencilset."; - - this._source = source; - this._jsonStencil = jsonStencil; - this._stencilSet = stencilSet; - this._namespace = namespace; - this._propertyPackages = propertyPackages; - - if(defaultPosition && !this._jsonStencil.position) - this._jsonStencil.position = defaultPosition; - - this._view; - this._properties = new Hash(); - - // check stencil consistency and set defaults. - /*with(this._jsonStencil) { - - if(!type) throw "Stencil does not provide type."; - if((type != "edge") && (type != "node")) - throw "Stencil type must be 'edge' or 'node'."; - if(!id || id == "") throw "Stencil does not provide valid id."; - if(!title || title == "") - throw "Stencil does not provide title"; - if(!description) { description = ""; }; - if(!groups) { groups = []; } - if(!roles) { roles = []; } + // load necessary scripts. + ORYX.URLS.each(function(url) { + ORYX.Log.debug("Requireing '%0'", url); + Kickstart.require(ORYX.PATH + url) }); + */ + // configurate logging and load plugins. + ORYX.loadPlugins(); + }, - // add id of stencil to its roles - roles.push(id); - }*/ - - //init all JSON values - if(!this._jsonStencil.type || !(this._jsonStencil.type === "edge" || this._jsonStencil.type === "node")) { - throw "ORYX.Core.StencilSet.Stencil(construct): Type is not defined."; - } - if(!this._jsonStencil.id || this._jsonStencil.id === "") { - throw "ORYX.Core.StencilSet.Stencil(construct): Id is not defined."; - } - if(!this._jsonStencil.title || this._jsonStencil.title === "") { - throw "ORYX.Core.StencilSet.Stencil(construct): Title is not defined."; - } + /** + * Third bootstrapping layer. This is where first the plugin coniguration + * file is loaded into oryx, analyzed, and where all plugins are being + * requested by the server. Afterwards, all editor instances will be + * initialized. + */ + loadPlugins: function () { - if(!this._jsonStencil.description) { this._jsonStencil.description = ""; }; - if(!this._jsonStencil.groups) { this._jsonStencil.groups = []; } - if(!this._jsonStencil.roles) { this._jsonStencil.roles = []; } - - //add id of stencil to its roles - this._jsonStencil.roles.push(this._jsonStencil.id); + // load plugins if enabled. + if (ORYX.CONFIG.PLUGINS_ENABLED) + ORYX._loadPlugins() + else + ORYX.Log.warn("Ignoring plugins, loading Core only."); - //prepend namespace to each role - this._jsonStencil.roles.each((function(role, index) { - this._jsonStencil.roles[index] = namespace + role; - }).bind(this)); + // init the editor instances. + init(); + }, - //delete duplicate roles - this._jsonStencil.roles = this._jsonStencil.roles.uniq(); + _loadPlugins: function () { - //make id unique by prepending namespace of stencil set - this._jsonStencil.id = namespace + this._jsonStencil.id; + // load plugin configuration file. + var source = ORYX.CONFIG.PLUGINS_CONFIG; - this.postProcessProperties(); - - // init serialize callback - if(!this._jsonStencil.serialize) { - this._jsonStencil.serialize = {}; - //this._jsonStencil.serialize = function(shape, data) { return data;}; - } - - // init deserialize callback - if(!this._jsonStencil.deserialize) { - this._jsonStencil.deserialize = {}; - //this._jsonStencil.deserialize = function(shape, data) { return data;}; - } - - // init layout callback - if(!this._jsonStencil.layout) { - this._jsonStencil.layout = [] - //this._jsonStencil.layout = function() {return true;} - } - - //TODO does not work correctly, if the url does not exist - //How to guarantee that the view is loaded correctly before leaving the constructor??? - var url = source + "view/" + jsonStencil.view; - // override content type when this is webkit. - - if(this._jsonStencil.view.trim().match(/ 0) { + globalProperties.push(property) + } + ; + }); + }); - title: function() { - return ORYX.Core.StencilSet.getTranslation(this._jsonStencil, "title"); - }, - description: function() { - return ORYX.Core.StencilSet.getTranslation(this._jsonStencil, "description"); - }, - - groups: function() { - return ORYX.Core.StencilSet.getTranslation(this._jsonStencil, "groups"); - }, - - position: function() { - return (isNaN(this._jsonStencil.position) ? 0 : this._jsonStencil.position); - }, + // TODO Why are we using XML if we don't respect structure anyway? + // for each plugin element in the configuration.. + var plugin = resultXml.getElementsByTagName("plugin"); + $A(plugin).each(function (node) { - view: function() { - return this._view.cloneNode(true) || this._view; - }, + // get all element's attributes. + // TODO: What about: var pluginData = $H(node.attributes) !? + var pluginData = new Hash(); + $A(node.attributes).each(function (attr) { + pluginData[attr.nodeName] = attr.nodeValue + }); - icon: function() { - return this._jsonStencil.icon; - }, - - fixedAspectRatio: function() { - return this._jsonStencil.fixedAspectRatio === true; - }, - - hasMultipleRepositoryEntries: function() { - return (this.getRepositoryEntries().length > 0); - }, - - getRepositoryEntries: function() { - return (this._jsonStencil.repositoryEntries) ? - $A(this._jsonStencil.repositoryEntries) : $A([]); - }, - - properties: function() { - return this._properties.values(); - }, + // ensure there's a name attribute. + if (!pluginData['name']) { + ORYX.Log.error("A plugin is not providing a name. Ingnoring this plugin."); + return; + } - property: function(id) { - return this._properties[id]; - }, + // ensure there's a source attribute. + if (!pluginData['source']) { + ORYX.Log.error("Plugin with name '%0' doesn't provide a source attribute.", pluginData['name']); + return; + } - roles: function() { - return this._jsonStencil.roles; - }, - - defaultAlign: function() { - if(!this._jsonStencil.defaultAlign) - return "east"; - return this._jsonStencil.defaultAlign; - }, + // Get all private Properties + var propertyNodes = node.getElementsByTagName("property"); + var properties = []; + $A(propertyNodes).each(function (prop) { + var property = new Hash(); - serialize: function(shape, data) { - return this._jsonStencil.serialize; - //return this._jsonStencil.serialize(shape, data); - }, - - deserialize: function(shape, data) { - return this._jsonStencil.deserialize; - //return this._jsonStencil.deserialize(shape, data); - }, - - // in which case is targetShape used? -// layout: function(shape, targetShape) { -// return this._jsonStencil.layout(shape, targetShape); -// }, - // layout property to store events for layouting in plugins - layout: function(shape) { - return this._jsonStencil.layout - }, - - addProperty: function(property, namespace) { - if(property && namespace) { - var oProp = new ORYX.Core.StencilSet.Property(property, namespace, this); - this._properties[oProp.prefix() + "-" + oProp.id()] = oProp; - } - }, - - removeProperty: function(propertyId) { - if(propertyId) { - var oProp = this._properties.values().find(function(prop) { - return (propertyId == prop.id()); - }); - if(oProp) - delete this._properties[oProp.prefix() + "-" + oProp.id()]; - } - }, + // Get all Attributes from the Node + var attributes = $A(prop.attributes) + attributes.each(function (attr) { + property[attr.nodeName] = attr.nodeValue + }); + if (attributes.length > 0) { + properties.push(property) + } + ; - _loadSVGOnSuccess: function(result) { - - var xml = null; - - /* - * We want to get a dom object for the requested file. Unfortunately, - * safari has some issues here. this is meant as a fallback for all - * browsers that don't recognize the svg mimetype as XML but support - * data: urls on Ajax calls. - */ - - // responseXML != undefined. - // if(!(result.responseXML)) - - // get the dom by data: url. - // xml = _evenMoreEvilHack(result.responseText, 'text/xml'); - - // else - - // get it the usual way. - xml = result.responseXML; - - //check if result is a SVG document - if( ORYX.Editor.checkClassType( xml.documentElement, SVGSVGElement )) { - - this._view = xml.documentElement; - - } else { - throw "ORYX.Core.StencilSet.Stencil(_loadSVGOnSuccess): The response is not a SVG document." - } - }, + }); - _loadSVGOnFailure: function(result) { - throw "ORYX.Core.StencilSet.Stencil(_loadSVGOnFailure): Loading SVG document failed." - }, + // Set all Global-Properties to the Properties + properties = properties.concat(globalProperties); - toString: function() { return "Stencil " + this.title() + " (" + this.id() + ")"; } -}; + // Set Properties to Plugin-Data + pluginData['properties'] = properties; -ORYX.Core.StencilSet.Stencil = Clazz.extend(ORYX.Core.StencilSet.Stencil); + // Get the RequieredNodes + var requireNodes = node.getElementsByTagName("requires"); + var requires; + $A(requireNodes).each(function (req) { + var namespace = $A(req.attributes).find(function (attr) { + return attr.name == "namespace" + }) + if (namespace && namespace.nodeValue) { + if (!requires) { + requires = {namespaces: []} + } -/** - * Transform a string into an xml document, the Safari way, as long as - * the nightlies are broken. Even more evil version. - * @param {Object} str - * @param {Object} contentType - */ -function _evenMoreEvilHack(str, contentType) { - - /* - * This even more evil hack was taken from - * http://web-graphics.com/mtarchive/001606.php#chatty004999 - */ - - if (window.ActiveXObject) { - var d = new ActiveXObject("MSXML.DomDocument"); - d.loadXML(str); - return d; - } else if (window.XMLHttpRequest) { - var req = new XMLHttpRequest; - req.open("GET", "data:" + (contentType || "application/xml") + - ";charset=utf-8," + encodeURIComponent(str), false); - if (req.overrideMimeType) { - req.overrideMimeType(contentType); - } - req.send(null); - return req.responseXML; - } -} + requires.namespaces.push(namespace.nodeValue) + } + }); -/** - * Transform a string into an xml document, the Safari way, as long as - * the nightlies are broken. - * @param {Object} result the xml document object. - */ -function _evilSafariHack(serializedXML) { - - /* - * The Dave way. Taken from: - * http://web-graphics.com/mtarchive/001606.php - * - * There is another possibility to parse XML in Safari, by implementing - * the DOMParser in javascript. However, in the latest nightlies of - * WebKit, DOMParser is already available, but still buggy. So, this is - * the best compromise for the time being. - */ - - var xml = serializedXML; - var url = "data:text/xml;charset=utf-8," + encodeURIComponent(xml); - var dom = null; - - // your standard AJAX stuff - var req = new XMLHttpRequest(); - req.open("GET", url); - req.onload = function() { dom = req.responseXML; } - req.send(null); - - return dom; -} - /* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + // Set Requires to the Plugin-Data, if there is one + if (requires) { + pluginData['requires'] = requires; + } -/** - * Init namespace - */ -if (!ORYX) { - var ORYX = {}; -} -if (!ORYX.Core) { - ORYX.Core = {}; -} -if (!ORYX.Core.StencilSet) { - ORYX.Core.StencilSet = {}; + + // Get the RequieredNodes + var notUsesInNodes = node.getElementsByTagName("notUsesIn"); + var notUsesIn; + $A(notUsesInNodes).each(function (not) { + var namespace = $A(not.attributes).find(function (attr) { + return attr.name == "namespace" + }) + if (namespace && namespace.nodeValue) { + if (!notUsesIn) { + notUsesIn = {namespaces: []} + } + + notUsesIn.namespaces.push(namespace.nodeValue) + } + }); + + // Set Requires to the Plugin-Data, if there is one + if (notUsesIn) { + pluginData['notUsesIn'] = notUsesIn; + } + + + var url = ORYX.PATH + ORYX.CONFIG.PLUGINS_FOLDER + pluginData['source']; + + ORYX.Log.debug("Requireing '%0'", url); + + // Add the Script-Tag to the Site + //Kickstart.require(url); + + ORYX.Log.info("Plugin '%0' successfully loaded.", pluginData['name']); + + // Add the Plugin-Data to all available Plugins + ORYX.availablePlugins.push(pluginData); + + }); + + }, + onFailure: this._loadPluginsOnFails + }); + + }, + + _loadPluginsOnFails: function (result) { + + ORYX.Log.error("Plugin configuration file not available."); + } +}); + + +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespaces + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} +if (!ORYX.Core.SVG) { + ORYX.Core.SVG = {}; } + /** - * Class Property - * uses Prototpye 1.5.0 - * uses Inheritance + * EditPathHandler + * + * Edit SVG paths' coordinates according to specified from-to movement and + * horizontal and vertical scaling factors. + * The resulting path's d attribute is stored in instance variable d. + * + * @constructor */ -ORYX.Core.StencilSet.Property = Clazz.extend({ +ORYX.Core.SVG.EditPathHandler = Clazz.extend({ + + construct: function () { + arguments.callee.$.construct.apply(this, arguments); + + this.x = 0; + this.y = 0; + this.oldX = 0; + this.oldY = 0; + this.deltaWidth = 1; + this.deltaHeight = 1; + + this.d = ""; + }, /** - * Constructor + * init + * + * @param {float} x Target point's x-coordinate + * @param {float} y Target point's y-coordinate + * @param {float} oldX Reference point's x-coordinate + * @param {float} oldY Reference point's y-coordinate + * @param {float} deltaWidth Horizontal scaling factor + * @param {float} deltaHeight Vertical scaling factor */ - construct: function(jsonProp, namespace, stencil){ - arguments.callee.$.construct.apply(this, arguments); - - this._jsonProp = jsonProp || ORYX.Log.error("Parameter jsonProp is not defined."); - this._namespace = namespace || ORYX.Log.error("Parameter namespace is not defined."); - this._stencil = stencil || ORYX.Log.error("Parameter stencil is not defined."); - - this._items = {}; - this._complexItems = {}; - - // Flag to indicate whether or not the property should be hidden - // This can be for example when the stencil set is upgraded, but the model - // has a value for that specific property filled in which we still want to show. - // If the value is missing, the property can simply be not shown. - this._hidden = false; - - jsonProp.id = jsonProp.id || ORYX.Log.error("ORYX.Core.StencilSet.Property(construct): Id is not defined."); - jsonProp.id = jsonProp.id.toLowerCase(); - - if (!jsonProp.type) { - ORYX.Log.info("Type is not defined for stencil '%0', id '%1'. Falling back to 'String'.", stencil, jsonProp.id); - jsonProp.type = "string"; - } - else { - jsonProp.type = jsonProp.type.toLowerCase(); - } - - jsonProp.prefix = jsonProp.prefix || "oryx"; - jsonProp.title = jsonProp.title || ""; - jsonProp.value = jsonProp.value || ""; - jsonProp.description = jsonProp.description || ""; - jsonProp.readonly = jsonProp.readonly || false; - jsonProp.optional = jsonProp.optional !== false; - - //init refToView - if (this._jsonProp.refToView) { - if (!(this._jsonProp.refToView instanceof Array)) { - this._jsonProp.refToView = [this._jsonProp.refToView]; - } - } - else { - this._jsonProp.refToView = []; - } - - var globalMin = this.getMinForType(jsonProp.type); - if (jsonProp.min === undefined || jsonProp.min === null) { - jsonProp.min =globalMin; - } else if (jsonProp.min < globalMin) { - jsonProp.min = globalMin; - } - - var globalMax = this.getMaxForType(jsonProp.type); - if (jsonProp.max === undefined || jsonProp.max === null) { - jsonProp.max = globalMax; - } else if (jsonProp.max > globalMax) { - jsonProp.min = globalMax; - } - - if (!jsonProp.fillOpacity) { - jsonProp.fillOpacity = false; - } - - if ("number" != typeof jsonProp.lightness) { - jsonProp.lightness = 1; - } else { - jsonProp.lightness = Math.max(0, Math.min(1, jsonProp.lightness)); - } - - if (!jsonProp.strokeOpacity) { - jsonProp.strokeOpacity = false; - } - - if (jsonProp.length === undefined || jsonProp.length === null) { - jsonProp.length = Number.MAX_VALUE; - } - - if (!jsonProp.wrapLines) { - jsonProp.wrapLines = false; - } - - if (!jsonProp.dateFormat) { - jsonProp.dateFormat = ORYX.I18N.PropertyWindow.dateFormat || "m/d/y"; - } - - if (!jsonProp.fill) { - jsonProp.fill = false; - } - - if (!jsonProp.stroke) { - jsonProp.stroke = false; - } - - if(!jsonProp.inverseBoolean) { - jsonProp.inverseBoolean = false; - } - - if(!jsonProp.directlyEditable && jsonProp.directlyEditable != false) { - jsonProp.directlyEditable = true; - } - - if(jsonProp.visible !== false) { - jsonProp.visible = true; - } - - if(jsonProp.isList !== true) { - jsonProp.isList = false; - - if(!jsonProp.list || !(jsonProp.list instanceof Array)) { - jsonProp.list = []; - } - } - - if(!jsonProp.category) { - if (jsonProp.popular) { - jsonProp.category = "popular"; - } else { - jsonProp.category = "others"; - } - } - - if(!jsonProp.alwaysAppearInMultiselect) { - jsonProp.alwaysAppearInMultiselect = false; - } - - if (jsonProp.type === ORYX.CONFIG.TYPE_CHOICE) { - if (jsonProp.items && jsonProp.items instanceof Array) { - jsonProp.items.each((function(jsonitem) { - // why is the item's value used as the key??? - this._items[jsonItem.value.toLowerCase()] = new ORYX.Core.StencilSet.PropertyItem(jsonItem, namespace, this); - }).bind(this)); - } - else { - throw "ORYX.Core.StencilSet.Property(construct): No property items defined." + init: function (x, y, oldX, oldY, deltaWidth, deltaHeight) { + this.x = x; + this.y = y; + this.oldX = oldX; + this.oldY = oldY; + this.deltaWidth = deltaWidth; + this.deltaHeight = deltaHeight; + + this.d = ""; + }, + + /** + * editPointsAbs + * + * @param {Array} points Array of absolutePoints + */ + editPointsAbs: function (points) { + if (points instanceof Array) { + var newPoints = []; + var x, y; + for (var i = 0; i < points.length; i++) { + x = (parseFloat(points[i]) - this.oldX) * this.deltaWidth + this.x; + i++; + y = (parseFloat(points[i]) - this.oldY) * this.deltaHeight + this.y; + newPoints.push(x); + newPoints.push(y); } - // extended by Kerstin (start) + + return newPoints; + } else { + //TODO error } - else - if (jsonProp.type === ORYX.CONFIG.TYPE_COMPLEX || jsonProp.type == ORYX.CONFIG.TYPE_MULTIPLECOMPLEX) { - if (jsonProp.complexItems && jsonProp.complexItems instanceof Array) { - jsonProp.complexItems.each((function(jsonComplexitem) { - this._complexItems[jsonComplexItem.id.toLowerCase()] = new ORYX.Core.StencilSet.ComplexPropertyItem(jsonComplexItem, namespace, this); - }).bind(this)); - } - } - // extended by Kerstin (end) }, - - getMinForType : function(type) { - if (type.toLowerCase() == ORYX.CONFIG.TYPE_INTEGER) { - return -Math.pow(2,31) - } else { - return -Number.MAX_VALUE+1; - } - }, - getMaxForType : function(type) { - if (type.toLowerCase() == ORYX.CONFIG.TYPE_INTEGER) { - return Math.pow(2,31)-1 - } else { - return Number.MAX_VALUE; - } - }, - + /** - * @param {ORYX.Core.StencilSet.Property} property - * @return {Boolean} True, if property has the same namespace and id. + * editPointsRel + * + * @param {Array} points Array of absolutePoints */ - equals: function(property){ - return (this._namespace === property.namespace() && - this.id() === property.id()) ? true : false; - }, - - namespace: function(){ - return this._namespace; - }, - - stencil: function(){ - return this._stencil; - }, - - id: function(){ - return this._jsonProp.id; - }, - - prefix: function(){ - return this._jsonProp.prefix; - }, - - type: function(){ - return this._jsonProp.type; - }, - - inverseBoolean: function() { - return this._jsonProp.inverseBoolean; - }, - - category: function() { - return this._jsonProp.category; - }, - - setCategory: function(value) { - this._jsonProp.category = value; - }, - - directlyEditable: function() { - return this._jsonProp.directlyEditable; - }, - - visible: function() { - return this._jsonProp.visible; - }, - - title: function(){ - return ORYX.Core.StencilSet.getTranslation(this._jsonProp, "title"); - }, - - value: function(){ - return this._jsonProp.value; - }, - - readonly: function(){ - return this._jsonProp.readonly; - }, - - optional: function(){ - return this._jsonProp.optional; - }, - - description: function(){ - return ORYX.Core.StencilSet.getTranslation(this._jsonProp, "description"); + editPointsRel: function (points) { + if (points instanceof Array) { + var newPoints = []; + var x, y; + for (var i = 0; i < points.length; i++) { + x = parseFloat(points[i]) * this.deltaWidth; + i++; + y = parseFloat(points[i]) * this.deltaHeight; + newPoints.push(x); + newPoints.push(y); + } + + return newPoints; + } else { + //TODO error + } }, - + /** - * An optional link to a SVG element so that the property affects the - * graphical representation of the stencil. + * arcAbs - A + * + * @param {Number} rx + * @param {Number} ry + * @param {Number} xAxisRotation + * @param {Boolean} largeArcFlag + * @param {Boolean} sweepFlag + * @param {Number} x + * @param {Number} y */ - refToView: function(){ - return this._jsonProp.refToView; + arcAbs: function (rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) { + var pointsAbs = this.editPointsAbs([x, y]); + var pointsRel = this.editPointsRel([rx, ry]); + + this.d = this.d.concat(" A" + pointsRel[0] + " " + pointsRel[1] + + " " + xAxisRotation + " " + largeArcFlag + + " " + sweepFlag + " " + pointsAbs[0] + " " + + pointsAbs[1] + " "); }, - + /** - * If type is integer or float, min is the lower bounds of value. + * arcRel - a + * + * @param {Number} rx + * @param {Number} ry + * @param {Number} xAxisRotation + * @param {Boolean} largeArcFlag + * @param {Boolean} sweepFlag + * @param {Number} x + * @param {Number} y */ - min: function(){ - return this._jsonProp.min; + arcRel: function (rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) { + var pointsRel = this.editPointsRel([rx, ry, x, y]); + + this.d = this.d.concat(" a" + pointsRel[0] + " " + pointsRel[1] + + " " + xAxisRotation + " " + largeArcFlag + + " " + sweepFlag + " " + pointsRel[2] + " " + + pointsRel[3] + " "); }, - + /** - * If type ist integer or float, max is the upper bounds of value. + * curvetoCubicAbs - C + * + * @param {Number} x1 + * @param {Number} y1 + * @param {Number} x2 + * @param {Number} y2 + * @param {Number} x + * @param {Number} y */ - max: function(){ - return this._jsonProp.max; + curvetoCubicAbs: function (x1, y1, x2, y2, x, y) { + var pointsAbs = this.editPointsAbs([x1, y1, x2, y2, x, y]); + + this.d = this.d.concat(" C" + pointsAbs[0] + " " + pointsAbs[1] + + " " + pointsAbs[2] + " " + pointsAbs[3] + + " " + pointsAbs[4] + " " + pointsAbs[5] + " "); }, - + /** - * If type is float, this method returns if the fill-opacity property should - * be set. - * @return {Boolean} + * curvetoCubicRel - c + * + * @param {Number} x1 + * @param {Number} y1 + * @param {Number} x2 + * @param {Number} y2 + * @param {Number} x + * @param {Number} y */ - fillOpacity: function(){ - return this._jsonProp.fillOpacity; + curvetoCubicRel: function (x1, y1, x2, y2, x, y) { + var pointsRel = this.editPointsRel([x1, y1, x2, y2, x, y]); + + this.d = this.d.concat(" c" + pointsRel[0] + " " + pointsRel[1] + + " " + pointsRel[2] + " " + pointsRel[3] + + " " + pointsRel[4] + " " + pointsRel[5] + " "); }, - + /** - * If type is float, this method returns if the stroke-opacity property should - * be set. - * @return {Boolean} + * linetoHorizontalAbs - H + * + * @param {Number} x */ - strokeOpacity: function(){ - return this._jsonProp.strokeOpacity; + linetoHorizontalAbs: function (x) { + var pointsAbs = this.editPointsAbs([x, 0]); + + this.d = this.d.concat(" H" + pointsAbs[0] + " "); }, - + /** - * If type is string or richtext, length is the maximum length of the text. - * TODO how long can a string be. + * linetoHorizontalRel - h + * + * @param {Number} x */ - length: function(){ - return this._jsonProp.length ? this._jsonProp.length : Number.MAX_VALUE; - }, - - wrapLines: function(){ - return this._jsonProp.wrapLines; + linetoHorizontalRel: function (x) { + var pointsRel = this.editPointsRel([x, 0]); + + this.d = this.d.concat(" h" + pointsRel[0] + " "); }, - + /** - * If type is date, dateFormat specifies the format of the date. The format - * specification of the ext library is used: - * - * Format Output Description - * ------ ---------- -------------------------------------------------------------- - * d 10 Day of the month, 2 digits with leading zeros - * D Wed A textual representation of a day, three letters - * j 10 Day of the month without leading zeros - * l Wednesday A full textual representation of the day of the week - * S th English ordinal day of month suffix, 2 chars (use with j) - * w 3 Numeric representation of the day of the week - * z 9 The julian date, or day of the year (0-365) - * W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52) - * F January A full textual representation of the month - * m 01 Numeric representation of a month, with leading zeros - * M Jan Month name abbreviation, three letters - * n 1 Numeric representation of a month, without leading zeros - * t 31 Number of days in the given month - * L 0 Whether its a leap year (1 if it is a leap year, else 0) - * Y 2007 A full numeric representation of a year, 4 digits - * y 07 A two digit representation of a year - * a pm Lowercase Ante meridiem and Post meridiem - * A PM Uppercase Ante meridiem and Post meridiem - * g 3 12-hour format of an hour without leading zeros - * G 15 24-hour format of an hour without leading zeros - * h 03 12-hour format of an hour with leading zeros - * H 15 24-hour format of an hour with leading zeros - * i 05 Minutes with leading zeros - * s 01 Seconds, with leading zeros - * O -0600 Difference to Greenwich time (GMT) in hours - * T CST Timezone setting of the machine running the code - * Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east) + * linetoAbs - L * - * Example: - * F j, Y, g:i a -> January 10, 2007, 3:05 pm + * @param {Number} x + * @param {Number} y */ - dateFormat: function(){ - return this._jsonProp.dateFormat; + linetoAbs: function (x, y) { + var pointsAbs = this.editPointsAbs([x, y]); + + this.d = this.d.concat(" L" + pointsAbs[0] + " " + pointsAbs[1] + " "); }, - + /** - * If type is color, this method returns if the fill property should - * be set. - * @return {Boolean} + * linetoRel - l + * + * @param {Number} x + * @param {Number} y */ - fill: function(){ - return this._jsonProp.fill; + linetoRel: function (x, y) { + var pointsRel = this.editPointsRel([x, y]); + + this.d = this.d.concat(" l" + pointsRel[0] + " " + pointsRel[1] + " "); }, - - /** - * Lightness defines the satiation of the color - * 0 is the pure color - * 1 is white - * @return {Integer} lightness - */ - lightness: function(){ - return this._jsonProp.lightness; - }, - + /** - * If type is color, this method returns if the stroke property should - * be set. - * @return {Boolean} + * movetoAbs - M + * + * @param {Number} x + * @param {Number} y */ - stroke: function(){ - return this._jsonProp.stroke; + movetoAbs: function (x, y) { + var pointsAbs = this.editPointsAbs([x, y]); + + this.d = this.d.concat(" M" + pointsAbs[0] + " " + pointsAbs[1] + " "); }, - + /** - * If type is choice, items is a hash map with all alternative values - * (PropertyItem objects) with id as keys. + * movetoRel - m + * + * @param {Number} x + * @param {Number} y */ - items: function(){ - return $H(this._items).values(); + movetoRel: function (x, y) { + var pointsRel; + if (this.d === "") { + pointsRel = this.editPointsAbs([x, y]); + } else { + pointsRel = this.editPointsRel([x, y]); + } + + this.d = this.d.concat(" m" + pointsRel[0] + " " + pointsRel[1] + " "); }, - - item: function(value){ - if (value) { - return this._items[value.toLowerCase()]; - } else { - return null; - } + + /** + * curvetoQuadraticAbs - Q + * + * @param {Number} x1 + * @param {Number} y1 + * @param {Number} x + * @param {Number} y + */ + curvetoQuadraticAbs: function (x1, y1, x, y) { + var pointsAbs = this.editPointsAbs([x1, y1, x, y]); + + this.d = this.d.concat(" Q" + pointsAbs[0] + " " + pointsAbs[1] + " " + + pointsAbs[2] + " " + pointsAbs[3] + " "); }, - - toString: function(){ - return "Property " + this.title() + " (" + this.id() + ")"; + + /** + * curvetoQuadraticRel - q + * + * @param {Number} x1 + * @param {Number} y1 + * @param {Number} x + * @param {Number} y + */ + curvetoQuadraticRel: function (x1, y1, x, y) { + var pointsRel = this.editPointsRel([x1, y1, x, y]); + + this.d = this.d.concat(" q" + pointsRel[0] + " " + pointsRel[1] + " " + + pointsRel[2] + " " + pointsRel[3] + " "); }, - - complexItems: function(){ - return $H(this._complexItems).values(); + + /** + * curvetoCubicSmoothAbs - S + * + * @param {Number} x2 + * @param {Number} y2 + * @param {Number} x + * @param {Number} y + */ + curvetoCubicSmoothAbs: function (x2, y2, x, y) { + var pointsAbs = this.editPointsAbs([x2, y2, x, y]); + + this.d = this.d.concat(" S" + pointsAbs[0] + " " + pointsAbs[1] + " " + + pointsAbs[2] + " " + pointsAbs[3] + " "); }, - - complexItem: function(id){ - if(id) { - return this._complexItems[id.toLowerCase()]; - } else { - return null; - } - + + /** + * curvetoCubicSmoothRel - s + * + * @param {Number} x2 + * @param {Number} y2 + * @param {Number} x + * @param {Number} y + */ + curvetoCubicSmoothRel: function (x2, y2, x, y) { + var pointsRel = this.editPointsRel([x2, y2, x, y]); + + this.d = this.d.concat(" s" + pointsRel[0] + " " + pointsRel[1] + " " + + pointsRel[2] + " " + pointsRel[3] + " "); }, - - complexAttributeToView: function(){ - return this._jsonProp.complexAttributeToView || ""; + + /** + * curvetoQuadraticSmoothAbs - T + * + * @param {Number} x + * @param {Number} y + */ + curvetoQuadraticSmoothAbs: function (x, y) { + var pointsAbs = this.editPointsAbs([x, y]); + + this.d = this.d.concat(" T" + pointsAbs[0] + " " + pointsAbs[1] + " "); }, - - isList: function() { - return !!this._jsonProp.isList; + + /** + * curvetoQuadraticSmoothRel - t + * + * @param {Number} x + * @param {Number} y + */ + curvetoQuadraticSmoothRel: function (x, y) { + var pointsRel = this.editPointsRel([x, y]); + + this.d = this.d.concat(" t" + pointsRel[0] + " " + pointsRel[1] + " "); + }, + + /** + * linetoVerticalAbs - V + * + * @param {Number} y + */ + linetoVerticalAbs: function (y) { + var pointsAbs = this.editPointsAbs([0, y]); + + this.d = this.d.concat(" V" + pointsAbs[1] + " "); }, - - getListItems: function() { - return this._jsonProp.list; + + /** + * linetoVerticalRel - v + * + * @param {Number} y + */ + linetoVerticalRel: function (y) { + var pointsRel = this.editPointsRel([0, y]); + + this.d = this.d.concat(" v" + pointsRel[1] + " "); }, - - /** - * If type is glossary link, the - * type of category can be defined where - * the link only can go to. - * @return {String} The glossary category id - */ - linkableType: function(){ - return this._jsonProp.linkableType || ""; - }, - - alwaysAppearInMultiselect : function() { - return this._jsonProp.alwaysAppearInMultiselect; - }, - - popular: function() { - return this._jsonProp.popular || false; - }, - - setPopular: function() { - this._jsonProp.popular = true; - }, - - hide: function() { - this._hidden = true; - }, - - isHidden: function() { - return this._hidden; - } - -}); -/* + + /** + * closePath - z or Z + */ + closePath: function () { + this.d = this.d.concat(" z"); + } + +});/* * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. * License rights for this program may be obtained from Alfresco Software, Ltd. * pursuant to a written agreement and any use of this program without such an @@ -6603,215 +2889,283 @@ ORYX.Core.StencilSet.Property = Clazz.extend({ */ /** - * Init namespace + * Init namespaces */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} -if(!ORYX.Core.StencilSet) {ORYX.Core.StencilSet = {};} +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} +if (!ORYX.Core.SVG) { + ORYX.Core.SVG = {}; +} + /** - * Class Stencil - * uses Prototpye 1.5.0 - * uses Inheritance + * MinMaxPathHandler + * + * Determine the minimum and maximum of a SVG path's absolute coordinates. + * For relative coordinates the absolute value is computed for consideration. + * The values are stored in attributes minX, minY, maxX, and maxY. + * + * @constructor */ -ORYX.Core.StencilSet.PropertyItem = Clazz.extend({ +ORYX.Core.SVG.MinMaxPathHandler = Clazz.extend({ - /** - * Constructor - */ - construct: function(jsonItem, namespace, property) { - arguments.callee.$.construct.apply(this, arguments); + construct: function () { + arguments.callee.$.construct.apply(this, arguments); - if(!jsonItem) { - throw "ORYX.Core.StencilSet.PropertyItem(construct): Parameter jsonItem is not defined."; - } - if(!namespace) { - throw "ORYX.Core.StencilSet.PropertyItem(construct): Parameter namespace is not defined."; - } - if(!property) { - throw "ORYX.Core.StencilSet.PropertyItem(construct): Parameter property is not defined."; - } - - this._jsonItem = jsonItem; - this._namespace = namespace; - this._property = property; - - //init all values - if(!jsonItem.value) { - throw "ORYX.Core.StencilSet.PropertyItem(construct): Value is not defined."; - } - - if(this._jsonItem.refToView) { - if(!(this._jsonItem.refToView instanceof Array)) { - this._jsonItem.refToView = [this._jsonItem.refToView]; - } - } else { - this._jsonItem.refToView = []; - } - }, + this.minX = undefined; + this.minY = undefined; + this.maxX = undefined; + this.maxY = undefined; - /** - * @param {ORYX.Core.StencilSet.PropertyItem} item - * @return {Boolean} True, if item has the same namespace and id. - */ - equals: function(item) { - return (this.property().equals(item.property()) && - this.value() === item.value()); - }, + this._lastAbsX = undefined; + this._lastAbsY = undefined; + }, - namespace: function() { - return this._namespace; - }, + /** + * Store minimal and maximal coordinates of passed points to attributes minX, maxX, minY, maxY + * + * @param {Array} points Array of absolutePoints + */ + calculateMinMax: function (points) { + if (points instanceof Array) { + var x, y; + for (var i = 0; i < points.length; i++) { + x = parseFloat(points[i]); + i++; + y = parseFloat(points[i]); + + this.minX = (this.minX !== undefined) ? Math.min(this.minX, x) : x; + this.maxX = (this.maxX !== undefined) ? Math.max(this.maxX, x) : x; + this.minY = (this.minY !== undefined) ? Math.min(this.minY, y) : y; + this.maxY = (this.maxY !== undefined) ? Math.max(this.maxY, y) : y; + + this._lastAbsX = x; + this._lastAbsY = y; + } + } else { + //TODO error + } + }, - property: function() { - return this._property; - }, + /** + * arcAbs - A + * + * @param {Number} rx + * @param {Number} ry + * @param {Number} xAxisRotation + * @param {Boolean} largeArcFlag + * @param {Boolean} sweepFlag + * @param {Number} x + * @param {Number} y + */ + arcAbs: function (rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) { + this.calculateMinMax([x, y]); + }, - value: function() { - return this._jsonItem.value; - }, - - title: function() { - return ORYX.Core.StencilSet.getTranslation(this._jsonItem, "title"); - }, + /** + * arcRel - a + * + * @param {Number} rx + * @param {Number} ry + * @param {Number} xAxisRotation + * @param {Boolean} largeArcFlag + * @param {Boolean} sweepFlag + * @param {Number} x + * @param {Number} y + */ + arcRel: function (rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) { + this.calculateMinMax([this._lastAbsX + x, this._lastAbsY + y]); + }, - refToView: function() { - return this._jsonItem.refToView; - }, - - icon: function() { - return (this._jsonItem.icon) ? this.property().stencil()._source + "icons/" + this._jsonItem.icon : ""; - }, + /** + * curvetoCubicAbs - C + * + * @param {Number} x1 + * @param {Number} y1 + * @param {Number} x2 + * @param {Number} y2 + * @param {Number} x + * @param {Number} y + */ + curvetoCubicAbs: function (x1, y1, x2, y2, x, y) { + this.calculateMinMax([x1, y1, x2, y2, x, y]); + }, - toString: function() { return "PropertyItem " + this.property() + " (" + this.value() + ")"; } -});/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + /** + * curvetoCubicRel - c + * + * @param {Number} x1 + * @param {Number} y1 + * @param {Number} x2 + * @param {Number} y2 + * @param {Number} x + * @param {Number} y + */ + curvetoCubicRel: function (x1, y1, x2, y2, x, y) { + this.calculateMinMax([this._lastAbsX + x1, this._lastAbsY + y1, + this._lastAbsX + x2, this._lastAbsY + y2, + this._lastAbsX + x, this._lastAbsY + y]); + }, -/** - * Init namespaces - */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} -if(!ORYX.Core.StencilSet) {ORYX.Core.StencilSet = {};} + /** + * linetoHorizontalAbs - H + * + * @param {Number} x + */ + linetoHorizontalAbs: function (x) { + this.calculateMinMax([x, this._lastAbsY]); + }, -/** - * Class Stencil - * uses Prototpye 1.5.0 - * uses Inheritance - */ -ORYX.Core.StencilSet.ComplexPropertyItem = Clazz.extend({ + /** + * linetoHorizontalRel - h + * + * @param {Number} x + */ + linetoHorizontalRel: function (x) { + this.calculateMinMax([this._lastAbsX + x, this._lastAbsY]); + }, - /** - * Constructor - */ - construct: function(jsonItem, namespace, property) { - arguments.callee.$.construct.apply(this, arguments); + /** + * linetoAbs - L + * + * @param {Number} x + * @param {Number} y + */ + linetoAbs: function (x, y) { + this.calculateMinMax([x, y]); + }, - if(!jsonItem) { - throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Parameter jsonItem is not defined."; - } - if(!namespace) { - throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Parameter namespace is not defined."; - } - if(!property) { - throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Parameter property is not defined."; - } - - this._jsonItem = jsonItem; - this._namespace = namespace; - this._property = property; - this._items = new Hash(); - this._complexItems = new Hash(); - - //init all values - if(!jsonItem.name) { - throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Name is not defined."; - } - - if(!jsonItem.type) { - throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Type is not defined."; - } else { - jsonItem.type = jsonItem.type.toLowerCase(); - } - - if(jsonItem.type === ORYX.CONFIG.TYPE_CHOICE) { - if(jsonItem.items && jsonItem.items instanceof Array) { - jsonItem.items.each((function(item) { - this._items[item.value] = new ORYX.Core.StencilSet.PropertyItem(item, namespace, this); - }).bind(this)); - } else { - throw "ORYX.Core.StencilSet.Property(construct): No property items defined." - } - } else if(jsonItem.type === ORYX.CONFIG.TYPE_COMPLEX) { - if(jsonItem.complexItems && jsonItem.complexItems instanceof Array) { - jsonItem.complexItems.each((function(complexItem) { - this._complexItems[complexItem.id] = new ORYX.Core.StencilSet.ComplexPropertyItem(complexItem, namespace, this); - }).bind(this)); - } else { - throw "ORYX.Core.StencilSet.Property(construct): No property items defined." - } - } - }, + /** + * linetoRel - l + * + * @param {Number} x + * @param {Number} y + */ + linetoRel: function (x, y) { + this.calculateMinMax([this._lastAbsX + x, this._lastAbsY + y]); + }, - /** - * @param {ORYX.Core.StencilSet.PropertyItem} item - * @return {Boolean} True, if item has the same namespace and id. - */ - equals: function(item) { - return (this.property().equals(item.property()) && - this.name() === item.name()); - }, + /** + * movetoAbs - M + * + * @param {Number} x + * @param {Number} y + */ + movetoAbs: function (x, y) { + this.calculateMinMax([x, y]); + }, - namespace: function() { - return this._namespace; - }, + /** + * movetoRel - m + * + * @param {Number} x + * @param {Number} y + */ + movetoRel: function (x, y) { + if (this._lastAbsX && this._lastAbsY) { + this.calculateMinMax([this._lastAbsX + x, this._lastAbsY + y]); + } else { + this.calculateMinMax([x, y]); + } + }, - property: function() { - return this._property; - }, + /** + * curvetoQuadraticAbs - Q + * + * @param {Number} x1 + * @param {Number} y1 + * @param {Number} x + * @param {Number} y + */ + curvetoQuadraticAbs: function (x1, y1, x, y) { + this.calculateMinMax([x1, y1, x, y]); + }, + + /** + * curvetoQuadraticRel - q + * + * @param {Number} x1 + * @param {Number} y1 + * @param {Number} x + * @param {Number} y + */ + curvetoQuadraticRel: function (x1, y1, x, y) { + this.calculateMinMax([this._lastAbsX + x1, this._lastAbsY + y1, this._lastAbsX + x, this._lastAbsY + y]); + }, + + /** + * curvetoCubicSmoothAbs - S + * + * @param {Number} x2 + * @param {Number} y2 + * @param {Number} x + * @param {Number} y + */ + curvetoCubicSmoothAbs: function (x2, y2, x, y) { + this.calculateMinMax([x2, y2, x, y]); + }, + + /** + * curvetoCubicSmoothRel - s + * + * @param {Number} x2 + * @param {Number} y2 + * @param {Number} x + * @param {Number} y + */ + curvetoCubicSmoothRel: function (x2, y2, x, y) { + this.calculateMinMax([this._lastAbsX + x2, this._lastAbsY + y2, this._lastAbsX + x, this._lastAbsY + y]); + }, + + /** + * curvetoQuadraticSmoothAbs - T + * + * @param {Number} x + * @param {Number} y + */ + curvetoQuadraticSmoothAbs: function (x, y) { + this.calculateMinMax([x, y]); + }, + + /** + * curvetoQuadraticSmoothRel - t + * + * @param {Number} x + * @param {Number} y + */ + curvetoQuadraticSmoothRel: function (x, y) { + this.calculateMinMax([this._lastAbsX + x, this._lastAbsY + y]); + }, + + /** + * linetoVerticalAbs - V + * + * @param {Number} y + */ + linetoVerticalAbs: function (y) { + this.calculateMinMax([this._lastAbsX, y]); + }, + + /** + * linetoVerticalRel - v + * + * @param {Number} y + */ + linetoVerticalRel: function (y) { + this.calculateMinMax([this._lastAbsX, this._lastAbsY + y]); + }, + + /** + * closePath - z or Z + */ + closePath: function () { + return;// do nothing + } - name: function() { - return ORYX.Core.StencilSet.getTranslation(this._jsonItem, "name"); - }, - - id: function() { - return this._jsonItem.id; - }, - - type: function() { - return this._jsonItem.type; - }, - - optional: function() { - return this._jsonItem.optional; - }, - - width: function() { - return this._jsonItem.width; - }, - - value: function() { - return this._jsonItem.value; - }, - - items: function() { - return this._items.values(); - }, - - complexItems: function() { - return this._complexItems.values(); - }, - - disable: function() { - return this._jsonItem.disable; - } });/* * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. * License rights for this program may be obtained from Alfresco Software, Ltd. @@ -6825,1308 +3179,276 @@ ORYX.Core.StencilSet.ComplexPropertyItem = Clazz.extend({ /** * Init namespaces */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} -if(!ORYX.Core.StencilSet) {ORYX.Core.StencilSet = {};} +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} +if (!ORYX.Core.SVG) { + ORYX.Core.SVG = {}; +} + /** - * Class Rules uses Prototpye 1.5.0 uses Inheritance - * - * This class implements the API to check the stencil sets' rules. + * PathHandler + * + * Determine absolute points of a SVG path. The coordinates are stored + * sequentially in the attribute points (x-coordinates at even indices, + * y-coordinates at odd indices). + * + * @constructor */ -ORYX.Core.StencilSet.Rules = { +ORYX.Core.SVG.PointsPathHandler = Clazz.extend({ - /** - * Constructor - */ - construct: function() { - arguments.callee.$.construct.apply(this, arguments); - - this._stencilSets = []; - this._stencils = []; - this._containerStencils = []; - - this._cachedConnectSET = new Hash(); - this._cachedConnectSE = new Hash(); - this._cachedConnectTE = new Hash(); - this._cachedCardSE = new Hash(); - this._cachedCardTE = new Hash(); - this._cachedContainPC = new Hash(); - this._cachedMorphRS = new Hash(); - - this._connectionRules = new Hash(); - this._cardinalityRules = new Hash(); - this._containmentRules = new Hash(); - this._morphingRules = new Hash(); - this._layoutRules = new Hash(); - }, - - /** - * Call this method to initialize the rules for a stencil set and all of its - * active extensions. - * - * @param {Object} - * stencilSet - */ - initializeRules: function(stencilSet) { - - var existingSS = this._stencilSets.find(function(ss) { - return (ss.namespace() == stencilSet.namespace()); - }); - if (existingSS) { - // reinitialize all rules - var stencilsets = this._stencilSets.clone(); - stencilsets = stencilsets.without(existingSS); - stencilsets.push(stencilSet); - - this._stencilSets = []; - this._stencils = []; - this._containerStencils = []; - - this._cachedConnectSET = new Hash(); - this._cachedConnectSE = new Hash(); - this._cachedConnectTE = new Hash(); - this._cachedCardSE = new Hash(); - this._cachedCardTE = new Hash(); - this._cachedContainPC = new Hash(); - this._cachedMorphRS = new Hash(); - - this._connectionRules = new Hash(); - this._cardinalityRules = new Hash(); - this._containmentRules = new Hash(); - this._morphingRules = new Hash(); - this._layoutRules = new Hash(); - - stencilsets.each(function(ss){ - this.initializeRules(ss); - }.bind(this)); - return; - } - else { - this._stencilSets.push(stencilSet); - - var jsonRules = new Hash(stencilSet.jsonRules()); - var namespace = stencilSet.namespace(); - var stencils = stencilSet.stencils(); - - stencilSet.extensions().values().each(function(extension) { - if(extension.rules) { - if(extension.rules.connectionRules) - jsonRules.connectionRules = jsonRules.connectionRules.concat(extension.rules.connectionRules); - if(extension.rules.cardinalityRules) - jsonRules.cardinalityRules = jsonRules.cardinalityRules.concat(extension.rules.cardinalityRules); - if(extension.rules.containmentRules) - jsonRules.containmentRules = jsonRules.containmentRules.concat(extension.rules.containmentRules); - if(extension.rules.morphingRules) - jsonRules.morphingRules = jsonRules.morphingRules.concat(extension.rules.morphingRules); - } - if(extension.stencils) - stencils = stencils.concat(extension.stencils); - }); - - this._stencils = this._stencils.concat(stencilSet.stencils()); - - // init connection rules - var cr = this._connectionRules; - if (jsonRules.connectionRules) { - jsonRules.connectionRules.each((function(rules){ - if (this._isRoleOfOtherNamespace(rules.role)) { - if (!cr[rules.role]) { - cr[rules.role] = new Hash(); - } - } - else { - if (!cr[namespace + rules.role]) - cr[namespace + rules.role] = new Hash(); - } - - rules.connects.each((function(connect){ - var toRoles = []; - if (connect.to) { - if (!(connect.to instanceof Array)) { - connect.to = [connect.to]; - } - connect.to.each((function(to){ - if (this._isRoleOfOtherNamespace(to)) { - toRoles.push(to); - } - else { - toRoles.push(namespace + to); - } - }).bind(this)); - } - - var role, from; - if (this._isRoleOfOtherNamespace(rules.role)) - role = rules.role; - else - role = namespace + rules.role; - - if (this._isRoleOfOtherNamespace(connect.from)) - from = connect.from; - else - from = namespace + connect.from; - - if (!cr[role][from]) - cr[role][from] = toRoles; - else - cr[role][from] = cr[role][from].concat(toRoles); - - }).bind(this)); - }).bind(this)); - } - - // init cardinality rules - var cardr = this._cardinalityRules; - if (jsonRules.cardinalityRules) { - jsonRules.cardinalityRules.each((function(rules){ - var cardrKey; - if (this._isRoleOfOtherNamespace(rules.role)) { - cardrKey = rules.role; - } - else { - cardrKey = namespace + rules.role; - } - - if (!cardr[cardrKey]) { - cardr[cardrKey] = {}; - for (i in rules) { - cardr[cardrKey][i] = rules[i]; - } - } - - var oe = new Hash(); - if (rules.outgoingEdges) { - rules.outgoingEdges.each((function(rule){ - if (this._isRoleOfOtherNamespace(rule.role)) { - oe[rule.role] = rule; - } - else { - oe[namespace + rule.role] = rule; - } - }).bind(this)); - } - cardr[cardrKey].outgoingEdges = oe; - var ie = new Hash(); - if (rules.incomingEdges) { - rules.incomingEdges.each((function(rule){ - if (this._isRoleOfOtherNamespace(rule.role)) { - ie[rule.role] = rule; - } - else { - ie[namespace + rule.role] = rule; - } - }).bind(this)); - } - cardr[cardrKey].incomingEdges = ie; - }).bind(this)); - } - - // init containment rules - var conr = this._containmentRules; - if (jsonRules.containmentRules) { - jsonRules.containmentRules.each((function(rules){ - var conrKey; - if (this._isRoleOfOtherNamespace(rules.role)) { - conrKey = rules.role; - } - else { - this._containerStencils.push(namespace + rules.role); - conrKey = namespace + rules.role; - } - if (!conr[conrKey]) { - conr[conrKey] = []; - } - (rules.contains||[]).each((function(containRole){ - if (this._isRoleOfOtherNamespace(containRole)) { - conr[conrKey].push(containRole); - } - else { - conr[conrKey].push(namespace + containRole); - } - }).bind(this)); - }).bind(this)); - } - - // init morphing rules - var morphr = this._morphingRules; - if (jsonRules.morphingRules) { - jsonRules.morphingRules.each((function(rules){ - var morphrKey; - if (this._isRoleOfOtherNamespace(rules.role)) { - morphrKey = rules.role; - } - else { - morphrKey = namespace + rules.role; - } - if (!morphr[morphrKey]) { - morphr[morphrKey] = []; - } - if(!rules.preserveBounds) { - rules.preserveBounds = false; - } - rules.baseMorphs.each((function(baseMorphStencilId){ - var morphStencil = this._getStencilById(namespace + baseMorphStencilId); - if(morphStencil) { - morphr[morphrKey].push(morphStencil); - } - }).bind(this)); - }).bind(this)); - } - - // init layouting rules - var layoutRules = this._layoutRules; - if (jsonRules.layoutRules) { - - var getDirections = function(o){ - return { - "edgeRole":o.edgeRole||undefined, - "t": o["t"]||1, - "r": o["r"]||1, - "b": o["b"]||1, - "l": o["l"]||1 - } - } - - jsonRules.layoutRules.each(function(rules){ - var layoutKey; - if (this._isRoleOfOtherNamespace(rules.role)) { - layoutKey = rules.role; - } - else { - layoutKey = namespace + rules.role; - } - if (!layoutRules[layoutKey]) { - layoutRules[layoutKey] = {}; - } - if (rules["in"]){ - layoutRules[layoutKey]["in"] = getDirections(rules["in"]); - } - if (rules["ins"]){ - layoutRules[layoutKey]["ins"] = (rules["ins"]||[]).map(function (e) { return getDirections(e) }) - } - if (rules["out"]) { - layoutRules[layoutKey]["out"] = getDirections(rules["out"]); - } - if (rules["outs"]){ - layoutRules[layoutKey]["outs"] = (rules["outs"]||[]).map(function (e) { return getDirections(e) }) - } - }.bind(this)); - } - } - }, - - _getStencilById: function(id) { - return this._stencils.find(function(stencil) { - return stencil.id()==id; - }); - }, - - _cacheConnect: function(args) { - result = this._canConnect(args); - - if (args.sourceStencil && args.targetStencil) { - var source = this._cachedConnectSET[args.sourceStencil.id()]; - - if(!source) { - source = new Hash(); - this._cachedConnectSET[args.sourceStencil.id()] = source; - } - - var edge = source[args.edgeStencil.id()]; - - if(!edge) { - edge = new Hash(); - source[args.edgeStencil.id()] = edge; - } - - edge[args.targetStencil.id()] = result; - - } else if (args.sourceStencil) { - var source = this._cachedConnectSE[args.sourceStencil.id()]; - - if(!source) { - source = new Hash(); - this._cachedConnectSE[args.sourceStencil.id()] = source; - } - - source[args.edgeStencil.id()] = result; + construct: function () { + arguments.callee.$.construct.apply(this, arguments); - } else { - var target = this._cachedConnectTE[args.targetStencil.id()]; - - if(!target) { - target = new Hash(); - this._cachedConnectTE[args.targetStencil.id()] = target; - } - - target[args.edgeStencil.id()] = result; - } - - return result; - }, - - _cacheCard: function(args) { - - if(args.sourceStencil) { - var source = this._cachedCardSE[args.sourceStencil.id()] - - if(!source) { - source = new Hash(); - this._cachedCardSE[args.sourceStencil.id()] = source; - } - - var max = this._getMaximumNumberOfOutgoingEdge(args); - if(max == undefined) - max = -1; - - source[args.edgeStencil.id()] = max; - } - - if(args.targetStencil) { - var target = this._cachedCardTE[args.targetStencil.id()] - - if(!target) { - target = new Hash(); - this._cachedCardTE[args.targetStencil.id()] = target; - } - - var max = this._getMaximumNumberOfIncomingEdge(args); - if(max == undefined) - max = -1; - - target[args.edgeStencil.id()] = max; - } - }, - - _cacheContain: function(args) { - - var result = [this._canContain(args), - this._getMaximumOccurrence(args.containingStencil, args.containedStencil)] - - if(result[1] == undefined) - result[1] = -1; - - var children = this._cachedContainPC[args.containingStencil.id()]; - - if(!children) { - children = new Hash(); - this._cachedContainPC[args.containingStencil.id()] = children; - } - - children[args.containedStencil.id()] = result; - - return result; - }, - - /** - * Returns all stencils belonging to a morph group. (calculation result is - * cached) - */ - _cacheMorph: function(role) { - - var morphs = this._cachedMorphRS[role]; - - if(!morphs) { - morphs = []; - - if(this._morphingRules.keys().include(role)) { - morphs = this._stencils.select(function(stencil) { - return stencil.roles().include(role); - }); - } - - this._cachedMorphRS[role] = morphs; - } - return morphs; - }, - - /** Begin connection rules' methods */ - - /** - * - * @param {Object} - * args sourceStencil: ORYX.Core.StencilSet.Stencil | undefined - * sourceShape: ORYX.Core.Shape | undefined - * - * At least sourceStencil or sourceShape has to be specified - * - * @return {Array} Array of stencils of edges that can be outgoing edges of - * the source. - */ - outgoingEdgeStencils: function(args) { - // check arguments - if(!args.sourceShape && !args.sourceStencil) { - return []; - } - - // init arguments - if(args.sourceShape) { - args.sourceStencil = args.sourceShape.getStencil(); - } - - var _edges = []; - - // test each edge, if it can connect to source - this._stencils.each((function(stencil) { - if(stencil.type() === "edge") { - var newArgs = Object.clone(args); - newArgs.edgeStencil = stencil; - if(this.canConnect(newArgs)) { - _edges.push(stencil); - } - } - }).bind(this)); + this.points = []; - return _edges; - }, + this._lastAbsX = undefined; + this._lastAbsY = undefined; + }, - /** - * - * @param {Object} - * args targetStencil: ORYX.Core.StencilSet.Stencil | undefined - * targetShape: ORYX.Core.Shape | undefined - * - * At least targetStencil or targetShape has to be specified - * - * @return {Array} Array of stencils of edges that can be incoming edges of - * the target. - */ - incomingEdgeStencils: function(args) { - // check arguments - if(!args.targetShape && !args.targetStencil) { - return []; - } - - // init arguments - if(args.targetShape) { - args.targetStencil = args.targetShape.getStencil(); - } - - var _edges = []; - - // test each edge, if it can connect to source - this._stencils.each((function(stencil) { - if(stencil.type() === "edge") { - var newArgs = Object.clone(args); - newArgs.edgeStencil = stencil; - if(this.canConnect(newArgs)) { - _edges.push(stencil); - } - } - }).bind(this)); + /** + * addPoints + * + * @param {Array} points Array of absolutePoints + */ + addPoints: function (points) { + if (points instanceof Array) { + var x, y; + for (var i = 0; i < points.length; i++) { + x = parseFloat(points[i]); + i++; + y = parseFloat(points[i]); + + this.points.push(x); + this.points.push(y); + //this.points.push({x:x, y:y}); + + this._lastAbsX = x; + this._lastAbsY = y; + } + } else { + //TODO error + } + }, - return _edges; - }, - - /** - * - * @param {Object} - * args edgeStencil: ORYX.Core.StencilSet.Stencil | undefined - * edgeShape: ORYX.Core.Edge | undefined targetStencil: - * ORYX.Core.StencilSet.Stencil | undefined targetShape: - * ORYX.Core.Node | undefined - * - * At least edgeStencil or edgeShape has to be specified!!! - * - * @return {Array} Returns an array of stencils that can be source of the - * specified edge. - */ - sourceStencils: function(args) { - // check arguments - if(!args || - !args.edgeShape && !args.edgeStencil) { - return []; - } - - // init arguments - if(args.targetShape) { - args.targetStencil = args.targetShape.getStencil(); - } - - if(args.edgeShape) { - args.edgeStencil = args.edgeShape.getStencil(); - } - - var _sources = []; - - // check each stencil, if it can be a source - this._stencils.each((function(stencil) { - var newArgs = Object.clone(args); - newArgs.sourceStencil = stencil; - if(this.canConnect(newArgs)) { - _sources.push(stencil); - } - }).bind(this)); + /** + * arcAbs - A + * + * @param {Number} rx + * @param {Number} ry + * @param {Number} xAxisRotation + * @param {Boolean} largeArcFlag + * @param {Boolean} sweepFlag + * @param {Number} x + * @param {Number} y + */ + arcAbs: function (rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) { + this.addPoints([x, y]); + }, - return _sources; - }, - - /** - * - * @param {Object} - * args edgeStencil: ORYX.Core.StencilSet.Stencil | undefined - * edgeShape: ORYX.Core.Edge | undefined sourceStencil: - * ORYX.Core.StencilSet.Stencil | undefined sourceShape: - * ORYX.Core.Node | undefined - * - * At least edgeStencil or edgeShape has to be specified!!! - * - * @return {Array} Returns an array of stencils that can be target of the - * specified edge. - */ - targetStencils: function(args) { - // check arguments - if(!args || - !args.edgeShape && !args.edgeStencil) { - return []; - } - - // init arguments - if(args.sourceShape) { - args.sourceStencil = args.sourceShape.getStencil(); - } - - if(args.edgeShape) { - args.edgeStencil = args.edgeShape.getStencil(); - } - - var _targets = []; - - // check stencil, if it can be a target - this._stencils.each((function(stencil) { - var newArgs = Object.clone(args); - newArgs.targetStencil = stencil; - if(this.canConnect(newArgs)) { - _targets.push(stencil); - } - }).bind(this)); + /** + * arcRel - a + * + * @param {Number} rx + * @param {Number} ry + * @param {Number} xAxisRotation + * @param {Boolean} largeArcFlag + * @param {Boolean} sweepFlag + * @param {Number} x + * @param {Number} y + */ + arcRel: function (rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) { + this.addPoints([this._lastAbsX + x, this._lastAbsY + y]); + }, - return _targets; - }, + /** + * curvetoCubicAbs - C + * + * @param {Number} x1 + * @param {Number} y1 + * @param {Number} x2 + * @param {Number} y2 + * @param {Number} x + * @param {Number} y + */ + curvetoCubicAbs: function (x1, y1, x2, y2, x, y) { + this.addPoints([x, y]); + }, - /** - * - * @param {Object} - * args edgeStencil: ORYX.Core.StencilSet.Stencil edgeShape: - * ORYX.Core.Edge |undefined sourceStencil: - * ORYX.Core.StencilSet.Stencil | undefined sourceShape: - * ORYX.Core.Node |undefined targetStencil: - * ORYX.Core.StencilSet.Stencil | undefined targetShape: - * ORYX.Core.Node |undefined - * - * At least source or target has to be specified!!! - * - * @return {Boolean} Returns, if the edge can connect source and target. - */ - canConnect: function(args) { - // check arguments - if(!args || - (!args.sourceShape && !args.sourceStencil && - !args.targetShape && !args.targetStencil) || - !args.edgeShape && !args.edgeStencil) { - return false; - } - - // init arguments - if(args.sourceShape) { - args.sourceStencil = args.sourceShape.getStencil(); - } - if(args.targetShape) { - args.targetStencil = args.targetShape.getStencil(); - } - if(args.edgeShape) { - args.edgeStencil = args.edgeShape.getStencil(); - } - - var result; - - if(args.sourceStencil && args.targetStencil) { - var source = this._cachedConnectSET[args.sourceStencil.id()]; - - if(!source) - result = this._cacheConnect(args); - else { - var edge = source[args.edgeStencil.id()]; - - if(!edge) - result = this._cacheConnect(args); - else { - var target = edge[args.targetStencil.id()]; - - if(target == undefined) - result = this._cacheConnect(args); - else - result = target; - } - } - } else if (args.sourceStencil) { - var source = this._cachedConnectSE[args.sourceStencil.id()]; - - if(!source) - result = this._cacheConnect(args); - else { - var edge = source[args.edgeStencil.id()]; - - if(edge == undefined) - result = this._cacheConnect(args); - else - result = edge; - } - } else { // args.targetStencil - var target = this._cachedConnectTE[args.targetStencil.id()]; - - if(!target) - result = this._cacheConnect(args); - else { - var edge = target[args.edgeStencil.id()]; - - if(edge == undefined) - result = this._cacheConnect(args); - else - result = edge; - } - } - - // check cardinality - if (result) { - if(args.sourceShape) { - var source = this._cachedCardSE[args.sourceStencil.id()]; - - if(!source) { - this._cacheCard(args); - source = this._cachedCardSE[args.sourceStencil.id()]; - } - - var max = source[args.edgeStencil.id()]; - - if(max == undefined) { - this._cacheCard(args); - } - - max = source[args.edgeStencil.id()]; - - if(max != -1) { - result = args.sourceShape.getOutgoingShapes().all(function(cs) { - if((cs.getStencil().id() === args.edgeStencil.id()) && - ((args.edgeShape) ? cs !== args.edgeShape : true)) { - max--; - return (max > 0) ? true : false; - } else { - return true; - } - }); - } - } - - if (args.targetShape) { - var target = this._cachedCardTE[args.targetStencil.id()]; - - if(!target) { - this._cacheCard(args); - target = this._cachedCardTE[args.targetStencil.id()]; - } - - var max = target[args.edgeStencil.id()]; - - if(max == undefined) { - this._cacheCard(args); - } - - max = target[args.edgeStencil.id()]; - - if(max != -1) { - result = args.targetShape.getIncomingShapes().all(function(cs){ - if ((cs.getStencil().id() === args.edgeStencil.id()) && - ((args.edgeShape) ? cs !== args.edgeShape : true)) { - max--; - return (max > 0) ? true : false; - } - else { - return true; - } - }); - } - } - } - - return result; - }, - - /** - * - * @param {Object} - * args edgeStencil: ORYX.Core.StencilSet.Stencil edgeShape: - * ORYX.Core.Edge |undefined sourceStencil: - * ORYX.Core.StencilSet.Stencil | undefined sourceShape: - * ORYX.Core.Node |undefined targetStencil: - * ORYX.Core.StencilSet.Stencil | undefined targetShape: - * ORYX.Core.Node |undefined - * - * At least source or target has to be specified!!! - * - * @return {Boolean} Returns, if the edge can connect source and target. - */ - _canConnect: function(args) { - // check arguments - if(!args || - (!args.sourceShape && !args.sourceStencil && - !args.targetShape && !args.targetStencil) || - !args.edgeShape && !args.edgeStencil) { - return false; - } - - // init arguments - if(args.sourceShape) { - args.sourceStencil = args.sourceShape.getStencil(); - } - if(args.targetShape) { - args.targetStencil = args.targetShape.getStencil(); - } - if(args.edgeShape) { - args.edgeStencil = args.edgeShape.getStencil(); - } + /** + * curvetoCubicRel - c + * + * @param {Number} x1 + * @param {Number} y1 + * @param {Number} x2 + * @param {Number} y2 + * @param {Number} x + * @param {Number} y + */ + curvetoCubicRel: function (x1, y1, x2, y2, x, y) { + this.addPoints([this._lastAbsX + x, this._lastAbsY + y]); + }, - // 1. check connection rules - var resultCR; - - // get all connection rules for this edge - var edgeRules = this._getConnectionRulesOfEdgeStencil(args.edgeStencil); + /** + * linetoHorizontalAbs - H + * + * @param {Number} x + */ + linetoHorizontalAbs: function (x) { + this.addPoints([x, this._lastAbsY]); + }, - // check connection rules, if the source can be connected to the target - // with the specified edge. - if(edgeRules.keys().length === 0) { - resultCR = false; - } else { - if(args.sourceStencil) { - resultCR = args.sourceStencil.roles().any(function(sourceRole) { - var targetRoles = edgeRules[sourceRole]; - - if(!targetRoles) {return false;} - - if(args.targetStencil) { - return (targetRoles.any(function(targetRole) { - return args.targetStencil.roles().member(targetRole); - })); - } else { - return true; - } - }); - } else { // !args.sourceStencil -> there is args.targetStencil - resultCR = edgeRules.values().any(function(targetRoles) { - return args.targetStencil.roles().any(function(targetRole) { - return targetRoles.member(targetRole); - }); - }); - } - } - - return resultCR; - }, + /** + * linetoHorizontalRel - h + * + * @param {Number} x + */ + linetoHorizontalRel: function (x) { + this.addPoints([this._lastAbsX + x, this._lastAbsY]); + }, - /** End connection rules' methods */ + /** + * linetoAbs - L + * + * @param {Number} x + * @param {Number} y + */ + linetoAbs: function (x, y) { + this.addPoints([x, y]); + }, + /** + * linetoRel - l + * + * @param {Number} x + * @param {Number} y + */ + linetoRel: function (x, y) { + this.addPoints([this._lastAbsX + x, this._lastAbsY + y]); + }, - /** Begin containment rules' methods */ + /** + * movetoAbs - M + * + * @param {Number} x + * @param {Number} y + */ + movetoAbs: function (x, y) { + this.addPoints([x, y]); + }, - isContainer: function(shape) { - return this._containerStencils.member(shape.getStencil().id()); - }, + /** + * movetoRel - m + * + * @param {Number} x + * @param {Number} y + */ + movetoRel: function (x, y) { + if (this._lastAbsX && this._lastAbsY) { + this.addPoints([this._lastAbsX + x, this._lastAbsY + y]); + } else { + this.addPoints([x, y]); + } + }, - /** - * - * @param {Object} - * args containingStencil: ORYX.Core.StencilSet.Stencil - * containingShape: ORYX.Core.AbstractShape containedStencil: - * ORYX.Core.StencilSet.Stencil containedShape: ORYX.Core.Shape - */ - canContain: function(args) { - if(!args || - !args.containingStencil && !args.containingShape || - !args.containedStencil && !args.containedShape) { - return false; - } - - // init arguments - if(args.containedShape) { - args.containedStencil = args.containedShape.getStencil(); - } - - if(args.containingShape) { - args.containingStencil = args.containingShape.getStencil(); - } - - //if(args.containingStencil.type() == 'edge' || args.containedStencil.type() == 'edge') - // return false; - if(args.containedStencil.type() == 'edge') - return false; - - var childValues; - - var parent = this._cachedContainPC[args.containingStencil.id()]; - - if(!parent) - childValues = this._cacheContain(args); - else { - childValues = parent[args.containedStencil.id()]; - - if(!childValues) - childValues = this._cacheContain(args); - } + /** + * curvetoQuadraticAbs - Q + * + * @param {Number} x1 + * @param {Number} y1 + * @param {Number} x + * @param {Number} y + */ + curvetoQuadraticAbs: function (x1, y1, x, y) { + this.addPoints([x, y]); + }, - if(!childValues[0]) - return false; - else if (childValues[1] == -1) - return true; - else { - if(args.containingShape) { - var max = childValues[1]; - return args.containingShape.getChildShapes(false).all(function(as) { - if(as.getStencil().id() === args.containedStencil.id()) { - max--; - return (max > 0) ? true : false; - } else { - return true; - } - }); - } else { - return true; - } - } - }, - - /** - * - * @param {Object} - * args containingStencil: ORYX.Core.StencilSet.Stencil - * containingShape: ORYX.Core.AbstractShape containedStencil: - * ORYX.Core.StencilSet.Stencil containedShape: ORYX.Core.Shape - */ - _canContain: function(args) { - if(!args || - !args.containingStencil && !args.containingShape || - !args.containedStencil && !args.containedShape) { - return false; - } - - // init arguments - if(args.containedShape) { - args.containedStencil = args.containedShape.getStencil(); - } - - if(args.containingShape) { - args.containingStencil = args.containingShape.getStencil(); - } - -// if(args.containingShape) { -// if(args.containingShape instanceof ORYX.Core.Edge) { -// // edges cannot contain other shapes -// return false; -// } -// } + /** + * curvetoQuadraticRel - q + * + * @param {Number} x1 + * @param {Number} y1 + * @param {Number} x + * @param {Number} y + */ + curvetoQuadraticRel: function (x1, y1, x, y) { + this.addPoints([this._lastAbsX + x, this._lastAbsY + y]); + }, - - var result; - - // check containment rules - result = args.containingStencil.roles().any((function(role) { - var roles = this._containmentRules[role]; - if(roles) { - return roles.any(function(role) { - return args.containedStencil.roles().member(role); - }); - } else { - return false; - } - }).bind(this)); - - return result; - }, - - /** End containment rules' methods */ - - - /** Begin morphing rules' methods */ - - /** - * - * @param {Object} - * args - * stencil: ORYX.Core.StencilSet.Stencil | undefined - * shape: ORYX.Core.Shape | undefined - * - * At least stencil or shape has to be specified - * - * @return {Array} Array of stencils that the passed stencil/shape can be - * transformed to (including the current stencil itself) - */ - morphStencils: function(args) { - // check arguments - if(!args.stencil && !args.shape) { - return []; - } - - // init arguments - if(args.shape) { - args.stencil = args.shape.getStencil(); - } - - var _morphStencils = []; - args.stencil.roles().each(function(role) { - this._cacheMorph(role).each(function(stencil) { - _morphStencils.push(stencil); - }) - }.bind(this)); + /** + * curvetoCubicSmoothAbs - S + * + * @param {Number} x2 + * @param {Number} y2 + * @param {Number} x + * @param {Number} y + */ + curvetoCubicSmoothAbs: function (x2, y2, x, y) { + this.addPoints([x, y]); + }, + /** + * curvetoCubicSmoothRel - s + * + * @param {Number} x2 + * @param {Number} y2 + * @param {Number} x + * @param {Number} y + */ + curvetoCubicSmoothRel: function (x2, y2, x, y) { + this.addPoints([this._lastAbsX + x, this._lastAbsY + y]); + }, - var baseMorphs = this.baseMorphs(); - // BaseMorphs should be in the front of the array - _morphStencils = _morphStencils.uniq().sort(function(a,b){ return baseMorphs.include(a)&&!baseMorphs.include(b) ? -1 : (baseMorphs.include(b)&&!baseMorphs.include(a) ? 1 : 0)}) - return _morphStencils; - }, - - /** - * @return {Array} An array of all base morph stencils - */ - baseMorphs: function() { - var _baseMorphs = []; - this._morphingRules.each(function(pair) { - pair.value.each(function(baseMorph) { - _baseMorphs.push(baseMorph); - }); - }); - return _baseMorphs; - }, - - /** - * Returns true if there are morphing rules defines - * @return {boolean} - */ - containsMorphingRules: function(){ - return this._stencilSets.any(function(ss){ return !!ss.jsonRules().morphingRules}); - }, - - /** - * - * @param {Object} - * args - * sourceStencil: - * ORYX.Core.StencilSet.Stencil | undefined - * sourceShape: - * ORYX.Core.Node |undefined - * targetStencil: - * ORYX.Core.StencilSet.Stencil | undefined - * targetShape: - * ORYX.Core.Node |undefined - * - * - * @return {Stencil} Returns, the stencil for the connecting edge - * or null if connection is not possible - */ - connectMorph: function(args) { - // check arguments - if(!args || - (!args.sourceShape && !args.sourceStencil && - !args.targetShape && !args.targetStencil)) { - return false; - } - - // init arguments - if(args.sourceShape) { - args.sourceStencil = args.sourceShape.getStencil(); - } - if(args.targetShape) { - args.targetStencil = args.targetShape.getStencil(); - } - - var incoming = this.incomingEdgeStencils(args); - var outgoing = this.outgoingEdgeStencils(args); - - var edgeStencils = incoming.select(function(e) { return outgoing.member(e); }); // intersection of sets - var baseEdgeStencils = this.baseMorphs().select(function(e) { return edgeStencils.member(e); }); // again: intersection of sets - - if(baseEdgeStencils.size()>0) - return baseEdgeStencils[0]; // return any of the possible base morphs - else if(edgeStencils.size()>0) - return edgeStencils[0]; // return any of the possible stencils - - return null; //connection not possible - }, - - /** - * Return true if the stencil should be located in the shape menu - * @param {ORYX.Core.StencilSet.Stencil} morph - * @return {Boolean} Returns true if the morphs in the morph group of the - * specified morph shall be displayed in the shape menu - */ - showInShapeMenu: function(stencil) { - return this._stencilSets.any(function(ss){ - return ss.jsonRules().morphingRules - .any(function(r){ - return stencil.roles().include(ss.namespace() + r.role) - && r.showInShapeMenu !== false; - }) - }); - }, - - preserveBounds: function(stencil) { - return this._stencilSets.any(function(ss) { - return ss.jsonRules().morphingRules.any(function(r) { - - - return stencil.roles().include(ss.namespace() + r.role) - && r.preserveBounds; - }) - }) - }, - - /** End morphing rules' methods */ + /** + * curvetoQuadraticSmoothAbs - T + * + * @param {Number} x + * @param {Number} y + */ + curvetoQuadraticSmoothAbs: function (x, y) { + this.addPoints([x, y]); + }, + /** + * curvetoQuadraticSmoothRel - t + * + * @param {Number} x + * @param {Number} y + */ + curvetoQuadraticSmoothRel: function (x, y) { + this.addPoints([this._lastAbsX + x, this._lastAbsY + y]); + }, - /** Begin layouting rules' methods */ - - /** - * Returns a set on "in" and "out" layouting rules for a given shape - * @param {Object} shape - * @param {Object} edgeShape (Optional) - * @return {Object} "in" and "out" with a default value of {"t":1, "r":1, "b":1, "r":1} if not specified in the json - */ - getLayoutingRules : function(shape, edgeShape){ - - if (!shape||!(shape instanceof ORYX.Core.Shape)){ return } - - var layout = {"in":{},"out":{}}; - - var parseValues = function(o, v){ - if (o && o[v]){ - ["t","r","b","l"].each(function (d) { - layout[v][d]=Math.max(o[v][d],layout[v][d]||0); - }); - } - if (o && o[v+"s"] instanceof Array){ - ["t","r","b","l"].each(function (d) { - var defaultRule = o[v+"s"].find(function (e) { return !e.edgeRole }); - var edgeRule; - if (edgeShape instanceof ORYX.Core.Edge) { - edgeRule = o[v + "s"].find(function (e) {return this._hasRole(edgeShape, e.edgeRole) }.bind(this)); - } - layout[v][d]=Math.max(edgeRule?edgeRule[d]:defaultRule[d],layout[v][d]||0); - }.bind(this)); - } - }.bind(this) - - // For each role - shape.getStencil().roles().each(function(role) { - // check if there are layout information - if (this._layoutRules[role]){ - // if so, parse those information to the 'layout' variable - parseValues(this._layoutRules[role], "in"); - parseValues(this._layoutRules[role], "out"); - } - }.bind(this)); - - // Make sure, that every attribute has an value, - // otherwise set 1 - ["in","out"].each(function(v){ - ["t","r","b","l"].each(function (d) { - layout[v][d]=layout[v][d]!==undefined?layout[v][d]:1; - }); - }) - - return layout; - }, - - /** End layouting rules' methods */ - - /** Helper methods */ - - /** - * Checks wether a shape contains the given role or the role is equal the stencil id - * @param {ORYX.Core.Shape} shape - * @param {String} role - */ - _hasRole: function(shape, role){ - if (!(shape instanceof ORYX.Core.Shape)||!role){ return } - var isRole = shape.getStencil().roles().any(function(r){ return r == role}); - - return isRole || shape.getStencil().id() == (shape.getStencil().namespace()+role); - }, + /** + * linetoVerticalAbs - V + * + * @param {Number} y + */ + linetoVerticalAbs: function (y) { + this.addPoints([this._lastAbsX, y]); + }, - /** - * - * @param {String} - * role - * - * @return {Array} Returns an array of stencils that can act as role. - */ - _stencilsWithRole: function(role) { - return this._stencils.findAll(function(stencil) { - return (stencil.roles().member(role)) ? true : false; - }); - }, - - /** - * - * @param {String} - * role - * - * @return {Array} Returns an array of stencils that can act as role and - * have the type 'edge'. - */ - _edgesWithRole: function(role) { - return this._stencils.findAll(function(stencil) { - return (stencil.roles().member(role) && stencil.type() === "edge") ? true : false; - }); - }, - - /** - * - * @param {String} - * role - * - * @return {Array} Returns an array of stencils that can act as role and - * have the type 'node'. - */ - _nodesWithRole: function(role) { - return this._stencils.findAll(function(stencil) { - return (stencil.roles().member(role) && stencil.type() === "node") ? true : false; - }); - }, - - /** - * - * @param {ORYX.Core.StencilSet.Stencil} - * parent - * @param {ORYX.Core.StencilSet.Stencil} - * child - * - * @returns {Boolean} Returns the maximum occurrence of shapes of the - * stencil's type inside the parent. - */ - _getMaximumOccurrence: function(parent, child) { - var max; - child.roles().each((function(role) { - var cardRule = this._cardinalityRules[role]; - if(cardRule && cardRule.maximumOccurrence) { - if(max) { - max = Math.min(max, cardRule.maximumOccurrence); - } else { - max = cardRule.maximumOccurrence; - } - } - }).bind(this)); - - return max; - }, - - - /** - * - * @param {Object} - * args sourceStencil: ORYX.Core.Node edgeStencil: - * ORYX.Core.StencilSet.Stencil - * - * @return {Boolean} Returns, the maximum number of outgoing edges of the - * type specified by edgeStencil of the sourceShape. - */ - _getMaximumNumberOfOutgoingEdge: function(args) { - if(!args || - !args.sourceStencil || - !args.edgeStencil) { - return false; - } - - var max; - args.sourceStencil.roles().each((function(role) { - var cardRule = this._cardinalityRules[role]; - - if(cardRule && cardRule.outgoingEdges) { - args.edgeStencil.roles().each(function(edgeRole) { - var oe = cardRule.outgoingEdges[edgeRole]; - - if(oe && oe.maximum) { - if(max) { - max = Math.min(max, oe.maximum); - } else { - max = oe.maximum; - } - } - }); - } - }).bind(this)); - - return max; - }, - - /** - * - * @param {Object} - * args targetStencil: ORYX.Core.StencilSet.Stencil edgeStencil: - * ORYX.Core.StencilSet.Stencil - * - * @return {Boolean} Returns the maximum number of incoming edges of the - * type specified by edgeStencil of the targetShape. - */ - _getMaximumNumberOfIncomingEdge: function(args) { - if(!args || - !args.targetStencil || - !args.edgeStencil) { - return false; - } - - var max; - args.targetStencil.roles().each((function(role) { - var cardRule = this._cardinalityRules[role]; - if(cardRule && cardRule.incomingEdges) { - args.edgeStencil.roles().each(function(edgeRole) { - var ie = cardRule.incomingEdges[edgeRole]; - if(ie && ie.maximum) { - if(max) { - max = Math.min(max, ie.maximum); - } else { - max = ie.maximum; - } - } - }); - } - }).bind(this)); + /** + * linetoVerticalRel - v + * + * @param {Number} y + */ + linetoVerticalRel: function (y) { + this.addPoints([this._lastAbsX, this._lastAbsY + y]); + }, - return max; - }, - - /** - * - * @param {ORYX.Core.StencilSet.Stencil} - * edgeStencil - * - * @return {Hash} Returns a hash map of all connection rules for - * edgeStencil. - */ - _getConnectionRulesOfEdgeStencil: function(edgeStencil) { - var edgeRules = new Hash(); - edgeStencil.roles().each((function(role) { - if(this._connectionRules[role]) { - this._connectionRules[role].each(function(cr) { - if(edgeRules[cr.key]) { - edgeRules[cr.key] = edgeRules[cr.key].concat(cr.value); - } else { - edgeRules[cr.key] = cr.value; - } - }); - } - }).bind(this)); - - return edgeRules; - }, - - _isRoleOfOtherNamespace: function(role) { - return (role.indexOf("#") > 0); - }, + /** + * closePath - z or Z + */ + closePath: function () { + return;// do nothing + } - toString: function() { return "Rules"; } -} -ORYX.Core.StencilSet.Rules = Clazz.extend(ORYX.Core.StencilSet.Rules); -/* +});/* * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. * License rights for this program may be obtained from Alfresco Software, Ltd. * pursuant to a written agreement and any use of this program without such an @@ -8137,7 +3459,22 @@ ORYX.Core.StencilSet.Rules = Clazz.extend(ORYX.Core.StencilSet.Rules); */ /** - * Init namespace + * + * Config variables + */ +NAMESPACE_ORYX = "http://www.b3mn.org/oryx"; +NAMESPACE_SVG = "http://www.w3.org/2000/svg/"; + +/** + * @classDescription This class wraps the manipulation of a SVG marker. + * @namespace ORYX.Core.SVG + * uses Inheritance (Clazz) + * uses Prototype 1.5.0 + * + */ + +/** + * Init package */ if (!ORYX) { var ORYX = {}; @@ -8145,429 +3482,174 @@ if (!ORYX) { if (!ORYX.Core) { ORYX.Core = {}; } -if (!ORYX.Core.StencilSet) { - ORYX.Core.StencilSet = {}; +if (!ORYX.Core.SVG) { + ORYX.Core.SVG = {}; } -/** - * This class represents a stencil set. It offers methods for accessing - * the attributes of the stencil set description JSON file and the stencil set's - * stencils. - */ -ORYX.Core.StencilSet.StencilSet = Clazz.extend({ +ORYX.Core.SVG.SVGMarker = Clazz.extend({ /** * Constructor - * @param source {URL} A reference to the stencil set specification. - * + * @param markerElement {SVGMarkerElement} */ - construct: function(source, modelMetaData, editorId){ + construct: function (markerElement) { arguments.callee.$.construct.apply(this, arguments); - - if (!source) { - throw "ORYX.Core.StencilSet.StencilSet(construct): Parameter 'source' is not defined."; - } - - if (source.endsWith("/")) { - source = source.substr(0, source.length - 1); - } - - this._extensions = new Hash(); - - this._source = source; - this._baseUrl = source.substring(0, source.lastIndexOf("/") + 1); - - this._jsonObject = {}; - - this._stencils = new Hash(); - this._availableStencils = new Hash(); - - if(ORYX.CONFIG.BACKEND_SWITCH) { - this._baseUrl = "editor/stencilsets/bpmn2.0/"; - this._source = "stencilsets/bpmn2.0/bpmn2.0.json"; - - new Ajax.Request(ACTIVITI.CONFIG.contextRoot + '/editor/stencilset?version=' + Date.now(), { - asynchronous: false, - method: 'get', - onSuccess: this._init.bind(this), - onFailure: this._cancelInit.bind(this) - }); - - } else { - new Ajax.Request(source, { - asynchronous: false, - method: 'get', - onSuccess: this._init.bind(this), - onFailure: this._cancelInit.bind(this) - }); - } - - if (this.errornous) - throw "Loading stencil set " + source + " failed."; - }, - - /** - * Finds a root stencil in this stencil set. There may be many of these. If - * there are, the first one found will be used. In Firefox, this is the - * topmost definition in the stencil set description file. - */ - findRootStencilName: function(){ - - // find any stencil that may be root. - var rootStencil = this._stencils.values().find(function(stencil){ - return stencil._jsonStencil.mayBeRoot - }); - - // if there is none, just guess the first. - if (!rootStencil) { - ORYX.Log.warn("Did not find any stencil that may be root. Taking a guess."); - rootStencil = this._stencils.values()[0]; - } - // return its id. - return rootStencil.id(); + this.id = undefined; + this.element = markerElement; + this.refX = undefined; + this.refY = undefined; + this.markerWidth = undefined; + this.markerHeight = undefined; + this.oldRefX = undefined; + this.oldRefY = undefined; + this.oldMarkerWidth = undefined; + this.oldMarkerHeight = undefined; + this.optional = false; + this.enabled = true; + this.minimumLength = undefined; + this.resize = false; + + this.svgShapes = []; + + this._init(); //initialisation of all the properties declared above. }, - + /** - * @param {ORYX.Core.StencilSet.StencilSet} stencilSet - * @return {Boolean} True, if stencil set has the same namespace. + * Initializes the values that are defined in the constructor. */ - equals: function(stencilSet){ - return (this.namespace() === stencilSet.namespace()); - }, - - /** - * - * @param {Oryx.Core.StencilSet.Stencil} rootStencil If rootStencil is defined, it only returns stencils - * that could be (in)direct child of that stencil. - */ - stencils: function(rootStencil, rules, sortByGroup){ - if(rootStencil && rules) { - var stencils = this._availableStencils.values(); - var containers = [rootStencil]; - var checkedContainers = []; - - var result = []; - - while (containers.size() > 0) { - var container = containers.pop(); - checkedContainers.push(container); - var children = stencils.findAll(function(stencil){ - var args = { - containingStencil: container, - containedStencil: stencil - }; - return rules.canContain(args); - }); - for(var i = 0; i < children.size(); i++) { - if (!checkedContainers.member(children[i])) { - containers.push(children[i]); - } - } - result = result.concat(children).uniq(); - } - - // Sort the result to the origin order - result = result.sortBy(function(stencil) { - return stencils.indexOf(stencil); - }); - - - if(sortByGroup) { - result = result.sortBy(function(stencil) { - return stencil.groups().first(); - }); - } - - var edges = stencils.findAll(function(stencil) { - return stencil.type() == "edge"; - }); - result = result.concat(edges); - - return result; - - } else { - if(sortByGroup) { - return this._availableStencils.values().sortBy(function(stencil) { - return stencil.groups().first(); - }); - } else { - return this._availableStencils.values(); - } - } - }, - - nodes: function(){ - return this._availableStencils.values().findAll(function(stencil){ - return (stencil.type() === 'node') - }); - }, - - edges: function(){ - return this._availableStencils.values().findAll(function(stencil){ - return (stencil.type() === 'edge') - }); - }, - - stencil: function(id){ - return this._stencils[id]; - }, - - title: function(){ - return ORYX.Core.StencilSet.getTranslation(this._jsonObject, "title"); - }, - - description: function(){ - return ORYX.Core.StencilSet.getTranslation(this._jsonObject, "description"); - }, - - namespace: function(){ - return this._jsonObject ? this._jsonObject.namespace : null; - }, - - jsonRules: function(){ - return this._jsonObject ? this._jsonObject.rules : null; - }, - - source: function(){ - return this._source; - }, - - extensions: function() { - return this._extensions; - }, - - addExtension: function(url) { - - new Ajax.Request(url, { - method: 'GET', - asynchronous: false, - onSuccess: (function(transport) { - this.addExtensionDirectly(transport.responseText); - }).bind(this), - onFailure: (function(transport) { - ORYX.Log.debug("Loading stencil set extension file failed. The request returned an error." + transport); - }).bind(this), - onException: (function(transport) { - ORYX.Log.debug("Loading stencil set extension file failed. The request returned an error." + transport); - }).bind(this) - - }); - }, - - addExtensionDirectly: function(str){ - - try { - eval("var jsonExtension = " + str); - - if(!(jsonExtension["extends"].endsWith("#"))) - jsonExtension["extends"] += "#"; - - if(jsonExtension["extends"] == this.namespace()) { - this._extensions[jsonExtension.namespace] = jsonExtension; - - var defaultPosition = this._stencils.keys().size(); - //load new stencils - if(jsonExtension.stencils) { - $A(jsonExtension.stencils).each(function(stencil) { - defaultPosition++; - var oStencil = new ORYX.Core.StencilSet.Stencil(stencil, this.namespace(), this._baseUrl, this, undefined, defaultPosition); - this._stencils[oStencil.id()] = oStencil; - this._availableStencils[oStencil.id()] = oStencil; - }.bind(this)); - } - - //load additional properties - if (jsonExtension.properties) { - var stencils = this._stencils.values(); - - stencils.each(function(stencil){ - var roles = stencil.roles(); - - jsonExtension.properties.each(function(prop){ - prop.roles.any(function(role){ - role = jsonExtension["extends"] + role; - if (roles.member(role)) { - prop.properties.each(function(property){ - stencil.addProperty(property, jsonExtension.namespace); - }); - - return true; - } - else - return false; - }) - }) - }.bind(this)); - } - - //remove stencil properties - if(jsonExtension.removeproperties) { - jsonExtension.removeproperties.each(function(remprop) { - var stencil = this.stencil(jsonExtension["extends"] + remprop.stencil); - if(stencil) { - remprop.properties.each(function(propId) { - stencil.removeProperty(propId); - }); - } - }.bind(this)); - } - - //remove stencils - if(jsonExtension.removestencils) { - $A(jsonExtension.removestencils).each(function(remstencil) { - delete this._availableStencils[jsonExtension["extends"] + remstencil]; - }.bind(this)); - } - } - } catch (e) { - ORYX.Log.debug("StencilSet.addExtension: Something went wrong when initialising the stencil set extension. " + e); - } - }, - - removeExtension: function(namespace) { - var jsonExtension = this._extensions[namespace]; - if(jsonExtension) { - - //unload extension's stencils - if(jsonExtension.stencils) { - $A(jsonExtension.stencils).each(function(stencil) { - var oStencil = new ORYX.Core.StencilSet.Stencil(stencil, this.namespace(), this._baseUrl, this); - delete this._stencils[oStencil.id()]; // maybe not ?? - delete this._availableStencils[oStencil.id()]; - }.bind(this)); - } - - //unload extension's properties - if (jsonExtension.properties) { - var stencils = this._stencils.values(); - - stencils.each(function(stencil){ - var roles = stencil.roles(); - - jsonExtension.properties.each(function(prop){ - prop.roles.any(function(role){ - role = jsonExtension["extends"] + role; - if (roles.member(role)) { - prop.properties.each(function(property){ - stencil.removeProperty(property.id); - }); - - return true; - } - else - return false; - }) - }) - }.bind(this)); - } - - //restore removed stencil properties - if(jsonExtension.removeproperties) { - jsonExtension.removeproperties.each(function(remprop) { - var stencil = this.stencil(jsonExtension["extends"] + remprop.stencil); - if(stencil) { - var stencilJson = $A(this._jsonObject.stencils).find(function(s) { return s.id == stencil.id() }); - remprop.properties.each(function(propId) { - var propertyJson = $A(stencilJson.properties).find(function(p) { return p.id == propId }); - stencil.addProperty(propertyJson, this.namespace()); - }.bind(this)); - } - }.bind(this)); - } - - //restore removed stencils - if(jsonExtension.removestencils) { - $A(jsonExtension.removestencils).each(function(remstencil) { - var sId = jsonExtension["extends"] + remstencil; - this._availableStencils[sId] = this._stencils[sId]; - }.bind(this)); - } - } - delete this._extensions[namespace]; - }, - - __handleStencilset: function(response){ - - try { - // using eval instead of prototype's parsing, - // since there are functions in this JSON. - eval("this._jsonObject =" + response.responseText); - } - catch (e) { - throw "Stenciset corrupt: " + e; + _init: function () { + //check if this.element is a SVGMarkerElement + if (!(this.element == "[object SVGMarkerElement]")) { + throw "SVGMarker: Argument is not an instance of SVGMarkerElement."; } - - // assert it was parsed. - if (!this._jsonObject) { - throw "Error evaluating stencilset. It may be corrupt."; + + this.id = this.element.getAttributeNS(null, "id"); + + //init svg marker attributes + var refXValue = this.element.getAttributeNS(null, "refX"); + if (refXValue) { + this.refX = parseFloat(refXValue); + } else { + this.refX = 0; } - - with (this._jsonObject) { - - // assert there is a namespace. - if (!namespace || namespace === "") - throw "Namespace definition missing in stencilset."; - - if (!(stencils instanceof Array)) - throw "Stencilset corrupt."; - - // assert namespace ends with '#'. - if (!namespace.endsWith("#")) - namespace = namespace + "#"; - - // assert title and description are strings. - if (!title) - title = ""; - if (!description) - description = ""; + var refYValue = this.element.getAttributeNS(null, "refY"); + if (refYValue) { + this.refY = parseFloat(refYValue); + } else { + this.refY = 0; + } + var markerWidthValue = this.element.getAttributeNS(null, "markerWidth"); + if (markerWidthValue) { + this.markerWidth = parseFloat(markerWidthValue); + } else { + this.markerWidth = 3; + } + var markerHeightValue = this.element.getAttributeNS(null, "markerHeight"); + if (markerHeightValue) { + this.markerHeight = parseFloat(markerHeightValue); + } else { + this.markerHeight = 3; + } + + this.oldRefX = this.refX; + this.oldRefY = this.refY; + this.oldMarkerWidth = this.markerWidth; + this.oldMarkerHeight = this.markerHeight; + + //init oryx attributes + var optionalAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "optional"); + if (optionalAttr) { + optionalAttr = optionalAttr.strip(); + this.optional = (optionalAttr.toLowerCase() === "yes"); + } else { + this.optional = false; + } + + var enabledAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "enabled"); + if (enabledAttr) { + enabledAttr = enabledAttr.strip(); + this.enabled = !(enabledAttr.toLowerCase() === "no"); + } else { + this.enabled = true; + } + + var minLengthAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "minimumLength"); + if (minLengthAttr) { + this.minimumLength = parseFloat(minLengthAttr); } + + var resizeAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "resize"); + if (resizeAttr) { + resizeAttr = resizeAttr.strip(); + this.resize = (resizeAttr.toLowerCase() === "yes"); + } else { + this.resize = false; + } + + //init SVGShape objects + //this.svgShapes = this._getSVGShapes(this.element); }, - + /** - * This method is called when the HTTP request to get the requested stencil - * set succeeds. The response is supposed to be a JSON representation - * according to the stencil set specification. - * @param {Object} response The JSON representation according to the - * stencil set specification. + * */ - _init: function(response){ - - // init and check consistency. - this.__handleStencilset(response); - - var pps = new Hash(); - - // init property packages - if(this._jsonObject.propertyPackages) { - $A(this._jsonObject.propertyPackages).each((function(pp) { - pps[pp.name] = pp.properties; - }).bind(this)); - } - - var defaultPosition = 0; - - // init each stencil - $A(this._jsonObject.stencils).each((function(stencil){ - defaultPosition++; - - // instantiate normally. - var oStencil = new ORYX.Core.StencilSet.Stencil(stencil, this.namespace(), this._baseUrl, this, pps, defaultPosition); - this._stencils[oStencil.id()] = oStencil; - this._availableStencils[oStencil.id()] = oStencil; - - }).bind(this)); + _getSVGShapes: function (svgElement) { + if (svgElement.hasChildNodes) { + var svgShapes = []; + var me = this; + $A(svgElement.childNodes).each(function (svgChild) { + try { + var svgShape = new ORYX.Core.SVG.SVGShape(svgChild); + svgShapes.push(svgShape); + } catch (e) { + svgShapes = svgShapes.concat(me._getSVGShapes(svgChild)); + } + }); + return svgShapes; + } }, - - _cancelInit: function(response){ - this.errornous = true; + + /** + * Writes the changed values into the SVG marker. + */ + update: function () { + //TODO mache marker resizebar!!! aber erst wenn der rest der connectingshape funzt! + +// //update marker attributes +// if(this.refX != this.oldRefX) { +// this.element.setAttributeNS(null, "refX", this.refX); +// } +// if(this.refY != this.oldRefY) { +// this.element.setAttributeNS(null, "refY", this.refY); +// } +// if(this.markerWidth != this.oldMarkerWidth) { +// this.element.setAttributeNS(null, "markerWidth", this.markerWidth); +// } +// if(this.markerHeight != this.oldMarkerHeight) { +// this.element.setAttributeNS(null, "markerHeight", this.markerHeight); +// } +// +// //update SVGShape objects +// var widthDelta = this.markerWidth / this.oldMarkerWidth; +// var heightDelta = this.markerHeight / this.oldMarkerHeight; +// if(widthDelta != 1 && heightDelta != 1) { +// this.svgShapes.each(function(svgShape) { +// +// }); +// } + + //update old values to prepare the next update + this.oldRefX = this.refX; + this.oldRefY = this.refY; + this.oldMarkerWidth = this.markerWidth; + this.oldMarkerHeight = this.markerHeight; }, - - toString: function(){ - return "StencilSet " + this.title() + " (" + this.namespace() + ")"; + + toString: function () { + return (this.element) ? "SVGMarker " + this.element.id : "SVGMarker " + this.element; } -}); -/* +});/* * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. * License rights for this program may be obtained from Alfresco Software, Ltd. * pursuant to a written agreement and any use of this program without such an @@ -8578,211 +3660,565 @@ ORYX.Core.StencilSet.StencilSet = Clazz.extend({ */ /** - * Init namespace + * + * Config variables */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} -if(!ORYX.Core.StencilSet) {ORYX.Core.StencilSet = {};} +NAMESPACE_ORYX = "http://www.b3mn.org/oryx"; +NAMESPACE_SVG = "http://www.w3.org/2000/svg/"; /** - * Class StencilSets - * uses Prototpye 1.5.0 - * uses Inheritance + * @classDescription This class wraps the manipulation of a SVG basic shape or a path. + * @namespace ORYX.Core.SVG + * uses Inheritance (Clazz) + * uses Prototype 1.5.0 + * uses PathParser by Kevin Lindsey (http://kevlindev.com/) + * uses MinMaxPathHandler + * uses EditPathHandler * - * Singleton */ -//storage for loaded stencil sets by namespace -ORYX.Core.StencilSet._stencilSetsByNamespace = new Hash(); -//storage for stencil sets by url -ORYX.Core.StencilSet._stencilSetsByUrl = new Hash(); +//init package +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} +if (!ORYX.Core.SVG) { + ORYX.Core.SVG = {}; +} -//storage for stencil set namespaces by editor instances -ORYX.Core.StencilSet._StencilSetNSByEditorInstance = new Hash(); +ORYX.Core.SVG.SVGShape = Clazz.extend({ -//storage for rules by editor instances -ORYX.Core.StencilSet._rulesByEditorInstance = new Hash(); + /** + * Constructor + * @param svgElem {SVGElement} An SVGElement that is a basic shape or a path. + */ + construct: function (svgElem) { + arguments.callee.$.construct.apply(this, arguments); -/** - * - * @param {String} editorId - * - * @return {Hash} Returns a hash map with all stencil sets that are loaded by - * the editor with the editorId. - */ -ORYX.Core.StencilSet.stencilSets = function(editorId) { - var stencilSetNSs = ORYX.Core.StencilSet._StencilSetNSByEditorInstance[editorId]; - var stencilSets = new Hash(); - if(stencilSetNSs) { - stencilSetNSs.each(function(stencilSetNS) { - var stencilSet = ORYX.Core.StencilSet.stencilSet(stencilSetNS) - stencilSets[stencilSet.namespace()] = stencilSet; - }); - } - return stencilSets; -}; + this.type; + this.element = svgElem; + this.x = undefined; + this.y = undefined; + this.width = undefined; + this.height = undefined; + this.oldX = undefined; + this.oldY = undefined; + this.oldWidth = undefined; + this.oldHeight = undefined; + this.radiusX = undefined; + this.radiusY = undefined; + this.isHorizontallyResizable = false; + this.isVerticallyResizable = false; + //this.anchors = []; + this.anchorLeft = false; + this.anchorRight = false; + this.anchorTop = false; + this.anchorBottom = false; -/** - * - * @param {String} namespace - * - * @return {ORYX.Core.StencilSet.StencilSet} Returns the stencil set with the specified - * namespace. - * - * The method can handle namespace strings like - * http://www.example.org/stencilset - * http://www.example.org/stencilset# - * http://www.example.org/stencilset#ANode - */ -ORYX.Core.StencilSet.stencilSet = function(namespace) { - ORYX.Log.trace("Getting stencil set %0", namespace); - var splitted = namespace.split("#", 1); - if(splitted.length === 1) { - ORYX.Log.trace("Getting stencil set %0", splitted[0]); - return ORYX.Core.StencilSet._stencilSetsByNamespace[splitted[0] + "#"]; - } else { - return undefined; - } -}; + //attributes of path elements of edge objects + this.allowDockers = true; + this.resizeMarkerMid = false; -/** - * - * @param {String} id - * - * @return {ORYX.Core.StencilSet.Stencil} Returns the stencil specified by the id. - * - * The id must be unique and contains the namespace of the stencil's stencil set. - * e.g. http://www.example.org/stencilset#ANode - */ -ORYX.Core.StencilSet.stencil = function(id) { - ORYX.Log.trace("Getting stencil for %0", id); - var ss = ORYX.Core.StencilSet.stencilSet(id); - if(ss) { - return ss.stencil(id); - } else { - - ORYX.Log.trace("Cannot fild stencil for %0", id); - return undefined; - } -}; + this.editPathParser; + this.editPathHandler; -/** - * - * @param {String} editorId - * - * @return {ORYX.Core.StencilSet.Rules} Returns the rules object for the editor - * specified by its editor id. - */ -ORYX.Core.StencilSet.rules = function(editorId) { - if(!ORYX.Core.StencilSet._rulesByEditorInstance[editorId]) { - ORYX.Core.StencilSet._rulesByEditorInstance[editorId] = new ORYX.Core.StencilSet.Rules(); - } - return ORYX.Core.StencilSet._rulesByEditorInstance[editorId]; -}; + this.init(); //initialisation of all the properties declared above. + }, -/** - * - * @param {String} url - * @param {String} editorId - * - * Loads a stencil set from url, if it is not already loaded. - * It also stores which editor instance loads the stencil set and - * initializes the Rules object for the editor instance. - */ -ORYX.Core.StencilSet.loadStencilSet = function(url, modelMetaData, editorId) { - - // Alfresco: disable cache, because stencil sets are now flexible - - //var stencilSet = ORYX.Core.StencilSet._stencilSetsByUrl[url]; - - //if(!stencilSet) { - //load stencil set - stencilSet = new ORYX.Core.StencilSet.StencilSet(url, modelMetaData, editorId); - - //store stencil set - ORYX.Core.StencilSet._stencilSetsByNamespace[stencilSet.namespace()] = stencilSet; - - //store stencil set by url - ORYX.Core.StencilSet._stencilSetsByUrl[url] = stencilSet; - //} - - var namespace = stencilSet.namespace(); - - //store which editorInstance loads the stencil set - if(ORYX.Core.StencilSet._StencilSetNSByEditorInstance[editorId]) { - ORYX.Core.StencilSet._StencilSetNSByEditorInstance[editorId].push(namespace); - } else { - ORYX.Core.StencilSet._StencilSetNSByEditorInstance[editorId] = [namespace]; - } - - //store the rules for the editor instance - if(ORYX.Core.StencilSet._rulesByEditorInstance[editorId]) { - ORYX.Core.StencilSet._rulesByEditorInstance[editorId].initializeRules(stencilSet); - } else { - var rules = new ORYX.Core.StencilSet.Rules(); - rules.initializeRules(stencilSet); - ORYX.Core.StencilSet._rulesByEditorInstance[editorId] = rules; - } -}; + /** + * Initializes the values that are defined in the constructor. + */ + init: function () { -/** - * Returns the translation of an attribute in jsonObject specified by its name - * according to navigator.language - */ -ORYX.Core.StencilSet.getTranslation = function(jsonObject, name) { - var lang = ORYX.I18N.Language.toLowerCase(); - - var result = jsonObject[name + "_" + lang]; - - if(result) - return result; - - result = jsonObject[name + "_" + lang.substr(0, 2)]; - - if(result) - return result; - - return jsonObject[name]; -}; -/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + /**initialize position and size*/ + if (ORYX.Editor.checkClassType(this.element, SVGRectElement) || ORYX.Editor.checkClassType(this.element, SVGImageElement)) { + this.type = "Rect"; -/** - * Init namespaces - */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} + var xAttr = this.element.getAttributeNS(null, "x"); + if (xAttr) { + this.oldX = parseFloat(xAttr); + } else { + throw "Missing attribute in element " + this.element; + } + var yAttr = this.element.getAttributeNS(null, "y"); + if (yAttr) { + this.oldY = parseFloat(yAttr); + } else { + throw "Missing attribute in element " + this.element; + } + var widthAttr = this.element.getAttributeNS(null, "width"); + if (widthAttr) { + this.oldWidth = parseFloat(widthAttr); + } else { + throw "Missing attribute in element " + this.element; + } + var heightAttr = this.element.getAttributeNS(null, "height"); + if (heightAttr) { + this.oldHeight = parseFloat(heightAttr); + } else { + throw "Missing attribute in element " + this.element; + } + } else if (ORYX.Editor.checkClassType(this.element, SVGCircleElement)) { + this.type = "Circle"; -/** - * @classDescription With Bounds you can set and get position and size of UIObjects. - */ -ORYX.Core.Command = Clazz.extend({ + var cx = undefined; + var cy = undefined; + //var r = undefined; - /** - * Constructor - */ - construct: function() { + var cxAttr = this.element.getAttributeNS(null, "cx"); + if (cxAttr) { + cx = parseFloat(cxAttr); + } else { + throw "Missing attribute in element " + this.element; + } + var cyAttr = this.element.getAttributeNS(null, "cy"); + if (cyAttr) { + cy = parseFloat(cyAttr); + } else { + throw "Missing attribute in element " + this.element; + } + var rAttr = this.element.getAttributeNS(null, "r"); + if (rAttr) { + //r = parseFloat(rAttr); + this.radiusX = parseFloat(rAttr); + } else { + throw "Missing attribute in element " + this.element; + } + this.oldX = cx - this.radiusX; + this.oldY = cy - this.radiusX; + this.oldWidth = 2 * this.radiusX; + this.oldHeight = 2 * this.radiusX; + + } else if (ORYX.Editor.checkClassType(this.element, SVGEllipseElement)) { + this.type = "Ellipse"; + + var cx = undefined; + var cy = undefined; + //var rx = undefined; + //var ry = undefined; + var cxAttr = this.element.getAttributeNS(null, "cx"); + if (cxAttr) { + cx = parseFloat(cxAttr); + } else { + throw "Missing attribute in element " + this.element; + } + var cyAttr = this.element.getAttributeNS(null, "cy"); + if (cyAttr) { + cy = parseFloat(cyAttr); + } else { + throw "Missing attribute in element " + this.element; + } + var rxAttr = this.element.getAttributeNS(null, "rx"); + if (rxAttr) { + this.radiusX = parseFloat(rxAttr); + } else { + throw "Missing attribute in element " + this.element; + } + var ryAttr = this.element.getAttributeNS(null, "ry"); + if (ryAttr) { + this.radiusY = parseFloat(ryAttr); + } else { + throw "Missing attribute in element " + this.element; + } + this.oldX = cx - this.radiusX; + this.oldY = cy - this.radiusY; + this.oldWidth = 2 * this.radiusX; + this.oldHeight = 2 * this.radiusY; + + } else if (ORYX.Editor.checkClassType(this.element, SVGLineElement)) { + this.type = "Line"; + + var x1 = undefined; + var y1 = undefined; + var x2 = undefined; + var y2 = undefined; + var x1Attr = this.element.getAttributeNS(null, "x1"); + if (x1Attr) { + x1 = parseFloat(x1Attr); + } else { + throw "Missing attribute in element " + this.element; + } + var y1Attr = this.element.getAttributeNS(null, "y1"); + if (y1Attr) { + y1 = parseFloat(y1Attr); + } else { + throw "Missing attribute in element " + this.element; + } + var x2Attr = this.element.getAttributeNS(null, "x2"); + if (x2Attr) { + x2 = parseFloat(x2Attr); + } else { + throw "Missing attribute in element " + this.element; + } + var y2Attr = this.element.getAttributeNS(null, "y2"); + if (y2Attr) { + y2 = parseFloat(y2Attr); + } else { + throw "Missing attribute in element " + this.element; + } + this.oldX = Math.min(x1, x2); + this.oldY = Math.min(y1, y2); + this.oldWidth = Math.abs(x1 - x2); + this.oldHeight = Math.abs(y1 - y2); + + } else if (ORYX.Editor.checkClassType(this.element, SVGPolylineElement) || ORYX.Editor.checkClassType(this.element, SVGPolygonElement)) { + this.type = "Polyline"; + + var pointsArray = []; + if (this.element.points && this.element.points.numberOfItems) { + for (var i = 0, size = this.element.points.numberOfItems; i < size; i++) { + pointsArray.push(this.element.points.getItem(i).x) + pointsArray.push(this.element.points.getItem(i).y) + } + } else { + var points = this.element.getAttributeNS(null, "points"); + if (points) { + points = points.replace(/,/g, " "); + pointsArray = points.split(" "); + pointsArray = pointsArray.without(""); + } else { + throw "Missing attribute in element " + this.element; + } + } - }, - - execute: function(){ - throw "Command.execute() has to be implemented!" - }, - - rollback: function(){ - throw "Command.rollback() has to be implemented!" - } - - - });/* + + if (pointsArray && pointsArray.length && pointsArray.length > 1) { + var minX = parseFloat(pointsArray[0]); + var minY = parseFloat(pointsArray[1]); + var maxX = parseFloat(pointsArray[0]); + var maxY = parseFloat(pointsArray[1]); + + for (var i = 0; i < pointsArray.length; i++) { + minX = Math.min(minX, parseFloat(pointsArray[i])); + maxX = Math.max(maxX, parseFloat(pointsArray[i])); + i++; + minY = Math.min(minY, parseFloat(pointsArray[i])); + maxY = Math.max(maxY, parseFloat(pointsArray[i])); + } + + this.oldX = minX; + this.oldY = minY; + this.oldWidth = maxX - minX; + this.oldHeight = maxY - minY; + } else { + throw "Missing attribute in element " + this.element; + } + + } else if (ORYX.Editor.checkClassType(this.element, SVGPathElement)) { + this.type = "Path"; + + this.editPathParser = new PathParser(); + this.editPathHandler = new ORYX.Core.SVG.EditPathHandler(); + this.editPathParser.setHandler(this.editPathHandler); + + var parser = new PathParser(); + var handler = new ORYX.Core.SVG.MinMaxPathHandler(); + parser.setHandler(handler); + parser.parsePath(this.element); + + this.oldX = handler.minX; + this.oldY = handler.minY; + this.oldWidth = handler.maxX - handler.minX; + this.oldHeight = handler.maxY - handler.minY; + + delete parser; + delete handler; + } else { + throw "Element is not a shape."; + } + + /** initialize attributes of oryx namespace */ + //resize + var resizeAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "resize"); + if (resizeAttr) { + resizeAttr = resizeAttr.toLowerCase(); + if (resizeAttr.match(/horizontal/)) { + this.isHorizontallyResizable = true; + } else { + this.isHorizontallyResizable = false; + } + if (resizeAttr.match(/vertical/)) { + this.isVerticallyResizable = true; + } else { + this.isVerticallyResizable = false; + } + } else { + this.isHorizontallyResizable = false; + this.isVerticallyResizable = false; + } + + //anchors + var anchorAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "anchors"); + if (anchorAttr) { + anchorAttr = anchorAttr.replace("/,/g", " "); + var anchors = anchorAttr.split(" ").without(""); + + for (var i = 0; i < anchors.length; i++) { + switch (anchors[i].toLowerCase()) { + case "left": + this.anchorLeft = true; + break; + case "right": + this.anchorRight = true; + break; + case "top": + this.anchorTop = true; + break; + case "bottom": + this.anchorBottom = true; + break; + } + } + } + + //allowDockers and resizeMarkerMid + if (ORYX.Editor.checkClassType(this.element, SVGPathElement)) { + var allowDockersAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "allowDockers"); + if (allowDockersAttr) { + if (allowDockersAttr.toLowerCase() === "no") { + this.allowDockers = false; + } else { + this.allowDockers = true; + } + } + + var resizeMarkerMidAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "resizeMarker-mid"); + if (resizeMarkerMidAttr) { + if (resizeMarkerMidAttr.toLowerCase() === "yes") { + this.resizeMarkerMid = true; + } else { + this.resizeMarkerMid = false; + } + } + } + + this.x = this.oldX; + this.y = this.oldY; + this.width = this.oldWidth; + this.height = this.oldHeight; + }, + + /** + * Writes the changed values into the SVG element. + */ + update: function () { + + if (this.x !== this.oldX || this.y !== this.oldY || this.width !== this.oldWidth || this.height !== this.oldHeight) { + switch (this.type) { + case "Rect": + if (this.x !== this.oldX) this.element.setAttributeNS(null, "x", this.x); + if (this.y !== this.oldY) this.element.setAttributeNS(null, "y", this.y); + if (this.width !== this.oldWidth) this.element.setAttributeNS(null, "width", this.width); + if (this.height !== this.oldHeight) this.element.setAttributeNS(null, "height", this.height); + break; + case "Circle": + //calculate the radius + //var r; +// if(this.width/this.oldWidth <= this.height/this.oldHeight) { +// this.radiusX = ((this.width > this.height) ? this.width : this.height)/2.0; +// } else { + this.radiusX = ((this.width < this.height) ? this.width : this.height) / 2.0; + //} + + this.element.setAttributeNS(null, "cx", this.x + this.width / 2.0); + this.element.setAttributeNS(null, "cy", this.y + this.height / 2.0); + this.element.setAttributeNS(null, "r", this.radiusX); + break; + case "Ellipse": + this.radiusX = this.width / 2; + this.radiusY = this.height / 2; + + this.element.setAttributeNS(null, "cx", this.x + this.radiusX); + this.element.setAttributeNS(null, "cy", this.y + this.radiusY); + this.element.setAttributeNS(null, "rx", this.radiusX); + this.element.setAttributeNS(null, "ry", this.radiusY); + break; + case "Line": + if (this.x !== this.oldX) + this.element.setAttributeNS(null, "x1", this.x); + + if (this.y !== this.oldY) + this.element.setAttributeNS(null, "y1", this.y); + + if (this.x !== this.oldX || this.width !== this.oldWidth) + this.element.setAttributeNS(null, "x2", this.x + this.width); + + if (this.y !== this.oldY || this.height !== this.oldHeight) + this.element.setAttributeNS(null, "y2", this.y + this.height); + break; + case "Polyline": + var points = this.element.getAttributeNS(null, "points"); + if (points) { + points = points.replace(/,/g, " ").split(" ").without(""); + + if (points && points.length && points.length > 1) { + + //TODO what if oldWidth == 0? + var widthDelta = (this.oldWidth === 0) ? 0 : this.width / this.oldWidth; + var heightDelta = (this.oldHeight === 0) ? 0 : this.height / this.oldHeight; + + var updatedPoints = ""; + for (var i = 0; i < points.length; i++) { + var x = (parseFloat(points[i]) - this.oldX) * widthDelta + this.x; + i++; + var y = (parseFloat(points[i]) - this.oldY) * heightDelta + this.y; + updatedPoints += x + " " + y + " "; + } + this.element.setAttributeNS(null, "points", updatedPoints); + } else { + //TODO error + } + } else { + //TODO error + } + break; + case "Path": + //calculate scaling delta + //TODO what if oldWidth == 0? + var widthDelta = (this.oldWidth === 0) ? 0 : this.width / this.oldWidth; + var heightDelta = (this.oldHeight === 0) ? 0 : this.height / this.oldHeight; + + //use path parser to edit each point of the path + this.editPathHandler.init(this.x, this.y, this.oldX, this.oldY, widthDelta, heightDelta); + this.editPathParser.parsePath(this.element); + + //change d attribute of path + this.element.setAttributeNS(null, "d", this.editPathHandler.d); + break; + } + + this.oldX = this.x; + this.oldY = this.y; + this.oldWidth = this.width; + this.oldHeight = this.height; + } + + // Remove cached variables + delete this.visible; + delete this.handler; + }, + + isPointIncluded: function (pointX, pointY) { + + // Check if there are the right arguments and if the node is visible + if (!pointX || !pointY || !this.isVisible()) { + return false; + } + + switch (this.type) { + case "Rect": + return (pointX >= this.x && pointX <= this.x + this.width && + pointY >= this.y && pointY <= this.y + this.height); + break; + case "Circle": + //calculate the radius +// var r; +// if(this.width/this.oldWidth <= this.height/this.oldHeight) { +// r = ((this.width > this.height) ? this.width : this.height)/2.0; +// } else { +// r = ((this.width < this.height) ? this.width : this.height)/2.0; +// } + return ORYX.Core.Math.isPointInEllipse(pointX, pointY, this.x + this.width / 2.0, this.y + this.height / 2.0, this.radiusX, this.radiusX); + break; + case "Ellipse": + return ORYX.Core.Math.isPointInEllipse(pointX, pointY, this.x + this.radiusX, this.y + this.radiusY, this.radiusX, this.radiusY); + break; + case "Line": + return ORYX.Core.Math.isPointInLine(pointX, pointY, this.x, this.y, this.x + this.width, this.y + this.height); + break; + case "Polyline": + var points = this.element.getAttributeNS(null, "points"); + + if (points) { + points = points.replace(/,/g, " ").split(" ").without(""); + + points = points.collect(function (n) { + return parseFloat(n); + }); + + return ORYX.Core.Math.isPointInPolygone(pointX, pointY, points); + } else { + return false; + } + break; + case "Path": + + // Cache Path handler + if (!this.handler) { + var parser = new PathParser(); + this.handler = new ORYX.Core.SVG.PointsPathHandler(); + parser.setHandler(this.handler); + parser.parsePath(this.element); + } + + return ORYX.Core.Math.isPointInPolygone(pointX, pointY, this.handler.points); + + break; + default: + return false; + } + }, + + /** + * Returns true if the element is visible + * @param {SVGElement} elem + * @return boolean + */ + isVisible: function (elem) { + + if (this.visible !== undefined) { + return this.visible; + } + + if (!elem) { + elem = this.element; + } + + var hasOwnerSVG = false; + try { + hasOwnerSVG = !!elem.ownerSVGElement; + } catch (e) { + } + + // Is SVG context + if (hasOwnerSVG) { + // IF G-Element + if (ORYX.Editor.checkClassType(elem, SVGGElement)) { + if (elem.className && elem.className.baseVal == "me") { + this.visible = true; + return this.visible; + } + } + + // Check if fill or stroke is set + var fill = elem.getAttributeNS(null, "fill"); + var stroke = elem.getAttributeNS(null, "stroke"); + if (fill && fill == "none" && stroke && stroke == "none") { + this.visible = false; + } else { + // Check if displayed + var attr = elem.getAttributeNS(null, "display"); + if (!attr) + this.visible = this.isVisible(elem.parentNode); + else if (attr == "none") + this.visible = false; + else + this.visible = true; + } + } else { + this.visible = true; + } + + return this.visible; + }, + + toString: function () { + return (this.element) ? "SVGShape " + this.element.id : "SVGShape " + this.element; + } +});/* * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. * License rights for this program may be obtained from Alfresco Software, Ltd. * pursuant to a written agreement and any use of this program without such an @@ -8795,3809 +4231,1149 @@ ORYX.Core.Command = Clazz.extend({ /** * Init namespaces */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} - +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} +if (!ORYX.Core.SVG) { + ORYX.Core.SVG = {}; +} /** - * @classDescription With Bounds you can set and get position and size of UIObjects. + * @classDescription Class for adding text to a shape. + * */ -ORYX.Core.Bounds = { +ORYX.Core.SVG.Label = Clazz.extend({ - /** - * Constructor - */ - construct: function() { - this._changedCallbacks = []; //register a callback with changedCallacks.push(this.method.bind(this)); - this.a = {}; - this.b = {}; - this.set.apply(this, arguments); - this.suspendChange = false; - this.changedWhileSuspend = false; - }, - - /** - * Calls all registered callbacks. - */ - _changed: function(sizeChanged) { - if(!this.suspendChange) { - this._changedCallbacks.each(function(callback) { - callback(this, sizeChanged); - }.bind(this)); - this.changedWhileSuspend = false; - } else - this.changedWhileSuspend = true; - }, - - /** - * Registers a callback that is called, if the bounds changes. - * @param callback {Function} The callback function. - */ - registerCallback: function(callback) { - if(!this._changedCallbacks.member(callback)) { - this._changedCallbacks.push(callback); - } - }, - - /** - * Unregisters a callback. - * @param callback {Function} The callback function. - */ - unregisterCallback: function(callback) { - this._changedCallbacks = this._changedCallbacks.without(callback); - }, - - /** - * Sets position and size of the shape dependent of four coordinates - * (set(ax, ay, bx, by);), two points (set({x: ax, y: ay}, {x: bx, y: by});) - * or one bound (set({a: {x: ax, y: ay}, b: {x: bx, y: by}});). - */ - set: function() { - - var changed = false; - - switch (arguments.length) { - - case 1: - if(this.a.x !== arguments[0].a.x) { - changed = true; - this.a.x = arguments[0].a.x; - } - if(this.a.y !== arguments[0].a.y) { - changed = true; - this.a.y = arguments[0].a.y; - } - if(this.b.x !== arguments[0].b.x) { - changed = true; - this.b.x = arguments[0].b.x; - } - if(this.b.y !== arguments[0].b.y) { - changed = true; - this.b.y = arguments[0].b.y; - } - break; - - case 2: - var ax = Math.min(arguments[0].x, arguments[1].x); - var ay = Math.min(arguments[0].y, arguments[1].y); - var bx = Math.max(arguments[0].x, arguments[1].x); - var by = Math.max(arguments[0].y, arguments[1].y); - if(this.a.x !== ax) { - changed = true; - this.a.x = ax; - } - if(this.a.y !== ay) { - changed = true; - this.a.y = ay; - } - if(this.b.x !== bx) { - changed = true; - this.b.x = bx; - } - if(this.b.y !== by) { - changed = true; - this.b.y = by; - } - break; - - case 4: - var ax = Math.min(arguments[0], arguments[2]); - var ay = Math.min(arguments[1], arguments[3]); - var bx = Math.max(arguments[0], arguments[2]); - var by = Math.max(arguments[1], arguments[3]); - if(this.a.x !== ax) { - changed = true; - this.a.x = ax; - } - if(this.a.y !== ay) { - changed = true; - this.a.y = ay; - } - if(this.b.x !== bx) { - changed = true; - this.b.x = bx; - } - if(this.b.y !== by) { - changed = true; - this.b.y = by; - } - break; - } - - if(changed) { - this._changed(true); - } - }, - - /** - * Moves the bounds so that the point p will be the new upper left corner. - * @param {Point} p - * or - * @param {Number} x - * @param {Number} y - */ - moveTo: function() { - - var currentPosition = this.upperLeft(); - switch (arguments.length) { - case 1: - this.moveBy({ - x: arguments[0].x - currentPosition.x, - y: arguments[0].y - currentPosition.y - }); - break; - case 2: - this.moveBy({ - x: arguments[0] - currentPosition.x, - y: arguments[1] - currentPosition.y - }); - break; - default: - //TODO error - } - - }, - - /** - * Moves the bounds relatively by p. - * @param {Point} p - * or - * @param {Number} x - * @param {Number} y - * - */ - moveBy: function() { - var changed = false; - - switch (arguments.length) { - case 1: - var p = arguments[0]; - if(p.x !== 0 || p.y !== 0) { - changed = true; - this.a.x += p.x; - this.b.x += p.x; - this.a.y += p.y; - this.b.y += p.y; - } - break; - case 2: - var x = arguments[0]; - var y = arguments[1]; - if(x !== 0 || y !== 0) { - changed = true; - this.a.x += x; - this.b.x += x; - this.a.y += y; - this.b.y += y; - } - break; - default: - //TODO error - } - - if(changed) { - this._changed(); - } - }, - - /*** - * Includes the bounds b into the current bounds. - * @param {Bounds} b - */ - include: function(b) { - - if( (this.a.x === undefined) && (this.a.y === undefined) && - (this.b.x === undefined) && (this.b.y === undefined)) { - return b; - }; - - var cx = Math.min(this.a.x,b.a.x); - var cy = Math.min(this.a.y,b.a.y); - - var dx = Math.max(this.b.x,b.b.x); - var dy = Math.max(this.b.y,b.b.y); - - - this.set(cx, cy, dx, dy); - }, - - /** - * Relatively extends the bounds by p. - * @param {Point} p - */ - extend: function(p) { - - if(p.x !== 0 || p.y !== 0) { - // this is over cross for the case that a and b have same coordinates. - //((this.a.x > this.b.x) ? this.a : this.b).x += p.x; - //((this.b.y > this.a.y) ? this.b : this.a).y += p.y; - this.b.x += p.x; - this.b.y += p.y; - - this._changed(true); - } - }, - - /** - * Widens the scope of the bounds by x. - * @param {Number} x - */ - widen: function(x) { - if (x !== 0) { - this.suspendChange = true; - this.moveBy({x: -x, y: -x}); - this.extend({x: 2*x, y: 2*x}); - this.suspendChange = false; - if(this.changedWhileSuspend) { - this._changed(true); - } - } - }, - - /** - * Returns the upper left corner's point regardless of the - * bound delimiter points. - */ - upperLeft: function() { - var result = {}; - result.x = this.a.x; - result.y = this.a.y; - return result; - }, - - /** - * Returns the lower Right left corner's point regardless of the - * bound delimiter points. - */ - lowerRight: function() { - var result = {}; - result.x = this.b.x; - result.y = this.b.y; - return result; - }, - - /** - * @return {Number} Width of bounds. - */ - width: function() { - return this.b.x - this.a.x; - }, - - /** - * @return {Number} Height of bounds. - */ - height: function() { - return this.b.y - this.a.y; - }, - - /** - * @return {Point} The center point of this bounds. - */ - center: function() { - var center = {}; - center.x =(this.a.x + this.b.x)/2.0; - center.y =(this.a.y + this.b.y)/2.0; - return center; - }, + _characterSets: [ + "%W", + "@", + "m", + "wDGMOQ?????#+=<>~^", + "ABCHKNRSUVXZ??????????&", + "bdghnopqux???????????ETY1234567890?????_????${}*????`???????????", + "aeksvyz?????FLP????????????????", + "c-", + "rtJ\"/()[]:;!|\\", + "fjI., ", + "'", + "il" + ], + _characterSetValues: [15, 14, 13, 11, 10, 9, 8, 7, 6, 5, 4, 3], - - /** - * @return {Point} The center point of this bounds relative to upperLeft. - */ - midPoint: function() { - - var midpoint = {}; - midpoint.x = (this.b.x - this.a.x)/2.0; - midpoint.y = (this.b.y - this.a.y)/2.0; - return midpoint; - }, - - /** - * Moves the center point of this bounds to the new position. - * @param p {Point} - * or - * @param x {Number} - * @param y {Number} - */ - centerMoveTo: function() { - var currentPosition = this.center(); - - switch (arguments.length) { - - case 1: - this.moveBy(arguments[0].x - currentPosition.x, - arguments[0].y - currentPosition.y); - break; - - case 2: - this.moveBy(arguments[0] - currentPosition.x, - arguments[1] - currentPosition.y); - break; - } - }, - - isIncluded: function(point, offset) { - - var pointX, pointY, offset; - - // Get the the two Points - switch(arguments.length) { - case 1: - pointX = arguments[0].x; - pointY = arguments[0].y; - offset = 0; - - break; - case 2: - if(arguments[0].x && arguments[0].y) { - pointX = arguments[0].x; - pointY = arguments[0].y; - offset = Math.abs(arguments[1]); - } else { - pointX = arguments[0]; - pointY = arguments[1]; - offset = 0; - } - break; - case 3: - pointX = arguments[0]; - pointY = arguments[1]; - offset = Math.abs(arguments[2]); - break; - default: - throw "isIncluded needs one, two or three arguments"; - } - - var ul = this.upperLeft(); - var lr = this.lowerRight(); - - if(pointX >= ul.x - offset - && pointX <= lr.x + offset && pointY >= ul.y - offset - && pointY <= lr.y + offset) - return true; - else - return false; - }, - - /** - * @return {Bounds} A copy of this bounds. - */ - clone: function() { - - //Returns a new bounds object without the callback - // references of the original bounds - return new ORYX.Core.Bounds(this); - }, - - toString: function() { - - return "( "+this.a.x+" | "+this.a.y+" )/( "+this.b.x+" | "+this.b.y+" )"; - }, - - serializeForERDF: function() { + /** + * Constructor + * @param options {Object} : + * textElement + * + */ + construct: function (options) { + arguments.callee.$.construct.apply(this, arguments); - return this.a.x+","+this.a.y+","+this.b.x+","+this.b.y; - } - }; - -ORYX.Core.Bounds = Clazz.extend(ORYX.Core.Bounds);/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + if (!options.textElement) { + throw "Label: No parameter textElement." + } else if (!ORYX.Editor.checkClassType(options.textElement, SVGTextElement)) { + throw "Label: Parameter textElement is not an SVGTextElement." + } -/** - * Init namespaces - */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} + this.invisibleRenderPoint = -5000; + this.node = options.textElement; -/** - * @classDescription Abstract base class for all objects that have a graphical representation - * within the editor. - * @extends Clazz - */ -ORYX.Core.UIObject = { - /** - * Constructor of the UIObject class. - */ - construct: function(options) { - - this.isChanged = true; //Flag, if UIObject has been changed since last update. - this.isResized = true; - this.isVisible = true; //Flag, if UIObject's display attribute is set to 'inherit' or 'none' - this.isSelectable = false; //Flag, if UIObject is selectable. - this.isResizable = false; //Flag, if UIObject is resizable. - this.isMovable = false; //Flag, if UIObject is movable. - - this.id = ORYX.Editor.provideId(); //get unique id - this.parent = undefined; //parent is defined, if this object is added to another uiObject. - this.node = undefined; //this is a reference to the SVG representation, either locally or in DOM. - this.children = []; //array for all add uiObjects - - this.bounds = new ORYX.Core.Bounds(); //bounds with undefined values - - this._changedCallback = this._changed.bind(this); //callback reference for calling _changed - this.bounds.registerCallback(this._changedCallback); //set callback in bounds - - if(options && options.eventHandlerCallback) { - this.eventHandlerCallback = options.eventHandlerCallback; - } - }, - - /** - * Sets isChanged flag to true. Callback for the bounds object. - */ - _changed: function(bounds, isResized) { - this.isChanged = true; - if(this.bounds == bounds) - this.isResized = isResized || this.isResized; - }, - - /** - * If something changed, this method calls the refresh method that must be implemented by subclasses. - */ - update: function() { - if(this.isChanged) { - this.refresh(); - this.isChanged = false; - - //call update of all children - this.children.each(function(value) { - value.update(); - }); - } - }, - - /** - * Is called in update method, if isChanged is set to true. Sub classes should call the super class method. - */ - refresh: function() { - - }, - - /** - * @return {Array} Array of all child UIObjects. - */ - getChildren: function() { - return this.children.clone(); - }, - - /** - * @return {Array} Array of all parent UIObjects. - */ - getParents: function(){ - var parents = []; - var parent = this.parent; - while(parent){ - parents.push(parent); - parent = parent.parent; - } - return parents; - }, - - /** - * Returns TRUE if the given parent is one of the UIObjects parents or the UIObject themselves, otherwise FALSE. - * @param {UIObject} parent - * @return {Boolean} - */ - isParent: function(parent){ - var cparent = this; - while(cparent){ - if (cparent === parent){ - return true; - } - cparent = cparent.parent; - } - return false; - }, - - /** - * @return {String} Id of this UIObject - */ - getId: function() { - return this.id; - }, - - /** - * Method for accessing child uiObjects by id. - * @param {String} id - * @param {Boolean} deep - * - * @return {UIObject} If found, it returns the UIObject with id. - */ - getChildById: function(id, deep) { - return this.children.find(function(uiObj) { - if(uiObj.getId() === id) { - return uiObj; - } else { - if(deep) { - var obj = uiObj.getChildById(id, deep); - if(obj) { - return obj; - } - } - } - }); - }, - - /** - * Adds an UIObject to this UIObject and sets the parent of the - * added UIObject. It is also added to the SVG representation of this - * UIObject. - * @param {UIObject} uiObject - */ - add: function(uiObject) { - //add uiObject, if it is not already a child of this object - if (!(this.children.member(uiObject))) { - //if uiObject is child of another parent, remove it from that parent. - if(uiObject.parent) { - uiObject.remove(uiObject); - } - - //add uiObject to children - this.children.push(uiObject); - - //set parent reference - uiObject.parent = this; - - //add uiObject.node to this.node - uiObject.node = this.node.appendChild(uiObject.node); - - //register callback to get informed, if child is changed - uiObject.bounds.registerCallback(this._changedCallback); - - //uiObject.update(); - } else { - ORYX.Log.info("add: ORYX.Core.UIObject is already a child of this object."); - } - }, - - /** - * Removes UIObject from this UIObject. The SVG representation will also - * be removed from this UIObject's SVG representation. - * @param {UIObject} uiObject - */ - remove: function(uiObject) { - //if uiObject is a child of this object, remove it. - if (this.children.member(uiObject)) { - //remove uiObject from children - this.children = this._uiObjects.without(uiObject); - - //delete parent reference of uiObject - uiObject.parent = undefined; - - //delete uiObject.node from this.node - uiObject.node = this.node.removeChild(uiObject.node); - - //unregister callback to get informed, if child is changed - uiObject.bounds.unregisterCallback(this._changedCallback); - } else { - ORYX.Log.info("remove: ORYX.Core.UIObject is not a child of this object."); - } - - }, - - /** - * Calculates absolute bounds of this UIObject. - */ - absoluteBounds: function() { - if(this.parent) { - var absUL = this.absoluteXY(); - return new ORYX.Core.Bounds(absUL.x, absUL.y, - absUL.x + this.bounds.width(), - absUL.y + this.bounds.height()); - } else { - return this.bounds.clone(); - } - }, - /** - * @return {Point} The absolute position of this UIObject. - */ - absoluteXY: function() { - if(this.parent) { - var pXY = this.parent.absoluteXY(); - var result = {}; - result.x = pXY.x + this.bounds.upperLeft().x; - result.y = pXY.y + this.bounds.upperLeft().y; - return result; - } else { - var result = {}; - result.x = this.bounds.upperLeft().x; - result.y = this.bounds.upperLeft().y; - return result; - } - }, + this.node.setAttributeNS(null, 'stroke-width', '0pt'); + this.node.setAttributeNS(null, 'letter-spacing', '-0.01px'); - /** - * @return {Point} The absolute position from the Center of this UIObject. - */ - absoluteCenterXY: function() { - if(this.parent) { - var pXY = this.parent.absoluteXY(); - var result = {}; - result.x = pXY.x + this.bounds.center().x; - result.y = pXY.y + this.bounds.center().y; - return result; - - } else { - var result = {}; - result.x = this.bounds.center().x; - result.y = this.bounds.center().y; - return result; - } - }, - - /** - * Hides this UIObject and all its children. - */ - hide: function() { - this.node.setAttributeNS(null, 'display', 'none'); - this.isVisible = false; - this.children.each(function(uiObj) { - uiObj.hide(); - }); - }, - - /** - * Enables visibility of this UIObject and all its children. - */ - show: function() { - this.node.setAttributeNS(null, 'display', 'inherit'); - this.isVisible = true; - this.children.each(function(uiObj) { - uiObj.show(); - }); - }, - - addEventHandlers: function(node) { - - node.addEventListener(ORYX.CONFIG.EVENT_MOUSEDOWN, this._delegateEvent.bind(this), false); - node.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this._delegateEvent.bind(this), false); - node.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this._delegateEvent.bind(this), false); - node.addEventListener(ORYX.CONFIG.EVENT_MOUSEOVER, this._delegateEvent.bind(this), false); - node.addEventListener(ORYX.CONFIG.EVENT_MOUSEOUT, this._delegateEvent.bind(this), false); - node.addEventListener('click', this._delegateEvent.bind(this), false); - node.addEventListener(ORYX.CONFIG.EVENT_DBLCLICK, this._delegateEvent.bind(this), false); - - }, - - _delegateEvent: function(event) { - if(this.eventHandlerCallback) { - this.eventHandlerCallback(event, this); - } - }, - - toString: function() { return "UIObject " + this.id } - }; - ORYX.Core.UIObject = Clazz.extend(ORYX.Core.UIObject);/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + this.shapeId = options.shapeId; -/** - * Init namespaces - */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} + this.id; -/** - * Top Level uiobject. - * @class ORYX.Core.AbstractShape - * @extends ORYX.Core.UIObject - */ -ORYX.Core.AbstractShape = ORYX.Core.UIObject.extend( -/** @lends ORYX.Core.AbstractShape.prototype */ -{ + this.fitToElemId; - /** - * Constructor - */ - construct: function(options, stencil, facade) { - - arguments.callee.$.construct.apply(this, arguments); - - this.resourceId = ORYX.Editor.provideId(); //Id of resource in DOM - - // stencil reference - this._stencil = stencil; - // if the stencil defines a super stencil that should be used for its instances, set it. - if (this._stencil._jsonStencil.superId){ - stencilId = this._stencil.id() - superStencilId = stencilId.substring(0, stencilId.indexOf("#") + 1) + stencil._jsonStencil.superId; - stencilSet = this._stencil.stencilSet(); - this._stencil = stencilSet.stencil(superStencilId); - } - - //Hash map for all properties. Only stores the values of the properties. - this.properties = new Hash(); - this.propertiesChanged = new Hash(); - - // List of properties which are not included in the stencilset, - // but which gets (de)serialized - this.hiddenProperties = new Hash(); - - - //Initialization of property map and initial value. - this._stencil.properties().each((function(property) { - var key = property.prefix() + "-" + property.id(); - this.properties[key] = property.value(); - this.propertiesChanged[key] = true; - }).bind(this)); - - // if super stencil was defined, also regard stencil's properties: - if (stencil._jsonStencil.superId) { - stencil.properties().each((function(property) { - var key = property.prefix() + "-" + property.id(); - var value = property.value(); - var oldValue = this.properties[key]; - this.properties[key] = value; - this.propertiesChanged[key] = true; - - // Raise an event, to show that the property has changed - // required for plugins like processLink.js - //window.setTimeout( function(){ - - this._delegateEvent({ - type : ORYX.CONFIG.EVENT_PROPERTY_CHANGED, - name : key, - value : value, - oldValue: oldValue - }); - - //}.bind(this), 10) - - }).bind(this)); - } + this.edgePosition; - }, + this.x; + this.y; + this.oldX; + this.oldY; - layout: function() { + this.isVisible = true; - }, - - /** - * Returns the stencil object specifiing the type of the shape. - */ - getStencil: function() { - return this._stencil; - }, - - /** - * - * @param {Object} resourceId - */ - getChildShapeByResourceId: function(resourceId) { + this._text; + this._verticalAlign; + this._horizontalAlign; + this._rotate; + this._rotationPoint; - resourceId = ERDF.__stripHashes(resourceId); - - return this.getChildShapes(true).find(function(shape) { - return shape.resourceId == resourceId - }); - }, - /** - * - * @param {Object} deep - * @param {Object} iterator - */ - getChildShapes: function(deep, iterator) { - var result = []; - - this.children.each(function(uiObject) { - if(uiObject instanceof ORYX.Core.Shape && uiObject.isVisible ) { - if(iterator) { - iterator(uiObject); - } - result.push(uiObject); - if(deep) { - result = result.concat(uiObject.getChildShapes(deep, iterator)); - } - } - }); + //this.anchors = []; + this.anchorLeft; + this.anchorRight; + this.anchorTop; + this.anchorBottom; - return result; - }, - - /** - * @param {Object} shape - * @return {boolean} true if any of shape's childs is given shape - */ - hasChildShape: function(shape){ - return this.getChildShapes().any(function(child){ - return (child === shape) || child.hasChildShape(shape); - }); - }, - - /** - * - * @param {Object} deep - * @param {Object} iterator - */ - getChildNodes: function(deep, iterator) { - var result = []; - - this.children.each(function(uiObject) { - if(uiObject instanceof ORYX.Core.Node && uiObject.isVisible) { - if(iterator) { - iterator(uiObject); - } - result.push(uiObject); - } - if(uiObject instanceof ORYX.Core.Shape) { - if(deep) { - result = result.concat(uiObject.getChildNodes(deep, iterator)); - } - } - }); + this._isChanged = true; - return result; - }, - - /** - * - * @param {Object} deep - * @param {Object} iterator - */ - getChildEdges: function(deep, iterator) { - var result = []; - - this.children.each(function(uiObject) { - if(uiObject instanceof ORYX.Core.Edge && uiObject.isVisible) { - if(iterator) { - iterator(uiObject); - } - result.push(uiObject); - } - if(uiObject instanceof ORYX.Core.Shape) { - if(deep) { - result = result.concat(uiObject.getChildEdges(deep, iterator)); - } - } - }); + //if the text element already has an id, don't change it. + var _id = this.node.getAttributeNS(null, 'id'); + if (_id) { + this.id = _id; + } - return result; - }, - - /** - * Returns a sorted array of ORYX.Core.Node objects. - * Ordered in z Order, the last object has the highest z Order. - */ - //TODO deep iterator - getAbstractShapesAtPosition: function() { - var x, y; - switch (arguments.length) { - case 1: - x = arguments[0].x; - y = arguments[0].y; - break; - case 2: //two or more arguments - x = arguments[0]; - y = arguments[1]; - break; - default: - throw "getAbstractShapesAtPosition needs 1 or 2 arguments!" - } + //initialization + + //set referenced element the text is fit to + this.fitToElemId = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'fittoelem'); + if (this.fitToElemId) + this.fitToElemId = this.shapeId + this.fitToElemId; + + //set alignment + var alignValues = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'align'); + if (alignValues) { + alignValues = alignValues.replace(/,/g, " "); + alignValues = alignValues.split(" "); + alignValues = alignValues.without(""); + + alignValues.each((function (alignValue) { + switch (alignValue) { + case 'top': + case 'middle': + case 'bottom': + if (!this._verticalAlign) { + this._originVerticalAlign = this._verticalAlign = alignValue; + } + break; + case 'left': + case 'center': + case 'right': + if (!this._horizontalAlign) { + this._originHorizontalAlign = this._horizontalAlign = alignValue; + } + break; + } + }).bind(this)); + } - if(this.isPointIncluded(x, y)) { - - var result = []; - result.push(this); - - //check, if one child is at that position - - - var childNodes = this.getChildNodes(); - var childEdges = this.getChildEdges(); - - [childNodes, childEdges].each(function(ne){ - var nodesAtPosition = new Hash(); - - ne.each(function(node) { - if(!node.isVisible){ return } - var candidates = node.getAbstractShapesAtPosition( x , y ); - if(candidates.length > 0) { - var nodesInZOrder = $A(node.node.parentNode.childNodes); - var zOrderIndex = nodesInZOrder.indexOf(node.node); - nodesAtPosition[zOrderIndex] = candidates; - } - }); - - nodesAtPosition.keys().sort().each(function(key) { - result = result.concat(nodesAtPosition[key]); - }); - }); - - return result; - - } else { - return []; - } - }, - - /** - * - * @param key {String} Must be 'prefix-id' of property - * @param value {Object} Can be of type String or Number according to property type. - */ - setProperty: function(key, value, force) { - var oldValue = this.properties[key]; - if(oldValue !== value || force === true) { - this.properties[key] = value; - this.propertiesChanged[key] = true; - this._changed(); - - // Raise an event, to show that the property has changed - //window.setTimeout( function(){ - - if (!this._isInSetProperty) { - this._isInSetProperty = true; - - this._delegateEvent({ - type : ORYX.CONFIG.EVENT_PROPERTY_CHANGED, - elements : [this], - name : key, - value : value, - oldValue: oldValue - }); - - delete this._isInSetProperty; - } - //}.bind(this), 10) - } - }, - - /** - * Returns TRUE if one of the properties is flagged as dirty - * @return {boolean} - */ - isPropertyChanged: function(){ - return this.propertiesChanged.any(function(property){ return property.value }); - }, + //set edge position (only in case the label belongs to an edge) + this.edgePosition = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'edgePosition'); + if (this.edgePosition) { + this.originEdgePosition = this.edgePosition = this.edgePosition.toLowerCase(); + } - /** - * - * @param {String} Must be 'prefix-id' of property - * @param {Object} Can be of type String or Number according to property type. - */ - setHiddenProperty: function(key, value) { - // IF undefined, Delete - if (value === undefined) { - delete this.hiddenProperties[key]; - return; - } - var oldValue = this.hiddenProperties[key]; - if (oldValue !== value) { - this.hiddenProperties[key] = value; - } - }, - /** - * Calculate if the point is inside the Shape - * @param {Point} - */ - isPointIncluded: function(pointX, pointY, absoluteBounds) { - var absBounds = absoluteBounds ? absoluteBounds : this.absoluteBounds(); - return absBounds.isIncluded(pointX, pointY); - - }, - - /** - * Get the serialized object - * return Array with hash-entrees (prefix, name, value) - * Following values will given: - * Type - * Properties - */ - serialize: function() { - var serializedObject = []; - - // Add the type - serializedObject.push({name: 'type', prefix:'oryx', value: this.getStencil().id(), type: 'literal'}); - - // Add hidden properties - this.hiddenProperties.each(function(prop){ - serializedObject.push({name: prop.key.replace("oryx-", ""), prefix: "oryx", value: prop.value, type: 'literal'}); - }.bind(this)); - - // Add all properties - this.getStencil().properties().each((function(property){ - - var prefix = property.prefix(); // Get prefix - var name = property.id(); // Get name - - //if(typeof this.properties[prefix+'-'+name] == 'boolean' || this.properties[prefix+'-'+name] != "") - serializedObject.push({name: name, prefix: prefix, value: this.properties[prefix+'-'+name], type: 'literal'}); - }).bind(this)); - - return serializedObject; - }, - - - deserialize: function(serialize){ - // Search in Serialize - var initializedDocker = 0; - - // Sort properties so that the hidden properties are first in the list - serialize = serialize.sort(function(a,b){ a = Number(this.properties.keys().member(a.prefix+"-"+a.name)); b = Number(this.properties.keys().member(b.prefix+"-"+b.name)); return a > b ? 1 : (a < b ? -1 : 0) }.bind(this)); - - serialize.each((function(obj){ - - var name = obj.name; - var prefix = obj.prefix; - var value = obj.value; - - // Complex properties can be real json objects, encode them to a string - if (Object.prototype.toString.call(value) === "Object") value = JSON.stringify(value); - - switch(prefix + "-" + name){ - case 'raziel-parent': - // Set parent - if(!this.parent) {break}; - - // Set outgoing Shape - var parent = this.getCanvas().getChildShapeByResourceId(value); - if(parent) { - parent.add(this); - } - - break; - default: - // If list, eval as an array - var prop = this.getStencil().property(prefix+"-"+name); - if (prop && prop.isList() && typeof value === "string"){ - if ((value||"").strip()&&!value.startsWith("[")&&!value.startsWith("]")) - value = "[\""+value.strip()+"\"]"; - value = ((value||"").strip()||"[]").evalJSON(); - } - - // Set property - if(this.properties.keys().member(prefix+"-"+name)) { - this.setProperty(prefix+"-"+name, value); - } else if(!(name === "bounds"||name === "parent"||name === "target"||name === "dockers"||name === "docker"||name === "outgoing"||name === "incoming")) { - this.setHiddenProperty(prefix+"-"+name, value); - } - - } - }).bind(this)); - }, - - toString: function() { return "ORYX.Core.AbstractShape " + this.id }, - - /** - * Converts the shape to a JSON representation. - * @return {Object} A JSON object with included ORYX.Core.AbstractShape.JSONHelper and getShape() method. - */ - toJSON: function(){ - var json = { - resourceId: this.resourceId, - properties: jQuery.extend({}, this.properties, this.hiddenProperties).inject({}, function(props, prop){ - var key = prop[0]; - var value = prop[1]; - - //If complex property, value should be a json object - if ( this.getStencil().property(key) - && this.getStencil().property(key).type() === ORYX.CONFIG.TYPE_COMPLEX - && Object.prototype.toString.call(value) === "String"){ - - try {value = JSON.parse(value);} catch(error){} - //try {value = JSON.parse(value);} catch(error){} - - // Parse date - } else if (value instanceof Date&&this.getStencil().property(key)){ - try { - value = value.format(this.getStencil().property(key).dateFormat()); - } catch(e){} - } - - //Takes "my_property" instead of "oryx-my_property" as key - key = key.replace(/^[\w_]+-/, ""); - props[key] = value; - - return props; - }.bind(this)), - stencil: { - id: this.getStencil().idWithoutNs() - }, - childShapes: this.getChildShapes().map(function(shape){ - return shape.toJSON(); - }) - }; - - if(this.getOutgoingShapes){ - json.outgoing = this.getOutgoingShapes().map(function(shape){ - return { - resourceId: shape.resourceId - }; - }); - } - - if(this.bounds){ - json.bounds = { - lowerRight: this.bounds.lowerRight(), - upperLeft: this.bounds.upperLeft() - }; + //get offset top + this.offsetTop = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'offsetTop') || ORYX.CONFIG.OFFSET_EDGE_LABEL_TOP; + if (this.offsetTop) { + this.offsetTop = parseInt(this.offsetTop); } - - if(this.dockers){ - json.dockers = this.dockers.map(function(docker){ - var d = docker.getDockedShape() && docker.referencePoint ? docker.referencePoint : docker.bounds.center(); - d.getDocker = function(){return docker;}; - return d; - }); + + //get offset top + this.offsetBottom = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'offsetBottom') || ORYX.CONFIG.OFFSET_EDGE_LABEL_BOTTOM; + if (this.offsetBottom) { + this.offsetBottom = parseInt(this.offsetBottom); } - - jQuery.extend(json, ORYX.Core.AbstractShape.JSONHelper); - - // do not pollute the json attributes (for serialization), so put the corresponding - // shape is encapsulated in a method - json.getShape = function(){ - return this; - }.bind(this); - - return json; - } - }); - -/** - * @namespace Collection of methods which can be used on a shape json object (ORYX.Core.AbstractShape#toJSON()). - * @example - * jQuery.extend(shapeAsJson, ORYX.Core.AbstractShape.JSONHelper); - */ -ORYX.Core.AbstractShape.JSONHelper = { - /** - * Iterates over each child shape. - * @param {Object} iterator Iterator function getting a child shape and his parent as arguments. - * @param {boolean} [deep=false] Iterate recursively (childShapes of childShapes) - * @param {boolean} [modify=false] If true, the result of the iterator function is taken as new shape, return false to delete it. This enables modifying the object while iterating through the child shapes. - * @example - * // Increases the lowerRight x value of each direct child shape by one. - * myShapeAsJson.eachChild(function(shape, parentShape){ - * shape.bounds.lowerRight.x = shape.bounds.lowerRight.x + 1; - * return shape; - * }, false, true); - */ - eachChild: function(iterator, deep, modify){ - if(!this.childShapes) return; - - var newChildShapes = []; //needed if modify = true - - this.childShapes.each(function(shape){ - if (!(shape.eachChild instanceof Function)){ - jQuery.extend(shape, ORYX.Core.AbstractShape.JSONHelper); - } - var res = iterator(shape, this); - if(res) newChildShapes.push(res); //if false is returned, and modify = true, current shape is deleted. - - if(deep) shape.eachChild(iterator, deep, modify); - }.bind(this)); - - if(modify) this.childShapes = newChildShapes; - }, - - getShape: function(){ - return null; - }, - getChildShapes: function(deep){ - var allShapes = this.childShapes; - - if(deep){ - this.eachChild(function(shape){ - if (!(shape.getChildShapes instanceof Function)){ - jQuery.extend(shape, ORYX.Core.AbstractShape.JSONHelper); - } - allShapes = allShapes.concat(shape.getChildShapes(deep)); - }, true); - } - - return allShapes; - }, - - /** - * @return {String} Serialized JSON object - */ - serialize: function(){ - return JSON.stringify(this); - } - } -/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ -/** - * Init namespaces - */ -if(!ORYX) {var ORYX = {};} -/** - @namespace Namespace for the Oryx core elements. - @name ORYX.Core -*/ -if(!ORYX.Core) {ORYX.Core = {};} + //set rotation + var rotateValue = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'rotate'); + if (rotateValue) { + try { + this._rotate = parseFloat(rotateValue); + } catch (e) { + this._rotate = 0; + } + } else { + this._rotate = 0; + } -/** - * @class Oryx canvas. - * @extends ORYX.Core.AbstractShape - * - */ -ORYX.Core.Canvas = ORYX.Core.AbstractShape.extend({ - /** @lends ORYX.Core.Canvas.prototype */ + //anchors + var anchorAttr = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "anchors"); + if (anchorAttr) { + anchorAttr = anchorAttr.replace("/,/g", " "); + var anchors = anchorAttr.split(" ").without(""); - /** - * Defines the current zoom level - */ - zoomLevel:1, + for (var i = 0; i < anchors.length; i++) { + switch (anchors[i].toLowerCase()) { + case "left": + this.originAnchorLeft = this.anchorLeft = true; + break; + case "right": + this.originAnchorRight = this.anchorRight = true; + break; + case "top": + this.originAnchorTop = this.anchorTop = true; + break; + case "bottom": + this.originAnchorBottom = this.anchorBottom = true; + break; + } + } + } - /** - * Constructor - */ - construct: function(options, stencil, facade) { - arguments.callee.$.construct.apply(this, arguments); + //if no alignment defined, set default alignment + if (!this._verticalAlign) { + this._verticalAlign = 'bottom'; + } + if (!this._horizontalAlign) { + this._horizontalAlign = 'left'; + } - if(!(options && options.width && options.height)) { - - ORYX.Log.fatal("Canvas is missing mandatory parameters options.width and options.height."); - return; - } - this.facade = facade; - //TODO: set document resource id - this.resourceId = options.id; - - this.nodes = []; - - this.edges = []; - - // Row highlighting states - this.colHighlightState = 0; - - this.colHighlightEnabled = false; - - //init svg document - this.rootNode = ORYX.Editor.graft("http://www.w3.org/2000/svg", options.parentNode, - ['svg', {id: this.id, width: options.width, height: options.height}, - ['defs', {}] - ]); - - this.rootNode.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink"); - this.rootNode.setAttribute("xmlns:svg", "http://www.w3.org/2000/svg"); - - this._htmlContainer = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", options.parentNode, - ['div', {id: "oryx_canvas_htmlContainer", style:"position:absolute; top:5px"}]); - - // Additional SVG-node BELOW the stencils to allow underlays (if that is even a word) by plugins - this.underlayNode = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.rootNode, - ['svg', {id: "underlay-container"}]); - - // Create 2 svg-elements in the svg-container - this.columnHightlight1 = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.underlayNode, - ['rect', {x: 0, width: ORYX.CONFIG.FORM_ROW_WIDTH + 35, height: "100%", style: "fill: #fff6d5", visibility: "hidden"}]); - - this.columnHightlight2 = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.underlayNode, - ['rect', {x: ORYX.CONFIG.FORM_ROW_WIDTH + 35, width: ORYX.CONFIG.FORM_ROW_WIDTH + 25, height: "100%", style: "fill: #fff6d5", visibility: "hidden"}]); - - this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.rootNode, - ['g', {}, - ['g', {"class": "stencils"}, - ['g', {"class": "me"}], - ['g', {"class": "children"}], - ['g', {"class": "edge"}] - ], - ['g', {"class":"svgcontainer"}] - ]); - - /* - var off = 2 * ORYX.CONFIG.GRID_DISTANCE; - var size = 3; - var d = ""; - for(var i = 0; i <= options.width; i += off) - for(var j = 0; j <= options.height; j += off) - d = d + "M" + (i - size) + " " + j + " l" + (2*size) + " 0 m" + (-size) + " " + (-size) + " l0 " + (2*size) + " m0" + (-size) + " "; - - ORYX.Editor.graft("http://www.w3.org/2000/svg", this.node.firstChild.firstChild, - ['path', {d:d , stroke:'#000000', 'stroke-width':'0.15px'},]); - */ - - //Global definition of default font for shapes - //Definitions in the SVG definition of a stencil will overwrite these settings for - // that stencil. - /*if(navigator.platform.indexOf("Mac") > -1) { - this.node.setAttributeNS(null, 'stroke', 'black'); - this.node.setAttributeNS(null, 'stroke-width', '0.5px'); - this.node.setAttributeNS(null, 'font-family', 'Skia'); - //this.node.setAttributeNS(null, 'letter-spacing', '2px'); - this.node.setAttributeNS(null, 'font-size', ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT); - } else { - this.node.setAttributeNS(null, 'stroke', 'none'); - this.node.setAttributeNS(null, 'font-family', 'Verdana'); - this.node.setAttributeNS(null, 'font-size', ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT); - }*/ - - this.node.setAttributeNS(null, 'stroke', 'none'); - this.node.setAttributeNS(null, 'font-family', 'Verdana, sans-serif'); - this.node.setAttributeNS(null, 'font-size-adjust', 'none'); - this.node.setAttributeNS(null, 'font-style', 'normal'); - this.node.setAttributeNS(null, 'font-variant', 'normal'); - this.node.setAttributeNS(null, 'font-weight', 'normal'); - this.node.setAttributeNS(null, 'line-heigth', 'normal'); - - this.node.setAttributeNS(null, 'font-size', ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT); - - this.bounds.set(0,0,options.width, options.height); - - this.addEventHandlers(this.rootNode.parentNode); - - //disable context menu - this.rootNode.oncontextmenu = function() {return false;}; - }, - - focus: function(){ - - try { - // Get a href - if (!this.focusEl) - { - this.focusEl = jQuery('body').append(jQuery('')); - this.focusEl.swallowEvent("click", true); - } - - // Focus it - this.focusEl.focus.defer(1, this.focusEl); - this.focusEl.blur.defer(3, this.focusEl); - - } catch(e){} - }, - - setHightlightState: function(state) { - if(this.colHighlightEnabled && this.colHighlightState != state) { - if(state == 0) { - this.columnHightlight1.setAttribute("visibility", "hidden"); - this.columnHightlight2.setAttribute("visibility", "hidden"); - } else if(state == 1) { - this.columnHightlight1.setAttribute("visibility", "visible"); - this.columnHightlight2.setAttribute("visibility", "hidden"); - } else if(state == 2) { - this.columnHightlight1.setAttribute("visibility", "hidden"); - this.columnHightlight2.setAttribute("visibility", "visible"); - } else if(state == 3) { - this.columnHightlight1.setAttribute("visibility", "visible"); - this.columnHightlight2.setAttribute("visibility", "visible"); - } - this.colHighlightState = state; - } - }, - - setHightlightStateBasedOnX : function(x) { - if(x > ORYX.CONFIG.FORM_ROW_WIDTH + 30) { - this.setHightlightState(2); - } else { - this.setHightlightState(1); - } - }, - - update: function() { - - this.nodes.each(function(node) { - this._traverseForUpdate(node); - }.bind(this)); - - // call stencil's layout callback - // (needed for row layouting of xforms) - //this.getStencil().layout(this); - - var layoutEvents = this.getStencil().layout(); - - if(layoutEvents) { - layoutEvents.each(function(event) { - - // setup additional attributes - event.shape = this; - event.forceExecution = true; - event.target = this.rootNode; - - // do layouting - - this._delegateEvent(event); - }.bind(this)) - } - - this.nodes.invoke("_update"); - - this.edges.invoke("_update", true); - - /*this.children.each(function(child) { - child._update(); - });*/ - }, - - _traverseForUpdate: function(shape) { - var childRet = shape.isChanged; - shape.getChildNodes(false, function(child) { - if(this._traverseForUpdate(child)) { - childRet = true; - } - }.bind(this)); - - if(childRet) { - shape.layout(); - return true; - } else { - return false; - } - }, - - layout: function() { - - - - }, - - /** - * - * @param {Object} deep - * @param {Object} iterator - */ - getChildNodes: function(deep, iterator) { - if(!deep && !iterator) { - return this.nodes.clone(); - } else { - var result = []; - this.nodes.each(function(uiObject) { - if(iterator) { - iterator(uiObject); - } - result.push(uiObject); - - if(deep && uiObject instanceof ORYX.Core.Shape) { - result = result.concat(uiObject.getChildNodes(deep, iterator)); - } - }); - - return result; - } - }, - - /** - * buggy crap! use base class impl instead! - * @param {Object} iterator - */ -/* getChildEdges: function(iterator) { - if(iterator) { - this.edges.each(function(edge) { - iterator(edge); - }); - } - - return this.edges.clone(); - }, -*/ - /** - * Overrides the UIObject.add method. Adds uiObject to the correct sub node. - * @param {UIObject} uiObject - */ - add: function(uiObject, index, silent) { - //if uiObject is child of another UIObject, remove it. - if(uiObject instanceof ORYX.Core.UIObject) { - if (!(this.children.member(uiObject))) { - //if uiObject is child of another parent, remove it from that parent. - if(uiObject.parent) { - uiObject.parent.remove(uiObject, true); - } - - //add uiObject to the Canvas - //add uiObject to this Shape - if(index != undefined) - this.children.splice(index, 0, uiObject); - else - this.children.push(uiObject); - - //set parent reference - uiObject.parent = this; - - //add uiObject.node to this.node depending on the type of uiObject - if(uiObject instanceof ORYX.Core.Shape) { - if(uiObject instanceof ORYX.Core.Edge) { - uiObject.addMarkers(this.rootNode.getElementsByTagNameNS(NAMESPACE_SVG, "defs")[0]); - uiObject.node = this.node.childNodes[0].childNodes[2].appendChild(uiObject.node); - this.edges.push(uiObject); - } else { - uiObject.node = this.node.childNodes[0].childNodes[1].appendChild(uiObject.node); - this.nodes.push(uiObject); - } - } else { //UIObject - uiObject.node = this.node.appendChild(uiObject.node); - } - - uiObject.bounds.registerCallback(this._changedCallback); - - if(this.eventHandlerCallback && silent !== true) - this.eventHandlerCallback({type:ORYX.CONFIG.EVENT_SHAPEADDED,shape:uiObject}) - } else { - - ORYX.Log.warn("add: ORYX.Core.UIObject is already a child of this object."); - } - } else { - - ORYX.Log.fatal("add: Parameter is not of type ORYX.Core.UIObject."); - } - }, + var xValue = this.node.getAttributeNS(null, 'x'); + if (xValue) { + this.oldX = this.x = parseFloat(xValue); + } else { + //TODO error + } - /** - * Overrides the UIObject.remove method. Removes uiObject. - * @param {UIObject} uiObject - */ - remove: function(uiObject, silent) { - //if uiObject is a child of this object, remove it. - if (this.children.member(uiObject)) { - //remove uiObject from children - var parent = uiObject.parent; - - this.children = this.children.without(uiObject); - - //delete parent reference of uiObject - uiObject.parent = undefined; - - //delete uiObject.node from this.node - if(uiObject instanceof ORYX.Core.Shape) { - if(uiObject instanceof ORYX.Core.Edge) { - uiObject.removeMarkers(); - uiObject.node = this.node.childNodes[0].childNodes[2].removeChild(uiObject.node); - this.edges = this.edges.without(uiObject); - } else { - uiObject.node = this.node.childNodes[0].childNodes[1].removeChild(uiObject.node); - this.nodes = this.nodes.without(uiObject); - } - } else { //UIObject - uiObject.node = this.node.removeChild(uiObject.node); - } + var yValue = this.node.getAttributeNS(null, 'y'); + if (yValue) { + this.oldY = this.y = parseFloat(yValue); + } else { + //TODO error + } - if(this.eventHandlerCallback && silent !== true) - this.eventHandlerCallback({type:ORYX.CONFIG.EVENT_SHAPEREMOVED,shape:uiObject, parent:parent}); - - uiObject.bounds.unregisterCallback(this._changedCallback); - } else { + //set initial text + this.text(this.node.textContent); + }, - ORYX.Log.warn("remove: ORYX.Core.UIObject is not a child of this object."); - } - }, - /** - * Creates shapes out of the given collection of shape objects and adds them to the canvas. - * @example - * canvas.addShapeObjects({ - bounds:{ lowerRight:{ y:510, x:633 }, upperLeft:{ y:146, x:210 } }, - resourceId:"oryx_F0715955-50F2-403D-9851-C08CFE70F8BD", - childShapes:[], - properties:{}, - stencil:{ - id:"Subprocess" - }, - outgoing:[{resourceId: 'aShape'}], - target: {resourceId: 'aShape'} - }); - * @param {Object} shapeObjects - * @param {Function} [eventHandler] An event handler passed to each newly created shape (as eventHandlerCallback) - * @return {Array} A collection of ORYX.Core.Shape - * @methodOf ORYX.Core.Canvas.prototype + * Reset the anchor position to the original value + * which was specified in the stencil set + * */ - addShapeObjects: function(shapeObjects, eventHandler){ - if(!shapeObjects) return; - - this.initializingShapes = true; - - /*FIXME This implementation is very evil! At first, all shapes are created on - canvas. In a second step, the attributes are applied. There must be a distinction - between the configuration phase (where the outgoings, for example, are just named), - and the creation phase (where the outgoings are evaluated). This must be reflected - in code to provide a nicer API/ implementation!!! */ - - var addShape = function(shape, parent){ - // Create a new Stencil - var stencil = ORYX.Core.StencilSet.stencil(this.getStencil().namespace() + shape.stencil.id ); - - // Create a new Shape - var ShapeClass = (stencil.type() == "node") ? ORYX.Core.Node : ORYX.Core.Edge; - var newShape = new ShapeClass( - {'eventHandlerCallback': eventHandler}, - stencil, this.facade); - - // Set the resource id - newShape.resourceId = shape.resourceId; - newShape.node.id = "svg-" + shape.resourceId; - - // Set parent to json object to be used later - // Due to the nested json structure, normally shape.parent is not set/ must not be set. - // In special cases, it can be easier to set this directly instead of a nested structure. - shape.parent = "#" + ((shape.parent && shape.parent.resourceId) || parent.resourceId); - - // Add the shape to the canvas - this.add( newShape ); + resetAnchorPosition: function () { + this.anchorLeft = this.originAnchorLeft || false; + this.anchorRight = this.originAnchorRight || false; + this.anchorTop = this.originAnchorTop || false; + this.anchorBottom = this.originAnchorBottom || false; + }, - return { - json: shape, - object: newShape - }; - }.bind(this); - - /** Builds up recursively a flatted array of shapes, including a javascript object and json representation - * @param {Object} shape Any object that has Object#childShapes - */ - var addChildShapesRecursively = function(shape){ - var addedShapes = []; - - if (shape.childShapes && shape.childShapes.constructor == String) - { - shape.childShapes = JSON.parse(shape.childShapes); - } - - shape.childShapes.each(function(childShape){ - addedShapes.push(addShape(childShape, shape)); - addedShapes = addedShapes.concat(addChildShapesRecursively(childShape)); - }); - - return addedShapes; - }.bind(this); + isOriginAnchorLeft: function () { + return this.originAnchorLeft || false; + }, + isOriginAnchorRight: function () { + return this.originAnchorRight || false; + }, + isOriginAnchorTop: function () { + return this.originAnchorTop || false; + }, + isOriginAnchorBottom: function () { + return this.originAnchorBottom || false; + }, - var shapes = addChildShapesRecursively({ - childShapes: shapeObjects, - resourceId: this.resourceId - }); - - // prepare deserialisation parameter - shapes.each( - function(shape){ - var properties = []; - for(field in shape.json.properties){ - properties.push({ - prefix: 'oryx', - name: field, - value: shape.json.properties[field] - }); - } - - // Outgoings - shape.json.outgoing.each(function(out){ - properties.push({ - prefix: 'raziel', - name: 'outgoing', - value: "#"+out.resourceId - }); - }); - - // Target - // (because of a bug, the first outgoing is taken when there is no target, - // can be removed after some time) - if(shape.object instanceof ORYX.Core.Edge) { - var target = shape.json.target || shape.json.outgoing[0]; - if(target){ - properties.push({ - prefix: 'raziel', - name: 'target', - value: "#"+target.resourceId - }); - } - } - - // Bounds - if (shape.json.bounds) { - properties.push({ - prefix: 'oryx', - name: 'bounds', - value: shape.json.bounds.upperLeft.x + "," + shape.json.bounds.upperLeft.y + "," + shape.json.bounds.lowerRight.x + "," + shape.json.bounds.lowerRight.y - }); - } - - //Dockers [{x:40, y:50}, {x:30, y:60}] => "40 50 30 60 #" - if(shape.json.dockers){ - properties.push({ - prefix: 'oryx', - name: 'dockers', - value: shape.json.dockers.inject("", function(dockersStr, docker){ - return dockersStr + docker.x + " " + docker.y + " "; - }) + " #" - }); - } - - //Parent - properties.push({ - prefix: 'raziel', - name: 'parent', - value: shape.json.parent - }); - - shape.__properties = properties; - }.bind(this) - ); - - // Deserialize the properties from the shapes - // This can't be done earlier because Shape#deserialize expects that all referenced nodes are already there - - // first, deserialize all nodes - shapes.each(function(shape) { - if(shape.object instanceof ORYX.Core.Node) { - shape.object.deserialize(shape.__properties, shape.json); - } - }); - - // second, deserialize all edges - shapes.each(function(shape) { - if(shape.object instanceof ORYX.Core.Edge) { - shape.object.deserialize(shape.__properties, shape.json); - shape.object._oldBounds = shape.object.bounds.clone(); - shape.object._update(); - } - }); - - delete this.initializingShapes; - return shapes.pluck("object"); + isAnchorLeft: function () { + return this.anchorLeft || false; + }, + isAnchorRight: function () { + return this.anchorRight || false; + }, + isAnchorTop: function () { + return this.anchorTop || false; }, - + isAnchorBottom: function () { + return this.anchorBottom || false; + }, + /** - * Updates the size of the canvas, regarding to the containg shapes. + * Returns the x coordinate + * @return {number} */ - updateSize: function(){ - // Check the size for the canvas - var maxWidth = 0; - var maxHeight = 0; - var offset = 100; - this.getChildShapes(true, function(shape){ - var b = shape.bounds; - maxWidth = Math.max( maxWidth, b.lowerRight().x + offset) - maxHeight = Math.max( maxHeight, b.lowerRight().y + offset) - }); - - if( this.bounds.width() < maxWidth || this.bounds.height() < maxHeight ){ - this.setSize({width: Math.max(this.bounds.width(), maxWidth), height: Math.max(this.bounds.height(), maxHeight)}) + getX: function () { + try { + var x = this.node.x.baseVal.getItem(0).value; + switch (this.horizontalAlign()) { + case "left": + return x; + case "center": + return x - (this.getWidth() / 2); + case "right": + return x - this.getWidth(); + } + return this.node.getBBox().x; + } catch (e) { + return this.x; } }, - getRootNode: function() { - return this.rootNode; - }, - - getUnderlayNode: function() { - return this.underlayNode; - }, - - getSvgContainer: function() { - return this.node.childNodes[1]; - }, - - getHTMLContainer: function() { - return this._htmlContainer; - }, - - /** - * Return all elements of the same highest level - * @param {Object} elements - */ - getShapesWithSharedParent: function(elements) { - - // If there is no elements, return [] - if(!elements || elements.length < 1) { return []; } - // If there is one element, return this element - if(elements.length == 1) { return elements;} - - return elements.findAll(function(value){ - var parentShape = value.parent; - while(parentShape){ - if(elements.member(parentShape)) return false; - parentShape = parentShape.parent; - } - return true; - }); - - }, - - setSize: function(size, dontSetBounds) { - if(!size || !size.width || !size.height){return;}; - - if(this.rootNode.parentNode){ - this.rootNode.parentNode.style.width = size.width + 'px'; - this.rootNode.parentNode.style.height = size.height + 'px'; - } - - this.rootNode.setAttributeNS(null, 'width', size.width); - this.rootNode.setAttributeNS(null, 'height', size.height); + setX: function (x) { + if (this.position) + this.position.x = x; + else + this.setOriginX(x); + }, - //this._htmlContainer.style.top = "-" + (size.height + 4) + 'px'; - if( !dontSetBounds ){ - this.bounds.set({a:{x:0,y:0},b:{x:size.width/this.zoomLevel,y:size.height/this.zoomLevel}}); - } - }, - - /** - * Returns an SVG document of the current process. - * @param {Boolean} escapeText Use true, if you want to parse it with an XmlParser, - * false, if you want to use the SVG document in browser on client side. - */ - getSVGRepresentation: function(escapeText) { - // Get the serialized svg image source - var svgClone = this.getRootNode().cloneNode(true); - - this._removeInvisibleElements(svgClone); - - var x1, y1, x2, y2; - this.getChildShapes(true).each(function(shape) { - var absBounds = shape.absoluteBounds(); - var ul = absBounds.upperLeft(); - var lr = absBounds.lowerRight(); - if(x1 == undefined) { - x1 = ul.x; - y1 = ul.y; - x2 = lr.x; - y2 = lr.y; - } else { - x1 = Math.min(x1, ul.x); - y1 = Math.min(y1, ul.y); - x2 = Math.max(x2, lr.x); - y2 = Math.max(y2, lr.y); - } - }); - - var margin = 50; - var width, height, tx, ty; - if(x1 == undefined) { - width = 0; - height = 0; - tx = 0; - ty = 0; - } else { - width = x2; - height = y2; - tx = -x1+margin/2; - ty = -y1+margin/2; - } - - // Set the width and height - svgClone.setAttributeNS(null, 'width', width + margin); - svgClone.setAttributeNS(null, 'height', height + margin); - - //remove scale factor - svgClone.childNodes[1].removeAttributeNS(null, 'transform'); - - try{ - var svgCont = svgClone.childNodes[1].childNodes[1]; - svgCont.parentNode.removeChild(svgCont); - } catch(e) {} - - if(escapeText) { - $A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'tspan')).each(function(elem) { - elem.textContent = elem.textContent.escapeHTML(); - }); - - $A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'text')).each(function(elem) { - if(elem.childNodes.length == 0) - elem.textContent = elem.textContent.escapeHTML(); - }); - } - - // generating absolute urls for the pdf-exporter - $A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'image')).each(function(elem) { - var href = elem.getAttributeNS("http://www.w3.org/1999/xlink","href"); - - if(!href.match("^(http|https)://")) { - href = window.location.protocol + "//" + window.location.host + href; - elem.setAttributeNS("http://www.w3.org/1999/xlink", "href", href); - } - }); - - - // escape all links - $A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'a')).each(function(elem) { - elem.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", (elem.getAttributeNS("http://www.w3.org/1999/xlink","href")||"").escapeHTML()); - }); - - return svgClone; - }, - - /** - * Removes all nodes (and its children) that has the - * attribute visibility set to "hidden" - */ - _removeInvisibleElements: function(element) { - var index = 0; - while(index < element.childNodes.length) { - var child = element.childNodes[index]; - if(child.getAttributeNS && - child.getAttributeNS(null, "visibility") === "hidden") { - element.removeChild(child); - } else { - this._removeInvisibleElements(child); - index++; - } - } - - }, - - /** - * This method checks all shapes on the canvas and removes all shapes that - * contain invalid bounds values or dockers values(NaN) - */ - /*cleanUp: function(parent) { - if (!parent) { - parent = this; - } - parent.getChildShapes().each(function(shape){ - var a = shape.bounds.a; - var b = shape.bounds.b; - if (isNaN(a.x) || isNaN(a.y) || isNaN(b.x) || isNaN(b.y)) { - parent.remove(shape); - } - else { - shape.getDockers().any(function(docker) { - a = docker.bounds.a; - b = docker.bounds.b; - if (isNaN(a.x) || isNaN(a.y) || isNaN(b.x) || isNaN(b.y)) { - parent.remove(shape); - return true; - } - return false; - }); - shape.getMagnets().any(function(magnet) { - a = magnet.bounds.a; - b = magnet.bounds.b; - if (isNaN(a.x) || isNaN(a.y) || isNaN(b.x) || isNaN(b.y)) { - parent.remove(shape); - return true; - } - return false; - }); - this.cleanUp(shape); - } - }.bind(this)); - },*/ - _delegateEvent: function(event) { - if(this.eventHandlerCallback && ( event.target == this.rootNode || event.target == this.rootNode.parentNode )) { - this.eventHandlerCallback(event, this); - } - }, - - toString: function() { return "Canvas " + this.id }, - /** - * Calls {@link ORYX.Core.AbstractShape#toJSON} and adds some stencil set information. + * Returns the y coordinate + * @return {number} */ - toJSON: function() { - var json = arguments.callee.$.toJSON.apply(this, arguments); - -// if(ORYX.CONFIG.STENCILSET_HANDLER.length > 0) { -// json.stencilset = { -// url: this.getStencil().stencilSet().namespace() -// }; -// } else { - json.stencilset = { - url: this.getStencil().stencilSet().source(), - namespace: this.getStencil().stencilSet().namespace() - }; -// } - - - return json; - } - });/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -var idCounter = 0; -var ID_PREFIX = "resource"; + getY: function () { + try { + return this.node.getBBox().y; + } catch (e) { + return this.y; + } + }, -/** - * Main initialization method. To be called when loading - * of the document, including all scripts, is completed. - */ -function init() { + setY: function (y) { + if (this.position) + this.position.y = y; + else + this.setOriginY(y); + }, - ORYX.Log.debug("Querying editor instances"); + setOriginX: function (x) { + this.x = x; + }, - // Hack for WebKit to set the SVGElement-Classes - ORYX.Editor.setMissingClasses(); - - // If someone wants to create the editor instance himself - if (window.onOryxResourcesLoaded) { - window.onOryxResourcesLoaded(); - } - // Else fetch the model from server and display editor - else { - var modelId = window.location.search.substring(4); - var modelUrl = "./service/model/" + modelId + "/json"; + setOriginY: function (y) { + this.y = y; + }, - ORYX.Editor.createByUrl(modelUrl); - } -} - -/** - @namespace Global Oryx name space - @name ORYX -*/ -if(!ORYX) {var ORYX = {};} -/** - * The Editor class. - * @class ORYX.Editor - * @extends Clazz - * @param {Object} config An editor object, passed to {@link ORYX.Editor#loadSerialized} - * @param {String} config.id Any ID that can be used inside the editor. If fullscreen=false, any HTML node with this id must be present to render the editor to this node. - * @param {boolean} [config.fullscreen=true] Render editor in fullscreen mode or not. - * @param {String} config.stencilset.url Stencil set URL. - * @param {String} [config.stencil.id] Stencil type used for creating the canvas. - * @param {Object} config.properties Any properties applied to the canvas. -*/ -ORYX.Editor = { - /** @lends ORYX.Editor.prototype */ - // Defines the global dom event listener - DOMEventListeners: new Hash(), - - // Defines the selection - selection: [], - - // Defines the current zoom level - zoomLevel:1.0, - - construct: function(config) { - - // initialization. - this._eventsQueue = []; - this.loadedPlugins = []; - this.pluginsData = []; - - - //meta data about the model for the signavio warehouse - //directory, new, name, description, revision, model (the model data) - - this.modelMetaData = config; - - var model = config; - - this.id = model.modelId; - - if(config.model) { - model = config.model; - } - - if(!this.id) { - this.id = model.id; - if(!this.id) { - this.id = ORYX.Editor.provideId(); - } - } - - // Defines if the editor should be fullscreen or not - this.fullscreen = config.fullscreen !== false; - - // Initialize the eventlistener - this._initEventListener(); - - // Load particular stencilset - if(ORYX.CONFIG.BACKEND_SWITCH) { - var ssUrl = (model.stencilset.namespace||model.stencilset.url).replace("#", "%23"); - ORYX.Core.StencilSet.loadStencilSet(ssUrl, this.modelMetaData, this.id); - } else { - var ssUrl = model.stencilset.url; - ORYX.Core.StencilSet.loadStencilSet(ssUrl, this.modelMetaData, this.id); - } + /** + * Returns the width of the label + * @return {number} + */ + getWidth: function () { + try { + try { + var width, cn = this.node.childNodes; + if (cn.length == 0) { + width = this.node.getBBox().width; + } else { + for (var i = 0, size = cn.length; i < size; ++i) { + var w = cn[i].getComputedTextLength(); + if ("undefined" == typeof width || width < w) { + width = w; + } + } + } + return width + (width % 2 == 0 ? 0 : 1); + } catch (ee) { + return this.node.getBBox().width; + } + } catch (e) { + return 0; + } + }, - // CREATES the canvas - this._createCanvas(model.stencil ? model.stencil.id : null, model.properties); - - // GENERATES the whole EXT.VIEWPORT - this._generateGUI(); - - // Initializing of a callback to check loading ends - var loadPluginFinished = false; - var loadContentFinished = false; - var initFinished = function(){ - if( !loadPluginFinished || !loadContentFinished ){ return } - this._finishedLoading(); - }.bind(this) - - // LOAD the plugins - window.setTimeout(function(){ - this.loadPlugins(); - loadPluginFinished = true; - initFinished(); - }.bind(this), 100); - - // LOAD the content of the current editor instance - window.setTimeout(function(){ - this.loadSerialized(model, true); // Request the meta data as well - this.getCanvas().update(); - loadContentFinished = true; - initFinished(); - }.bind(this), 200); - }, - - _finishedLoading: function() { - // Raise Loaded Event - this.handleEvents( {type:ORYX.CONFIG.EVENT_LOADED} ) - }, - - _initEventListener: function(){ - - // Register on Events - - document.documentElement.addEventListener(ORYX.CONFIG.EVENT_KEYDOWN, this.catchKeyDownEvents.bind(this), false); - document.documentElement.addEventListener(ORYX.CONFIG.EVENT_KEYUP, this.catchKeyUpEvents.bind(this), false); - - // Enable Key up and down Event - this._keydownEnabled = true; - this._keyupEnabled = true; - - this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEDOWN] = []; - this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEUP] = []; - this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEOVER] = []; - this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEOUT] = []; - this.DOMEventListeners[ORYX.CONFIG.EVENT_SELECTION_CHANGED] = []; - this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEMOVE] = []; - - }, - - /** - * Generate the whole viewport of the - * Editor and initialized the Ext-Framework - * - */ - _generateGUI: function() { - - // Defines the layout height if it's NOT fullscreen - var layoutHeight = ORYX.CONFIG.WINDOW_HEIGHT; - var canvasParent = this.getCanvas().rootNode.parentNode; - - jQuery("#canvasSection").append(canvasParent); - - // Set the editor to the center, and refresh the size - canvasParent.parentNode.setAttributeNS(null, 'align', 'center'); - canvasParent.setAttributeNS(null, 'align', 'left'); - this.getCanvas().setSize({ - width : ORYX.CONFIG.CANVAS_WIDTH, - height : ORYX.CONFIG.CANVAS_HEIGHT - }); - - }, - - getAvailablePlugins: function(){ - var curAvailablePlugins=ORYX.availablePlugins.clone(); - curAvailablePlugins.each(function(plugin){ - if(this.loadedPlugins.find(function(loadedPlugin){ - return loadedPlugin.type==this.name; - }.bind(plugin))){ - plugin.engaged=true; - } else { - plugin.engaged=false; - } - }.bind(this)); - return curAvailablePlugins; - }, + getOriginUpperLeft: function () { + var x = this.x, y = this.y; + switch (this._horizontalAlign) { + case 'center' : + x -= this.getWidth() / 2; + break; + case 'right' : + x -= this.getWidth(); + break; + } + switch (this._verticalAlign) { + case 'middle' : + y -= this.getHeight() / 2; + break; + case 'bottom' : + y -= this.getHeight(); + break; + } + return {x: x, y: y}; + }, - loadScript: function (url, callback){ - var script = document.createElement("script") - script.type = "text/javascript"; - if (script.readyState){ //IE - script.onreadystatechange = function(){ - if (script.readyState == "loaded" || script.readyState == "complete"){ - script.onreadystatechange = null; - callback(); - } - }; - } else { //Others - script.onload = function(){ - callback(); - }; - } - script.src = url; - document.getElementsByTagName("head")[0].appendChild(script); - }, - /** - * activate Plugin - * - * @param {String} name - * @param {Function} callback - * callback(sucess, [errorCode]) - * errorCodes: NOTUSEINSTENCILSET, REQUIRESTENCILSET, NOTFOUND, YETACTIVATED - */ - activatePluginByName: function(name, callback, loadTry){ - - var match=this.getAvailablePlugins().find(function(value){return value.name==name}); - if(match && (!match.engaged || (match.engaged==='false'))){ - var loadedStencilSetsNamespaces = this.getStencilSets().keys(); - var facade = this._getPluginFacade(); - var newPlugin; - var me=this; - ORYX.Log.debug("Initializing plugin '%0'", match.name); - - if (!match.requires || !match.requires.namespaces || match.requires.namespaces.any(function(req){ return loadedStencilSetsNamespaces.indexOf(req) >= 0 }) ){ - if(!match.notUsesIn || !match.notUsesIn.namespaces || !match.notUsesIn.namespaces.any(function(req){ return loadedStencilSetsNamespaces.indexOf(req) >= 0 })){ - - try { - - var className = eval(match.name); - var newPlugin = new className(facade, match); - newPlugin.type = match.name; - - // If there is an GUI-Plugin, they get all Plugins-Offer-Meta-Data - if (newPlugin.registryChanged) - newPlugin.registryChanged(me.pluginsData); - - // If there have an onSelection-Method it will pushed to the Editor Event-Handler - if (newPlugin.onSelectionChanged) - me.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, newPlugin.onSelectionChanged.bind(newPlugin)); - this.loadedPlugins.push(newPlugin); - this.loadedPlugins.each(function(loaded){ - if(loaded.registryChanged) - loaded.registryChanged(this.pluginsData); - }.bind(me)); - callback(true); - - } catch(e) { - ORYX.Log.warn("Plugin %0 is not available", match.name); - if(!!loadTry){ - callback(false,"INITFAILED"); - return; - } - this.loadScript("plugins/scripts/"+match.source, this.activatePluginByName.bind(this,match.name,callback,true)); - } - } else { - callback(false,"NOTUSEINSTENCILSET"); - ORYX.Log.info("Plugin need a stencilset which is not loaded'", match.name); - } - - } else { - callback(false,"REQUIRESTENCILSET"); - ORYX.Log.info("Plugin need a stencilset which is not loaded'", match.name); - } + /** + * Returns the height of the label + * @return {number} + */ + getHeight: function () { + try { + return this.node.getBBox().height; + } catch (e) { + return 0; + } + }, - - } else { - callback(false, match?"NOTFOUND":"YETACTIVATED"); - //TODO error handling - } - }, + /** + * Returns the relative center position of the label + * to its parent shape. + * @return {Object} + */ + getCenter: function () { + var up = {x: this.getX(), y: this.getY()}; + up.x += this.getWidth() / 2; + up.y += this.getHeight() / 2; + return up; + }, - /** - * Laden der Plugins - */ - loadPlugins: function() { - - // if there should be plugins but still are none, try again. - // TODO this should wait for every plugin respectively. - /*if (!ORYX.Plugins && ORYX.availablePlugins.length > 0) { - window.setTimeout(this.loadPlugins.bind(this), 100); - return; - }*/ - - var me = this; - var newPlugins = []; - - - var loadedStencilSetsNamespaces = this.getStencilSets().keys(); - - // Available Plugins will be initalize - var facade = this._getPluginFacade(); - - // If there is an Array where all plugins are described, than only take those - // (that comes from the usage of oryx with a mashup api) - if( ORYX.MashupAPI && ORYX.MashupAPI.loadablePlugins && ORYX.MashupAPI.loadablePlugins instanceof Array ){ - - // Get the plugins from the available plugins (those who are in the plugins.xml) - ORYX.availablePlugins = $A(ORYX.availablePlugins).findAll(function(value){ - return ORYX.MashupAPI.loadablePlugins.include( value.name ) - }) - - // Add those plugins to the list, which are only in the loadablePlugins list - ORYX.MashupAPI.loadablePlugins.each(function( className ){ - if( !(ORYX.availablePlugins.find(function(val){ return val.name == className }))){ - ORYX.availablePlugins.push( {name: className } ); - } - }) - } - - - ORYX.availablePlugins.each(function(value) { - ORYX.Log.debug("Initializing plugin '%0'", value.name); - if( (!value.requires || !value.requires.namespaces || value.requires.namespaces.any(function(req){ return loadedStencilSetsNamespaces.indexOf(req) >= 0 }) ) && - (!value.notUsesIn || !value.notUsesIn.namespaces || !value.notUsesIn.namespaces.any(function(req){ return loadedStencilSetsNamespaces.indexOf(req) >= 0 }) )&& - /*only load activated plugins or undefined */ - (value.engaged || (value.engaged===undefined)) ){ - - try { - var className = eval(value.name); - if( className ){ - var plugin = new className(facade, value); - plugin.type = value.name; - newPlugins.push( plugin ); - plugin.engaged=true; - } - } catch(e) { - ORYX.Log.warn("Plugin %0 is not available %1", value.name, e); - } - - } else { - ORYX.Log.info("Plugin need a stencilset which is not loaded'", value.name); - } - - }); + /** + * Sets the position of a label relative to the parent. + * @param {Object} position + */ + setPosition: function (position) { + if (!position || position.x === undefined || position.y === undefined) { + delete this.position; + } else { + this.position = position; + } - newPlugins.each(function(value) { - // If there is an GUI-Plugin, they get all Plugins-Offer-Meta-Data - if(value.registryChanged) - value.registryChanged(me.pluginsData); + if (this.position) { + delete this._referencePoint; + delete this.edgePosition; + } - // If there have an onSelection-Method it will pushed to the Editor Event-Handler - if(value.onSelectionChanged) - me.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, value.onSelectionChanged.bind(value)); - }); + this._isChanged = true; + this.update(); + }, - this.loadedPlugins = newPlugins; - - this.registerPluginsOnKeyEvents(); - - this.setSelection(); - - }, + /** + * Return the position + */ + getPosition: function () { + return this.position; + }, - /** - * Creates the Canvas - * @param {String} [stencilType] The stencil type used for creating the canvas. If not given, a stencil with myBeRoot = true from current stencil set is taken. - * @param {Object} [canvasConfig] Any canvas properties (like language). - */ - _createCanvas: function(stencilType, canvasConfig) { - if (stencilType) { - // Add namespace to stencilType - if (stencilType.search(/^http/) === -1) { - stencilType = this.getStencilSets().values()[0].namespace() + stencilType; - } - } - else { - // Get any root stencil type - stencilType = this.getStencilSets().values()[0].findRootStencilName(); + setReferencePoint: function (ref) { + if (ref) { + this._referencePoint = ref; + } else { + delete this._referencePoint; } - - // get the stencil associated with the type - var canvasStencil = ORYX.Core.StencilSet.stencil(stencilType); - - if (!canvasStencil) - ORYX.Log.fatal("Initialisation failed, because the stencil with the type %0 is not part of one of the loaded stencil sets.", stencilType); - - // create all dom - // TODO fix border, so the visible canvas has a double border and some spacing to the scrollbars - var div = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", null, ['div']); - // set class for custom styling - div.addClassName("ORYX_Editor"); - - // create the canvas - this._canvas = new ORYX.Core.Canvas({ - width : ORYX.CONFIG.CANVAS_WIDTH, - height : ORYX.CONFIG.CANVAS_HEIGHT, - 'eventHandlerCallback' : this.handleEvents.bind(this), - id : this.id, - parentNode : div - }, canvasStencil, this._getPluginFacade()); - - if (canvasConfig) { - // Migrate canvasConfig to an RDF-like structure - //FIXME this isn't nice at all because we don't want rdf any longer - var properties = []; - for(field in canvasConfig){ - properties.push({ - prefix: 'oryx', - name: field, - value: canvasConfig[field] - }); - } - - this._canvas.deserialize(properties); + if (this._referencePoint) { + delete this.position; } - - }, - - /** - * Returns a per-editor singleton plugin facade. - * To be used in plugin initialization. - */ - _getPluginFacade: function() { - - // if there is no pluginfacade already created: - if(!(this._pluginFacade)) - - // create it. - this._pluginFacade = { - - activatePluginByName: this.activatePluginByName.bind(this), - //deactivatePluginByName: this.deactivatePluginByName.bind(this), - getAvailablePlugins: this.getAvailablePlugins.bind(this), - offer: this.offer.bind(this), - getStencilSets: this.getStencilSets.bind(this), - getStencilSetExtensionDefinition:function(){ return Object.clone(this.ss_extensions_def||{})}.bind(this), - getRules: this.getRules.bind(this), - loadStencilSet: this.loadStencilSet.bind(this), - createShape: this.createShape.bind(this), - deleteShape: this.deleteShape.bind(this), - getSelection: this.getSelection.bind(this), - setSelection: this.setSelection.bind(this), - updateSelection: this.updateSelection.bind(this), - getCanvas: this.getCanvas.bind(this), - - importJSON: this.importJSON.bind(this), - getJSON: this.getJSON.bind(this), - getSerializedJSON: this.getSerializedJSON.bind(this), - - executeCommands: this.executeCommands.bind(this), - isExecutingCommands: this.isExecutingCommands.bind(this), - - registerOnEvent: this.registerOnEvent.bind(this), - unregisterOnEvent: this.unregisterOnEvent.bind(this), - raiseEvent: this.handleEvents.bind(this), - enableEvent: this.enableEvent.bind(this), - disableEvent: this.disableEvent.bind(this), - - eventCoordinates: this.eventCoordinates.bind(this), - eventCoordinatesXY: this.eventCoordinatesXY.bind(this), - - getModelMetaData: this.getModelMetaData.bind(this) - }; - - // return it. - return this._pluginFacade; - }, + }, - isExecutingCommands: function(){ - return !!this.commandExecuting; - }, + getReferencePoint: function () { + return this._referencePoint || undefined; + }, - /** - * Implementes the command pattern - * (The real usage of the command pattern - * is implemented and shown in the Plugins/undo.js) - * - * @param [] Array of commands - */ - executeCommands: function(commands){ - - if (!this.commandStack){ - this.commandStack = []; - } - if (!this.commandStackExecuted){ - this.commandStackExecuted = []; - } - - - this.commandStack = [].concat(this.commandStack) - .concat(commands); - - // Check if already executes - if (this.commandExecuting){ return; } - - // Start execution - this.commandExecuting = true; - - // Iterate over all commands - while(this.commandStack.length > 0){ - var command = this.commandStack.shift(); - // and execute it - command.execute(); - this.commandStackExecuted.push(command); - } - - // Raise event for executing commands - this.handleEvents({ - type : ORYX.CONFIG.EVENT_EXECUTE_COMMANDS, - commands : this.commandStackExecuted - }); - - // Remove temporary vars - delete this.commandStack; - delete this.commandStackExecuted; - delete this.commandExecuting; - - - this.updateSelection(); + changed: function () { + this._isChanged = true; + }, - }, - /** - * Returns JSON of underlying canvas (calls ORYX.Canvas#toJSON()). - * @return {Object} Returns JSON representation as JSON object. + * Register a callback which will be called if the label + * was rendered. + * @param {Object} fn */ - getJSON: function(){ - delete Array.prototype.toJSON; - var canvasJSON = this.getCanvas().toJSON(); - canvasJSON.ssextensions = this.getStencilSets().values()[0].extensions().keys().findAll(function(sse){ return !sse.endsWith('/meta#') }); - return canvasJSON; + registerOnChange: function (fn) { + if (!this.changeCallbacks) { + this.changeCallbacks = []; + } + if (fn instanceof Function && !this.changeCallbacks.include(fn)) { + this.changeCallbacks.push(fn); + } }, - + /** - * Serializes a call to toJSON(). - * @return {String} Returns JSON representation as string. + * Unregister the callback for changes. + * @param {Object} fn */ - getSerializedJSON: function(){ - return JSON.stringify(this.getJSON()); + unregisterOnChange: function (fn) { + if (this.changeCallbacks && fn instanceof Function && this.changeCallbacks.include(fn)) { + this.changeCallbacks = this.changeCallbacks.without(fn); + } }, - - /** - * Imports shapes in JSON as expected by {@link ORYX.Editor#loadSerialized} - * @param {Object|String} jsonObject The (serialized) json object to be imported - * @param {boolean } [noSelectionAfterImport=false] Set to true if no shapes should be selected after import - * @throws {SyntaxError} If the serialized json object contains syntax errors - */ - importJSON: function(jsonObject, noSelectionAfterImport) { - - try { - jsonObject = this.renewResourceIds(jsonObject); - } catch(error){ - throw error; - } - //check, if the imported json model can be loaded in this editor - // (stencil set has to fit) - if(jsonObject.stencilset.namespace && jsonObject.stencilset.namespace !== this.getCanvas().getStencil().stencilSet().namespace()) { - alert(String.format(ORYX.I18N.JSONImport.wrongSS, jsonObject.stencilset.namespace, this.getCanvas().getStencil().stencilSet().namespace())); - return null; - } else { - var commandClass = ORYX.Core.Command.extend({ - construct: function(jsonObject, loadSerializedCB, noSelectionAfterImport, facade){ - this.jsonObject = jsonObject; - this.noSelection = noSelectionAfterImport; - this.facade = facade; - this.shapes; - this.connections = []; - this.parents = new Hash(); - this.selection = this.facade.getSelection(); - this.loadSerialized = loadSerializedCB; - }, - execute: function(){ - - if (!this.shapes) { - // Import the shapes out of the serialization - this.shapes = this.loadSerialized( this.jsonObject ); - - //store all connections - this.shapes.each(function(shape) { - - if (shape.getDockers) { - var dockers = shape.getDockers(); - if (dockers) { - if (dockers.length > 0) { - this.connections.push([dockers.first(), dockers.first().getDockedShape(), dockers.first().referencePoint]); - } - if (dockers.length > 1) { - this.connections.push([dockers.last(), dockers.last().getDockedShape(), dockers.last().referencePoint]); - } - } - } - - //store parents - this.parents[shape.id] = shape.parent; - }.bind(this)); - } else { - this.shapes.each(function(shape) { - this.parents[shape.id].add(shape); - }.bind(this)); - - this.connections.each(function(con) { - con[0].setDockedShape(con[1]); - con[0].setReferencePoint(con[2]); - con[0].update(); - }); - } - - //this.parents.values().uniq().invoke("update"); - this.facade.getCanvas().update(); - - if(!this.noSelection) - this.facade.setSelection(this.shapes); - else - this.facade.updateSelection(); - - // call updateSize again, because during loadSerialized the edges' bounds - // are not yet initialized properly - this.facade.getCanvas().updateSize(); - - }, - rollback: function(){ - var selection = this.facade.getSelection(); - - this.shapes.each(function(shape) { - selection = selection.without(shape); - this.facade.deleteShape(shape); - }.bind(this)); - - /*this.parents.values().uniq().each(function(parent) { - if(!this.shapes.member(parent)) - parent.update(); - }.bind(this));*/ - - this.facade.getCanvas().update(); - - this.facade.setSelection(selection); - } - }) - - var command = new commandClass(jsonObject, - this.loadSerialized.bind(this), - noSelectionAfterImport, - this._getPluginFacade()); - - this.executeCommands([command]); - - return command.shapes.clone(); - } - }, - + /** - * This method renew all resource Ids and according references. - * Warning: The implementation performs a substitution on the serialized object for - * easier implementation. This results in a low performance which is acceptable if this - * is only used when importing models. - * @param {Object|String} jsonObject - * @throws {SyntaxError} If the serialized json object contains syntax errors. - * @return {Object} The jsonObject with renewed ids. - * @private + * Returns TRUE if the labe is currently in + * the update mechanism. + * @return {Boolean} */ - renewResourceIds: function(jsonObject){ - // For renewing resource ids, a serialized and object version is needed - if(Object.prototype.toString.call(jsonObject) === "String"){ - try { - var serJsonObject = jsonObject; - jsonObject = JSON.parse(jsonObject); - } catch(error){ - throw new SyntaxError(error.message); - } - } else { - var serJsonObject = JSON.stringify(jsonObject); - } - - // collect all resourceIds recursively - var collectResourceIds = function(shapes){ - if(!shapes) return []; - - return shapes.map(function(shape){ - return collectResourceIds(shape.childShapes).concat(shape.resourceId); - }).flatten(); - } - var resourceIds = collectResourceIds(jsonObject.childShapes); - - // Replace each resource id by a new one - resourceIds.each(function(oldResourceId){ - var newResourceId = ORYX.Editor.provideId(); - serJsonObject = serJsonObject.replace(new RegExp(oldResourceId, 'g'), newResourceId); - }); - - return JSON.parse(serJsonObject); + isUpdating: function () { + return !!this._isUpdating; + }, + + + getOriginEdgePosition: function () { + return this.originEdgePosition; }, /** - * Loads serialized model to the oryx. - * @example - * editor.loadSerialized({ - * resourceId: "mymodel1", - * childShapes: [ - * { - * stencil:{ id:"Subprocess" }, - * outgoing:[{resourceId: 'aShape'}], - * target: {resourceId: 'aShape'}, - * bounds:{ lowerRight:{ y:510, x:633 }, upperLeft:{ y:146, x:210 } }, - * resourceId: "myshape1", - * childShapes:[], - * properties:{}, - * } - * ], - * properties:{ - * language: "English" - * }, - * stencilset:{ - * url:"http://localhost:8080/oryx/stencilsets/bpmn1.1/bpmn1.1.json" - * }, - * stencil:{ - * id:"BPMNDiagram" - * } - * }); - * @param {Object} model Description of the model to load. - * @param {Array} [model.ssextensions] List of stenctil set extensions. - * @param {String} model.stencilset.url - * @param {String} model.stencil.id - * @param {Array} model.childShapes - * @param {Array} [model.properties] - * @param {String} model.resourceId - * @return {ORYX.Core.Shape[]} List of created shapes - * @methodOf ORYX.Editor.prototype + * Returns the edgeposition. + * + * @return {String} "starttop", "startmiddle", "startbottom", + * "midtop", "midbottom", "endtop", "endbottom" or null */ - loadSerialized: function(model, requestMeta){ - var canvas = this.getCanvas(); - - // Bugfix (cf. http://code.google.com/p/oryx-editor/issues/detail?id=240) - // Deserialize the canvas' stencil set extensions properties first! - this.loadSSExtensions(model.ssextensions); - - // Load Meta Data Extension if available - // #Signavio - if (requestMeta === true) { - var metaDataExtension = this.getExtensionForMetaData(); - if (metaDataExtension) { - this.loadSSExtension(metaDataExtension); - } - } - - var shapes = this.getCanvas().addShapeObjects(model.childShapes, this.handleEvents.bind(this)); - - if(model.properties) { - for(key in model.properties) { - var value = model.properties[key]; - var prop = this.getCanvas().getStencil().property("oryx-"+key); - if (!(typeof value === "string") && (!prop || !prop.isList())) { - value = JSON.stringify(value); - } - this.getCanvas().setProperty("oryx-" + key, value); - } - } - - - this.getCanvas().updateSize(); - - // Force to update the selection - this.selection = [null]; - this.setSelection([]); - - return shapes; + getEdgePosition: function () { + return this.edgePosition || null; }, - - /** - * Return the namespace of the extension which - * provided all the self defined meta data - * @return {String} Returns null if no extension is defined, otherwise the namespace - * - */ - getExtensionForMetaData: function(){ - if (!this.ss_extensions_def||!(this.ss_extensions_def.extensions instanceof Array)){ - return null; - } - - var stencilsets = this.getStencilSets(); - var extension = this.ss_extensions_def.extensions.find(function(ex){ - return !!stencilsets[ex["extends"]] && ex.namespace.endsWith("/meta#"); - }); - - return extension ? extension.namespace || null : null; - }, - + /** - * Calls ORYX.Editor.prototype.ss_extension_namespace for each element - * @param {Array} ss_extension_namespaces An array of stencil set extension namespaces. + * Set the edge position, must be one of the valid + * edge positions (see getEdgePosition). + * Removes the reference point and the absolute position as well. + * + * @param {Object} position */ - loadSSExtensions: function(ss_extension_namespaces){ - if(!ss_extension_namespaces) return; - - ss_extension_namespaces.each(function(ss_extension_namespace){ - this.loadSSExtension(ss_extension_namespace); - }.bind(this)); + setEdgePosition: function (position) { + if (["starttop", "startmiddle", "startbottom", + "midtop", "midbottom", "endtop", "endbottom"].include(position)) { + this.edgePosition = position; + delete this.position; + delete this._referencePoint; + } else { + delete this.edgePosition; + } }, - - /** - * Loads a stencil set extension. - * The stencil set extensions definiton file must already - * be loaded when the editor is initialized. - */ - loadSSExtension: function(ss_extension_namespace) { - - if (this.ss_extensions_def) { - var extension = this.ss_extensions_def.extensions.find(function(ex){ - return (ex.namespace == ss_extension_namespace); - }); - - if (!extension) { - return; - } - - var stencilset = this.getStencilSets()[extension["extends"]]; - - if (!stencilset) { - return; - } - - // Check if absolute or relative url - if ((extension["definition"]||"").startsWith("/")){ - stencilset.addExtension(extension["definition"]) - } else { - stencilset.addExtension(ORYX.CONFIG.SS_EXTENSIONS_FOLDER + extension["definition"]) - } - - //stencilset.addExtension("/oryx/build/stencilsets/extensions/" + extension["definition"]) - this.getRules().initializeRules(stencilset); - - this._getPluginFacade().raiseEvent({ - type: ORYX.CONFIG.EVENT_STENCIL_SET_LOADED - }); - } - - }, - disableEvent: function(eventType){ - if(eventType == ORYX.CONFIG.EVENT_KEYDOWN) { - this._keydownEnabled = false; - } - if(eventType == ORYX.CONFIG.EVENT_KEYUP) { - this._keyupEnabled = false; - } - if(this.DOMEventListeners.keys().member(eventType)) { - var value = this.DOMEventListeners.remove(eventType); - this.DOMEventListeners['disable_' + eventType] = value; - } - }, + /** + * Update the SVG text element. + */ + update: function (force) { - enableEvent: function(eventType){ - if(eventType == ORYX.CONFIG.EVENT_KEYDOWN) { - this._keydownEnabled = true; - } - - if(eventType == ORYX.CONFIG.EVENT_KEYUP) { - this._keyupEnabled = true; - } - - if(this.DOMEventListeners.keys().member("disable_" + eventType)) { - var value = this.DOMEventListeners.remove("disable_" + eventType); - this.DOMEventListeners[eventType] = value; - } - }, + var x = this.x, y = this.y; + if (this.position) { + x = this.position.x; + y = this.position.y; + } + x = Math.floor(x); + y = Math.floor(y); + + if (this._isChanged || x !== this.oldX || y !== this.oldY || force === true) { + if (this.isVisible) { + this._isChanged = false; + this._isUpdating = true; + + this.node.setAttributeNS(null, 'x', x); + this.node.setAttributeNS(null, 'y', y); + this.node.removeAttributeNS(null, "fill-opacity"); + + //this.node.setAttributeNS(null, 'font-size', this._fontSize); + //this.node.setAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'align', this._horizontalAlign + " " + this._verticalAlign); + + this.oldX = x; + this.oldY = y; + + //set rotation + if (!this.position && !this.getReferencePoint()) { + if (this._rotate !== undefined) { + if (this._rotationPoint) + this.node.setAttributeNS(null, 'transform', 'rotate(' + this._rotate + ' ' + Math.floor(this._rotationPoint.x) + ' ' + Math.floor(this._rotationPoint.y) + ')'); + else + this.node.setAttributeNS(null, 'transform', 'rotate(' + this._rotate + ' ' + Math.floor(x) + ' ' + Math.floor(y) + ')'); + } + } else { + this.node.removeAttributeNS(null, 'transform'); + } - /** - * Methods for the PluginFacade - */ - registerOnEvent: function(eventType, callback) { - if(!(this.DOMEventListeners.keys().member(eventType))) { - this.DOMEventListeners[eventType] = []; - } + var textLines = this._text.split("\n"); + while (textLines.last() == "") + textLines.pop(); + + + if (this.node.ownerDocument) { + // Only reset the tspans if the text + // has changed or has to be wrapped + if (this.fitToElemId || this._textHasChanged) { + this.node.textContent = ""; // Remove content + textLines.each((function (textLine, index) { + var tspan = this.node.ownerDocument.createElementNS(ORYX.CONFIG.NAMESPACE_SVG, 'tspan'); + tspan.textContent = textLine.trim(); + if (this.fitToElemId) { + tspan.setAttributeNS(null, 'x', this.invisibleRenderPoint); + tspan.setAttributeNS(null, 'y', this.invisibleRenderPoint); + } - this.DOMEventListeners[eventType].push(callback); - }, + /* + * Chrome's getBBox() method fails, if a text node contains an empty tspan element. + * So, we add a whitespace to such a tspan element. + */ + if (tspan.textContent === "") { + tspan.textContent = " "; + } - unregisterOnEvent: function(eventType, callback) { - if(this.DOMEventListeners.keys().member(eventType)) { - this.DOMEventListeners[eventType] = this.DOMEventListeners[eventType].without(callback); - } else { - // Event is not supported - // TODO: Error Handling - } - }, + //append tspan to text node + this.node.appendChild(tspan); + }).bind(this)); + delete this._textHasChanged; + delete this.indices; + } - getSelection: function() { - return this.selection || []; - }, + //Work around for Mozilla bug 293581 + if (this.isVisible && this.fitToElemId) { + this.node.setAttributeNS(null, 'visibility', 'hidden'); + } - getStencilSets: function() { - return ORYX.Core.StencilSet.stencilSets(this.id); - }, - - getRules: function() { - return ORYX.Core.StencilSet.rules(this.id); - }, - - loadStencilSet: function(source) { - try { - ORYX.Core.StencilSet.loadStencilSet(source, this.modelMetaData, this.id); - this.handleEvents({type:ORYX.CONFIG.EVENT_STENCIL_SET_LOADED}); - } catch (e) { - ORYX.Log.warn("Requesting stencil set file failed. (" + e + ")"); - } - }, - - offer: function(pluginData) { - if(!this.pluginsData.member(pluginData)){ - this.pluginsData.push(pluginData); - } - }, - - /** - * It creates an new event or adds the callback, if already existing, - * for the key combination that the plugin passes in keyCodes attribute - * of the offer method. - * - * The new key down event fits the schema: - * key.event[.metactrl][.alt][.shift].'thekeyCode' - */ - registerPluginsOnKeyEvents: function() { - this.pluginsData.each(function(pluginData) { - - if(pluginData.keyCodes) { - - pluginData.keyCodes.each(function(keyComb) { - var eventName = "key.event"; - - /* Include key action */ - eventName += '.' + keyComb.keyAction; - - if(keyComb.metaKeys) { - /* Register on ctrl or apple meta key as meta key */ - if(keyComb.metaKeys. - indexOf(ORYX.CONFIG.META_KEY_META_CTRL) > -1) { - eventName += "." + ORYX.CONFIG.META_KEY_META_CTRL; - } - - /* Register on alt key as meta key */ - if(keyComb.metaKeys. - indexOf(ORYX.CONFIG.META_KEY_ALT) > -1) { - eventName += '.' + ORYX.CONFIG.META_KEY_ALT; - } - - /* Register on shift key as meta key */ - if(keyComb.metaKeys. - indexOf(ORYX.CONFIG.META_KEY_SHIFT) > -1) { - eventName += '.' + ORYX.CONFIG.META_KEY_SHIFT; - } - } - - /* Register on the actual key */ - if(keyComb.keyCode) { - eventName += '.' + keyComb.keyCode; - } - - /* Register the event */ - ORYX.Log.debug("Register Plugin on Key Event: %0", eventName); - if (pluginData.toggle === true && pluginData.buttonInstance) { - this.registerOnEvent(eventName, function() { - pluginData.buttonInstance.toggle(!pluginData.buttonInstance.pressed); // Toggle - pluginData.functionality.call(pluginData, pluginData.buttonInstance, pluginData.buttonInstance.pressed); // Call function - }); - } else { - this.registerOnEvent(eventName, pluginData.functionality) - } - - }.bind(this)); - } - }.bind(this)); - }, - - isEqual: function(a,b){ - return a === b || (a.length === b.length && a.all(function(r){ return b.include(r) })) - }, - - isDirty: function(a){ - return a.any(function(shape){ return shape.isPropertyChanged() }) - }, + if (this.fitToElemId) { + window.setTimeout(this._checkFittingToReferencedElem.bind(this), 0); + //this._checkFittingToReferencedElem(); + } else { + window.setTimeout(this._positionText.bind(this), 0); + //this._positionText(); + } + } + } else { + this.node.textContent = ""; + //this.node.setAttributeNS(null, "fill-opacity", "0.2"); + } + } + }, - setSelection: function(elements, subSelectionElement, force) { - - if (!elements) { elements = []; } - if (!(elements instanceof Array)) { elements = [elements]; } - - elements = elements.findAll(function(n){ return n && n instanceof ORYX.Core.Shape }); - - if (elements[0] instanceof ORYX.Core.Canvas) { - elements = []; - } - - if (!force && this.isEqual(this.selection, elements) && !this.isDirty(elements)){ - return; - } - - this.selection = elements; - this._subSelection = subSelectionElement; - - this.handleEvents({type:ORYX.CONFIG.EVENT_SELECTION_CHANGED, elements:elements, subSelection: subSelectionElement, force: !!force}) - }, - - updateSelection: function() { - this.setSelection(this.selection, this._subSelection, true); - /*var s = this.selection; - this.setSelection(); - this.setSelection(s);*/ - }, + _checkFittingToReferencedElem: function () { + try { + var tspans = $A(this.node.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'tspan')); - getCanvas: function() { - return this._canvas; - }, - - - /** - * option = { - * type: string, - * position: {x:int, y:int}, - * connectingType: uiObj-Class - * connectedShape: uiObj - * draggin: bool - * namespace: url - * parent: ORYX.Core.AbstractShape - * template: a template shape that the newly created inherits properties from. - * } - */ - createShape: function(option) { - - if(option && option.serialize && option.serialize instanceof Array){ - - var type = option.serialize.find(function(obj){return (obj.prefix+"-"+obj.name) == "oryx-type"}); - var stencil = ORYX.Core.StencilSet.stencil(type.value); - - if(stencil.type() == 'node'){ - var newShapeObject = new ORYX.Core.Node({'eventHandlerCallback':this.handleEvents.bind(this)}, stencil, this._getPluginFacade()); - } else { - var newShapeObject = new ORYX.Core.Edge({'eventHandlerCallback':this.handleEvents.bind(this)}, stencil, this._getPluginFacade()); - } - - this.getCanvas().add(newShapeObject); - newShapeObject.deserialize(option.serialize); - - return newShapeObject; - } + //only do this in firefox 3. all other browsers do not support word wrapping!!!!! + //if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent) && new Number(RegExp.$1)>=3) { + var newtspans = []; - // If there is no argument, throw an exception - if(!option || !option.type || !option.namespace) { throw "To create a new shape you have to give an argument with type and namespace";} - - var canvas = this.getCanvas(); - var newShapeObject; + var refNode = this.node.ownerDocument.getElementById(this.fitToElemId); - // Get the shape type - var shapetype = option.type; + if (refNode) { + var refbb = refNode.getBBox(); - // Get the stencil set - var sset = ORYX.Core.StencilSet.stencilSet(option.namespace); - // Create an New Shape, dependents on an Edge or a Node - if(sset.stencil(shapetype).type() == "node") { - newShapeObject = new ORYX.Core.Node({'eventHandlerCallback':this.handleEvents.bind(this)}, sset.stencil(shapetype), this._getPluginFacade()) - } else { - newShapeObject = new ORYX.Core.Edge({'eventHandlerCallback':this.handleEvents.bind(this)}, sset.stencil(shapetype), this._getPluginFacade()) - } - - // when there is a template, inherit the properties. - if(option.template) { + var fontSize = this.getFontSize(); - newShapeObject._jsonStencil.properties = option.template._jsonStencil.properties; - newShapeObject.postProcessProperties(); - } + for (var j = 0; j < tspans.length; j++) { + var tspan = tspans[j]; - // Add to the canvas - if(option.parent && newShapeObject instanceof ORYX.Core.Node) { - option.parent.add(newShapeObject); - } else { - canvas.add(newShapeObject); - } - - - // Set the position - var point = option.position ? option.position : {x:100, y:200}; - - - var con; - // If there is create a shape and in the argument there is given an ConnectingType and is instance of an edge - if(option.connectingType && option.connectedShape && !(newShapeObject instanceof ORYX.Core.Edge)) { - - // there will be create a new Edge - con = new ORYX.Core.Edge({'eventHandlerCallback':this.handleEvents.bind(this)}, sset.stencil(option.connectingType)); - - // And both endings dockers will be referenced to the both shapes - con.dockers.first().setDockedShape(option.connectedShape); - - var magnet = option.connectedShape.getDefaultMagnet() - var cPoint = magnet ? magnet.bounds.center() : option.connectedShape.bounds.midPoint(); - con.dockers.first().setReferencePoint( cPoint ); - con.dockers.last().setDockedShape(newShapeObject); - con.dockers.last().setReferencePoint(newShapeObject.getDefaultMagnet().bounds.center()); - - // The Edge will be added to the canvas and be updated - canvas.add(con); - //con.update(); - - } - - // Move the new Shape to the position - if(newShapeObject instanceof ORYX.Core.Edge && option.connectedShape) { - - newShapeObject.dockers.first().setDockedShape(option.connectedShape); - - if( option.connectedShape instanceof ORYX.Core.Node ){ - newShapeObject.dockers.first().setReferencePoint(option.connectedShape.getDefaultMagnet().bounds.center()); - newShapeObject.dockers.last().bounds.centerMoveTo(point); - } else { - newShapeObject.dockers.first().setReferencePoint(option.connectedShape.bounds.midPoint()); - } - - var start = newShapeObject.dockers.first(); - var end = newShapeObject.dockers.last(); - - if(start.getDockedShape() && end.getDockedShape()) { - var startPoint = start.getAbsoluteReferencePoint(); - var endPoint = end.getAbsoluteReferencePoint(); - - var docker = newShapeObject.createDocker(); - docker.bounds.centerMoveTo({ - x: startPoint.x + (endPont.x - startPoint.x) / 2, - y: startPoint.y + (endPont.y - startPoint.y) / 2 - }); - } + var textLength = this._getRenderedTextLength(tspan, undefined, undefined, fontSize); - } else { - - var b = newShapeObject.bounds - if( newShapeObject instanceof ORYX.Core.Node && newShapeObject.dockers.length == 1){ - b = newShapeObject.dockers.first().bounds - } - - b.centerMoveTo(point); - - var upL = b.upperLeft(); - b.moveBy( -Math.min(upL.x, 0) , -Math.min(upL.y, 0) ) - - var lwR = b.lowerRight(); - b.moveBy( -Math.max(lwR.x-canvas.bounds.width(), 0) , -Math.max(lwR.y-canvas.bounds.height(), 0) ) - - } - - // Update the shape - if (newShapeObject instanceof ORYX.Core.Edge) { - newShapeObject._update(false); - } - - // And refresh the selection - if(!(newShapeObject instanceof ORYX.Core.Edge)&&!(option.dontUpdateSelection)) { - this.setSelection([newShapeObject]); - } - - if(con && con.alignDockers) { - //con.alignDockers(); - } - if(newShapeObject.alignDockers) { - newShapeObject.alignDockers(); - } + var refBoxLength = (this._rotate != 0 + && this._rotate % 180 != 0 + && this._rotate % 90 == 0 ? + refbb.height : refbb.width); - return newShapeObject; - }, - - deleteShape: function(shape) { - - if (!shape || !shape.parent){ return } - - //remove shape from parent - // this also removes it from DOM - shape.parent.remove(shape); - - //delete references to outgoing edges - shape.getOutgoingShapes().each(function(os) { - var docker = os.getDockers().first(); - if(docker && docker.getDockedShape() == shape) { - docker.setDockedShape(undefined); - } - }); - - //delete references to incoming edges - shape.getIncomingShapes().each(function(is) { - var docker = is.getDockers().last(); - if(docker && docker.getDockedShape() == shape) { - docker.setDockedShape(undefined); - } - }); - - //delete references of the shape's dockers - shape.getDockers().each(function(docker) { - docker.setDockedShape(undefined); - }); - }, - - /** - * Returns an object with meta data about the model. - * Like name, description, ... - * - * Empty object with the current backend. - * - * @return {Object} Meta data about the model - */ - getModelMetaData: function() { - return this.modelMetaData; - }, + if (textLength > refBoxLength) { - /* Event-Handler Methods */ - - /** - * Helper method to execute an event immediately. The event is not - * scheduled in the _eventsQueue. Needed to handle Layout-Callbacks. - */ - _executeEventImmediately: function(eventObj) { - if(this.DOMEventListeners.keys().member(eventObj.event.type)) { - this.DOMEventListeners[eventObj.event.type].each((function(value) { - value(eventObj.event, eventObj.arg); - }).bind(this)); - } - }, + var startIndex = 0; + var lastSeperatorIndex = 0; - _executeEvents: function() { - this._queueRunning = true; - while(this._eventsQueue.length > 0) { - var val = this._eventsQueue.shift(); - this._executeEventImmediately(val); - } - this._queueRunning = false; - }, - - /** - * Leitet die Events an die Editor-Spezifischen Event-Methoden weiter - * @param {Object} event Event , welches gefeuert wurde - * @param {Object} uiObj Target-UiObj - */ - handleEvents: function(event, uiObj) { - - ORYX.Log.trace("Dispatching event type %0 on %1", event.type, uiObj); - - switch(event.type) { - case ORYX.CONFIG.EVENT_MOUSEDOWN: - this._handleMouseDown(event, uiObj); - break; - case ORYX.CONFIG.EVENT_MOUSEMOVE: - this._handleMouseMove(event, uiObj); - break; - case ORYX.CONFIG.EVENT_MOUSEUP: - this._handleMouseUp(event, uiObj); - break; - case ORYX.CONFIG.EVENT_MOUSEOVER: - this._handleMouseHover(event, uiObj); - break; - case ORYX.CONFIG.EVENT_MOUSEOUT: - this._handleMouseOut(event, uiObj); - break; - } - /* Force execution if necessary. Used while handle Layout-Callbacks. */ - if(event.forceExecution) { - this._executeEventImmediately({event: event, arg: uiObj}); - } else { - this._eventsQueue.push({event: event, arg: uiObj}); - } - - if(!this._queueRunning) { - this._executeEvents(); - } - - // TODO: Make this return whether no listener returned false. - // So that, when one considers bubbling undesireable, it won't happen. - return false; - }, + var numOfChars = this.getTrimmedTextLength(tspan.textContent); + for (var i = 0; i < numOfChars; i++) { + var sslength = this._getRenderedTextLength(tspan, startIndex, i - startIndex, fontSize); - isValidEvent: function (e) { - try { - var isInput = ["INPUT", "TEXTAREA"].include(e.target.tagName.toUpperCase()); - var gridHasFocus = e.target.className.include("x-grid3-focus") && !e.target.className.include("x-grid3-focus-canvas"); - return !isInput && !gridHasFocus; - } catch(e){ - return false; - } - }, + if (sslength > refBoxLength - 2) { + var newtspan = this.node.ownerDocument.createElementNS(ORYX.CONFIG.NAMESPACE_SVG, 'tspan'); + if (lastSeperatorIndex <= startIndex) { + lastSeperatorIndex = (i == 0) ? i : i - 1; + newtspan.textContent = tspan.textContent.slice(startIndex, lastSeperatorIndex).trim(); + //lastSeperatorIndex = i; + } else { + newtspan.textContent = tspan.textContent.slice(startIndex, ++lastSeperatorIndex).trim(); + } - catchKeyUpEvents: function(event) { - if(!this._keyupEnabled) { - return; - } - /* assure we have the current event. */ - if (!event) - event = window.event; - - // Checks if the event comes from some input field - if (!this.isValidEvent(event)){ - return; - } - - /* Create key up event type */ - var keyUpEvent = this.createKeyCombEvent(event, ORYX.CONFIG.KEY_ACTION_UP); - - ORYX.Log.debug("Key Event to handle: %0", keyUpEvent); - - /* forward to dispatching. */ - this.handleEvents({type: keyUpEvent, event:event}); - }, - - /** - * Catches all key down events and forward the appropriated event to - * dispatching concerning to the pressed keys. - * - * @param {Event} - * The key down event to handle - */ - catchKeyDownEvents: function(event) { - if(!this._keydownEnabled) { - return; - } - /* Assure we have the current event. */ - if (!event) - event = window.event; - - /* Fixed in FF3 */ - // This is a mac-specific fix. The mozilla event object has no knowledge - // of meta key modifier on osx, however, it is needed for certain - // shortcuts. This fix adds the metaKey field to the event object, so - // that all listeners that registered per Oryx plugin facade profit from - // this. The original bug is filed in - // https://bugzilla.mozilla.org/show_bug.cgi?id=418334 - //if (this.__currentKey == ORYX.CONFIG.KEY_CODE_META) { - // event.appleMetaKey = true; - //} - //this.__currentKey = pressedKey; - - // Checks if the event comes from some input field - if (!this.isValidEvent(event)){ - return; - } - - /* Create key up event type */ - var keyDownEvent = this.createKeyCombEvent(event, ORYX.CONFIG.KEY_ACTION_DOWN); - - ORYX.Log.debug("Key Event to handle: %0", keyDownEvent); - - /* Forward to dispatching. */ - this.handleEvents({type: keyDownEvent,event: event}); - }, - - /** - * Creates the event type name concerning to the pressed keys. - * - * @param {Event} keyDownEvent - * The source keyDownEvent to build up the event name - */ - createKeyCombEvent: function(keyEvent, keyAction) { + newtspan.setAttributeNS(null, 'x', this.invisibleRenderPoint); + newtspan.setAttributeNS(null, 'y', this.invisibleRenderPoint); + + //insert tspan to text node + //this.node.insertBefore(newtspan, tspan); + newtspans.push(newtspan); + + startIndex = lastSeperatorIndex; + } else { + var curChar = tspan.textContent.charAt(i); + if (curChar == ' ' || + curChar == '-' || + curChar == "." || + curChar == "," || + curChar == ";" || + curChar == ":") { + lastSeperatorIndex = i; + } + } + } - /* Get the currently pressed key code. */ - var pressedKey = keyEvent.which || keyEvent.keyCode; - //this.__currentKey = pressedKey; - - /* Event name */ - var eventName = "key.event"; - - /* Key action */ - if(keyAction) { - eventName += "." + keyAction; - } - - /* Ctrl or apple meta key is pressed */ - if(keyEvent.ctrlKey || keyEvent.metaKey) { - eventName += "." + ORYX.CONFIG.META_KEY_META_CTRL; - } - - /* Alt key is pressed */ - if(keyEvent.altKey) { - eventName += "." + ORYX.CONFIG.META_KEY_ALT; - } - - /* Alt key is pressed */ - if(keyEvent.shiftKey) { - eventName += "." + ORYX.CONFIG.META_KEY_SHIFT; - } - - /* Return the composed event name */ - return eventName + "." + pressedKey; - }, + tspan.textContent = tspan.textContent.slice(startIndex).trim(); + } - _handleMouseDown: function(event, uiObj) { - - // get canvas. - var canvas = this.getCanvas(); - // Try to get the focus - canvas.focus() - - // find the shape that is responsible for this element's id. - var element = event.currentTarget; - var elementController = uiObj; + newtspans.push(tspan); + } - // gather information on selection. - var currentIsSelectable = (elementController !== null) && - (elementController !== undefined) && (elementController.isSelectable); - var currentIsMovable = (elementController !== null) && - (elementController !== undefined) && (elementController.isMovable); - var modifierKeyPressed = event.shiftKey || event.ctrlKey; - var noObjectsSelected = this.selection.length === 0; - var currentIsSelected = this.selection.member(elementController); + while (this.node.hasChildNodes()) + this.node.removeChild(this.node.childNodes[0]); + while (newtspans.length > 0) { + this.node.appendChild(newtspans.shift()); + } + } + //} + } catch (e) { + ORYX.Log.fatal("Error " + e); + } + window.setTimeout(this._positionText.bind(this), 0); + //this._positionText(); + }, - // Rule #1: When there is nothing selected, select the clicked object. - if(currentIsSelectable && noObjectsSelected) { + /** + * This is a work around method for Mozilla bug 293581. + * Before the method getComputedTextLength works, the text has to be rendered. + */ + _positionText: function () { + try { - this.setSelection([elementController]); + var tspans = this.node.childNodes; - ORYX.Log.trace("Rule #1 applied for mouse down on %0", element.id); + var fontSize = this.getFontSize(this.node); - // Rule #3: When at least one element is selected, and there is no - // control key pressed, and the clicked object is not selected, select - // the clicked object. - } else if(currentIsSelectable && !noObjectsSelected && - !modifierKeyPressed && !currentIsSelected) { + var invalidTSpans = []; - this.setSelection([elementController]); + var x = this.x, y = this.y; + if (this.position) { + x = this.position.x; + y = this.position.y; + } + x = Math.floor(x); + y = Math.floor(y); + + var i = 0, indic = []; // Cache indices if the _positionText is called again, before update is called + var is = (this.indices || $R(0, tspans.length - 1).toArray()); + var length = is.length; + is.each((function (index) { + if ("undefined" == typeof index) { + return; + } - //var objectType = elementController.readAttributes(); - //alert(objectType[0] + ": " + objectType[1]); + var tspan = tspans[i++]; - ORYX.Log.trace("Rule #3 applied for mouse down on %0", element.id); + if (tspan.textContent.trim() === "") { + invalidTSpans.push(tspan); + } else { + //set vertical position + var dy = 0; + switch (this._verticalAlign) { + case 'bottom': + dy = -(length - index - 1) * (fontSize); + break; + case 'middle': + dy = -(length / 2.0 - index - 1) * (fontSize); + dy -= ORYX.CONFIG.LABEL_LINE_DISTANCE / 2; + break; + case 'top': + dy = index * (fontSize); + dy += fontSize; + break; + } + tspan.setAttributeNS(null, 'dy', Math.floor(dy)); - // Rule #4: When the control key is pressed, and the current object is - // not selected, add it to the selection. - } else if(currentIsSelectable && modifierKeyPressed - && !currentIsSelected) { - - var newSelection = this.selection.clone(); - newSelection.push(elementController) - this.setSelection(newSelection) + tspan.setAttributeNS(null, 'x', x); + tspan.setAttributeNS(null, 'y', y); + indic.push(index); + } - ORYX.Log.trace("Rule #4 applied for mouse down on %0", element.id); + }).bind(this)); - // Rule #6 - } else if(currentIsSelectable && currentIsSelected && - modifierKeyPressed) { + indic.length = tspans.length; + this.indices = this.indices || indic; - var newSelection = this.selection.clone(); - this.setSelection(newSelection.without(elementController)) + invalidTSpans.each(function (tspan) { + this.node.removeChild(tspan) + }.bind(this)); - ORYX.Log.trace("Rule #6 applied for mouse down on %0", elementController.id); + //set horizontal alignment + switch (this._horizontalAlign) { + case 'left': + this.node.setAttributeNS(null, 'text-anchor', 'start'); + break; + case 'center': + this.node.setAttributeNS(null, 'text-anchor', 'middle'); + break; + case 'right': + this.node.setAttributeNS(null, 'text-anchor', 'end'); + break; + } - // Rule #5: When there is at least one object selected and no control - // key pressed, we're dragging. - /*} else if(currentIsSelectable && !noObjectsSelected - && !modifierKeyPressed) { + } catch (e) { + //console.log(e); + this._isChanged = true; + } - if(this.log.isTraceEnabled()) - this.log.trace("Rule #5 applied for mouse down on "+element.id); -*/ - // Rule #2: When clicked on something that is neither - // selectable nor movable, clear the selection, and return. - } else if (!currentIsSelectable && !currentIsMovable) { - - this.setSelection([]); - - ORYX.Log.trace("Rule #2 applied for mouse down on %0", element.id); - return; + if (this.isVisible) { + this.node.removeAttributeNS(null, 'visibility'); + } - // Rule #7: When the current object is not selectable but movable, - // it is probably a control. Leave the selection unchanged but set - // the movedObject to the current one and enable Drag. Dockers will - // be processed in the dragDocker plugin. - } else if(!currentIsSelectable && currentIsMovable && !(elementController instanceof ORYX.Core.Controls.Docker)) { - - // TODO: If there is any moveable elements, do this in a plugin - //ORYX.Core.UIEnableDrag(event, elementController); - - ORYX.Log.trace("Rule #7 applied for mouse down on %0", element.id); - - // Rule #8: When the element is selectable and is currently selected and no - // modifier key is pressed - } else if(currentIsSelectable && currentIsSelected && - !modifierKeyPressed) { - - this._subSelection = this._subSelection != elementController ? elementController : undefined; - - this.setSelection(this.selection, this._subSelection); - - ORYX.Log.trace("Rule #8 applied for mouse down on %0", element.id); - } - - - // prevent event from bubbling, return. - //Event.stop(event); - return; - }, - _handleMouseMove: function(event, uiObj) { - return; - }, + // Finished + delete this._isUpdating; - _handleMouseUp: function(event, uiObj) { - // get canvas. - var canvas = this.getCanvas(); + // Raise change event + (this.changeCallbacks || []).each(function (fn) { + fn.apply(fn); + }) - // find the shape that is responsible for this elemement's id. - var elementController = uiObj; + }, - //get event position - var evPos = this.eventCoordinates(event); + /** + * Returns the text length of the text content of an SVG tspan element. + * For all browsers but Firefox 3 the values are estimated. + * @param {TSpanSVGElement} tspan + * @param {int} startIndex Optional, for sub strings + * @param {int} endIndex Optional, for sub strings + */ + _getRenderedTextLength: function (tspan, startIndex, endIndex, fontSize) { + //if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent) && new Number(RegExp.$1) >= 3) { + if (startIndex === undefined) { +//test string: abcdefghijklmnopqrstuvwxyz????????????????,.-#+ 1234567890?????ABCDEFGHIJKLMNOPQRSTUVWXYZ;:_'*???????????????!"????$%&/()=?[]{}|<>'~????`\^?????????@????????????????? +// for(var i = 0; i < tspan.textContent.length; i++) { +// console.log(tspan.textContent.charAt(i), tspan.getSubStringLength(i,1), this._estimateCharacterWidth(tspan.textContent.charAt(i))*(fontSize/14.0)); +// } + return tspan.getComputedTextLength(); + } else { + return tspan.getSubStringLength(startIndex, endIndex); + } + /*} else { + if(startIndex === undefined) { + return this._estimateTextWidth(tspan.textContent, fontSize); + } else { + return this._estimateTextWidth(tspan.textContent.substr(startIndex, endIndex).trim(), fontSize); + } + }*/ + }, - //Event.stop(event); - }, + /** + * Estimates the text width for a string. + * Used for word wrapping in all browser but FF3. + * @param {Object} text + */ + _estimateTextWidth: function (text, fontSize) { + var sum = 0.0; + for (var i = 0; i < text.length; i++) { + sum += this._estimateCharacterWidth(text.charAt(i)); + } - _handleMouseHover: function(event, uiObj) { - return; - }, + return sum * (fontSize / 14.0); + }, - _handleMouseOut: function(event, uiObj) { - return; - }, + /** + * Estimates the width of a single character for font size 14. + * Used for word wrapping in all browser but FF3. + * @param {Object} character + */ + _estimateCharacterWidth: function (character) { + for (var i = 0; i < this._characterSets.length; i++) { + if (this._characterSets[i].indexOf(character) >= 0) { + return this._characterSetValues[i]; + } + } + return 9; + }, - /** - * Calculates the event coordinates to SVG document coordinates. - * @param {Event} event - * @return {SVGPoint} The event coordinates in the SVG document - */ - eventCoordinates: function(event) { + getReferencedElementWidth: function () { + var refNode = this.node.ownerDocument.getElementById(this.fitToElemId); - var canvas = this.getCanvas(); + if (refNode) { + var refbb = refNode.getBBox(); - var svgPoint = canvas.node.ownerSVGElement.createSVGPoint(); - svgPoint.x = event.clientX; - svgPoint.y = event.clientY; - - var additionalIEZoom = 1; - if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { - var ua = navigator.userAgent; - if (ua.indexOf('MSIE') >= 0) { - //IE 10 and below - var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); - if (zoom !== 100) { - additionalIEZoom = zoom / 100 - } + if (refbb) { + return (this._rotate != 0 + && this._rotate % 180 != 0 + && this._rotate % 90 == 0 ? + refbb.height : refbb.width); } } - - if (additionalIEZoom !== 1) { - svgPoint.x = svgPoint.x * additionalIEZoom; - svgPoint.y = svgPoint.y * additionalIEZoom; - } - - var matrix = canvas.node.getScreenCTM(); - return svgPoint.matrixTransform(matrix.inverse()); - }, - - eventCoordinatesXY: function(x, y) { - var canvas = this.getCanvas(); + return undefined; + }, - var svgPoint = canvas.node.ownerSVGElement.createSVGPoint(); - svgPoint.x = x; - svgPoint.y = y; - - var additionalIEZoom = 1; - if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { - var ua = navigator.userAgent; - if (ua.indexOf('MSIE') >= 0) { - //IE 10 and below - var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); - if (zoom !== 100) { - additionalIEZoom = zoom / 100 + /** + * If no parameter is provided, this method returns the current text. + * @param text {String} Optional. Replaces the old text with this one. + */ + text: function () { + switch (arguments.length) { + case 0: + return this._text + break; + + case 1: + var oldText = this._text; + if (arguments[0]) { + // Filter out multiple spaces to fix issue in chrome for line-wrapping + this._text = arguments[0].toString(); + if (this._text != null && this._text != undefined) { + this._text = this._text.replace(/ {2,}/g, ' '); + } + } else { + this._text = ""; } - } + if (oldText !== this._text) { + this._isChanged = true; + this._textHasChanged = true; + } + break; + + default: + //TODO error + break; } - - if (additionalIEZoom !== 1) { - svgPoint.x = svgPoint.x * additionalIEZoom; - svgPoint.y = svgPoint.y * additionalIEZoom; + }, + + getOriginVerticalAlign: function () { + return this._originVerticalAlign; + }, + + verticalAlign: function () { + switch (arguments.length) { + case 0: + return this._verticalAlign; + case 1: + if (['top', 'middle', 'bottom'].member(arguments[0])) { + var oldValue = this._verticalAlign; + this._verticalAlign = arguments[0]; + if (this._verticalAlign !== oldValue) { + this._isChanged = true; + } + } + break; + + default: + //TODO error + break; } - - var matrix = canvas.node.getScreenCTM(); - return svgPoint.matrixTransform(matrix.inverse()); - } -}; -ORYX.Editor = Clazz.extend(ORYX.Editor); + }, -/** - * Creates a new ORYX.Editor instance by fetching a model from given url and passing it to the constructur - * @param {String} modelUrl The JSON URL of a model. - * @param {Object} config Editor config passed to the constructur, merged with the response of the request to modelUrl - */ -ORYX.Editor.createByUrl = function(modelUrl){ - new Ajax.Request(modelUrl, { - method: 'GET', - onSuccess: function(transport) { - var editorConfig = JSON.parse(transport.responseText); - new ORYX.Editor(editorConfig); - }.bind(this) - }); -} + getOriginHorizontalAlign: function () { + return this._originHorizontalAlign; + }, -// TODO Implement namespace awareness on attribute level. -/** - * graft() function - * Originally by Sean M. Burke from interglacial.com, altered for usage with - * SVG and namespace (xmlns) support. Be sure you understand xmlns before - * using this funtion, as it creates all grafted elements in the xmlns - * provided by you and all element's attribures in default xmlns. If you - * need to graft elements in a certain xmlns and wish to assign attributes - * in both that and another xmlns, you will need to do stepwise grafting, - * adding non-default attributes yourself or you'll have to enhance this - * function. Latter, I would appreciate: martin???apfelfabrik.de - * @param {Object} namespace The namespace in which - * elements should be grafted. - * @param {Object} parent The element that should contain the grafted - * structure after the function returned. - * @param {Object} t the crafting structure. - * @param {Object} doc the document in which grafting is performed. - */ -ORYX.Editor.graft = function(namespace, parent, t, doc) { + horizontalAlign: function () { + switch (arguments.length) { + case 0: + return this._horizontalAlign; + case 1: + if (['left', 'center', 'right'].member(arguments[0])) { + var oldValue = this._horizontalAlign; + this._horizontalAlign = arguments[0]; + if (this._horizontalAlign !== oldValue) { + this._isChanged = true; + } + } + break; - doc = (doc || (parent && parent.ownerDocument) || document); - var e; - if(t === undefined) { - throw "Can't graft an undefined value"; - } else if(t.constructor == String) { - e = doc.createTextNode( t ); - } else { - for(var i = 0; i < t.length; i++) { - if( i === 0 && t[i].constructor == String ) { - var snared; - snared = t[i].match( /^([a-z][a-z0-9]*)\.([^\s\.]+)$/i ); - if( snared ) { - e = doc.createElementNS(namespace, snared[1] ); - e.setAttributeNS(null, 'class', snared[2] ); - continue; + default: + //TODO error + break; + } + }, + + rotate: function () { + switch (arguments.length) { + case 0: + return this._rotate; + case 1: + if (this._rotate != arguments[0]) { + this._rotate = arguments[0]; + this._rotationPoint = undefined; + this._isChanged = true; } - snared = t[i].match( /^([a-z][a-z0-9]*)$/i ); - if( snared ) { - e = doc.createElementNS(namespace, snared[1] ); // but no class - continue; + case 2: + if (this._rotate != arguments[0] || + !this._rotationPoint || + this._rotationPoint.x != arguments[1].x || + this._rotationPoint.y != arguments[1].y) { + this._rotate = arguments[0]; + this._rotationPoint = arguments[1]; + this._isChanged = true; } - // Otherwise: - e = doc.createElementNS(namespace, "span" ); - e.setAttribute(null, "class", "namelessFromLOL" ); - } - - if( t[i] === undefined ) { - throw "Can't graft an undefined value in a list!"; - } else if( t[i].constructor == String || t[i].constructor == Array ) { - this.graft(namespace, e, t[i], doc ); - } else if( t[i].constructor == Number ) { - this.graft(namespace, e, t[i].toString(), doc ); - } else if( t[i].constructor == Object ) { - // hash's properties => element's attributes - for(var k in t[i]) { e.setAttributeNS(null, k, t[i][k] ); } - } else { + } + }, - } + hide: function () { + if (this.isVisible) { + this.isVisible = false; + this._isChanged = true; } - } - if(parent && parent.appendChild) { - parent.appendChild( e ); - } else { + }, - } - return e; // return the topmost created node -}; + show: function () { + if (!this.isVisible) { + this.isVisible = true; + this._isChanged = true; -ORYX.Editor.provideId = function() { - var res = [], hex = '0123456789ABCDEF'; + // Since text is removed from the tspan when "hidden", mark + // the text as changed to get it redrawn + this._textHasChanged = true; + } + }, - for (var i = 0; i < 36; i++) res[i] = Math.floor(Math.random()*0x10); + /** + * iterates parent nodes till it finds a SVG font-size + * attribute. + * @param {SVGElement} node + */ + getInheritedFontSize: function (node) { + if (!node || !node.getAttributeNS) + return; - res[14] = 4; - res[19] = (res[19] & 0x3) | 0x8; + var attr = node.getAttributeNS(null, "font-size"); + if (attr) { + return parseFloat(attr); + } else if (!ORYX.Editor.checkClassType(node, SVGSVGElement)) { + return this.getInheritedFontSize(node.parentNode); + } + }, - for (var i = 0; i < 36; i++) res[i] = hex[res[i]]; + getFontSize: function (node) { + var tspans = this.node.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'tspan'); - res[8] = res[13] = res[18] = res[23] = '-'; + //trying to get an inherited font-size attribute + //NO CSS CONSIDERED! + var fontSize = this.getInheritedFontSize(this.node); - return "oryx_" + res.join(''); -}; + if (!fontSize) { + //because this only works in firefox 3, all other browser use the default line height + if (tspans[0] && /Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent) && new Number(RegExp.$1) >= 3) { + fontSize = tspans[0].getExtentOfChar(0).height; + } else { + fontSize = ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT; + } -/** - * When working with Ext, conditionally the window needs to be resized. To do - * so, use this class method. Resize is deferred until 100ms, and all subsequent - * resizeBugFix calls are ignored until the initially requested resize is - * performed. - */ -ORYX.Editor.resizeFix = function() { - if (!ORYX.Editor._resizeFixTimeout) { - ORYX.Editor._resizeFixTimeout = window.setTimeout(function() { - window.resizeBy(1,1); - window.resizeBy(-1,-1); - ORYX.Editor._resizefixTimeout = null; - }, 100); - } -}; + //handling of unsupported method in webkit + if (fontSize <= 0) { + fontSize = ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT; + } + } -ORYX.Editor.Cookie = { - - callbacks:[], - - onChange: function( callback, interval ){ - - this.callbacks.push(callback); - this.start( interval ) - - }, - - start: function( interval ){ - - if( this.pe ){ - return; - } - - var currentString = document.cookie; - - this.pe = new PeriodicalExecuter( function(){ - - if( currentString != document.cookie ){ - currentString = document.cookie; - this.callbacks.each(function(callback) { callback(this.getParams()) }.bind(this)); - } - - }.bind(this), ( interval || 10000 ) / 1000); - }, - - stop: function(){ + if (fontSize) + this.node.setAttribute("oryx:fontSize", fontSize); - if( this.pe ){ - this.pe.stop(); - this.pe = null; - } - }, - - getParams: function(){ - var res = {}; - - var p = document.cookie; - p.split("; ").each(function(param){ res[param.split("=")[0]] = param.split("=")[1];}); - - return res; - }, - - toString: function(){ - return document.cookie; - } -}; + return fontSize; + }, -/** - * Workaround for SAFARI/Webkit, because - * when trying to check SVGSVGElement of instanceof there is - * raising an error - * - */ -ORYX.Editor.SVGClassElementsAreAvailable = true; -ORYX.Editor.setMissingClasses = function() { - - try { - SVGElement; - } catch(e) { - ORYX.Editor.SVGClassElementsAreAvailable = false; - SVGSVGElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg').toString(); - SVGGElement = document.createElementNS('http://www.w3.org/2000/svg', 'g').toString(); - SVGPathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path').toString(); - SVGTextElement = document.createElementNS('http://www.w3.org/2000/svg', 'text').toString(); - //SVGMarkerElement = document.createElementNS('http://www.w3.org/2000/svg', 'marker').toString(); - SVGRectElement = document.createElementNS('http://www.w3.org/2000/svg', 'rect').toString(); - SVGImageElement = document.createElementNS('http://www.w3.org/2000/svg', 'image').toString(); - SVGCircleElement = document.createElementNS('http://www.w3.org/2000/svg', 'circle').toString(); - SVGEllipseElement = document.createElementNS('http://www.w3.org/2000/svg', 'ellipse').toString(); - SVGLineElement = document.createElementNS('http://www.w3.org/2000/svg', 'line').toString(); - SVGPolylineElement = document.createElementNS('http://www.w3.org/2000/svg', 'polyline').toString(); - SVGPolygonElement = document.createElementNS('http://www.w3.org/2000/svg', 'polygon').toString(); - - } - -} -ORYX.Editor.checkClassType = function( classInst, classType ) { - - if( ORYX.Editor.SVGClassElementsAreAvailable ){ - return classInst instanceof classType - } else { - return classInst == classType - } -}; -/* + /** + * Get trimmed text length for use with + * getExtentOfChar and getSubStringLength. + * @param {String} text + */ + getTrimmedTextLength: function (text) { + text = text.strip().gsub(' ', ' '); + + var oldLength; + do { + oldLength = text.length; + text = text.gsub(' ', ' '); + } while (oldLength > text.length); + + return text.length; + }, + + /** + * Returns the offset from + * edge to the label which is + * positioned under the edge + * @return {int} + */ + getOffsetBottom: function () { + return this.offsetBottom; + }, + + + /** + * Returns the offset from + * edge to the label which is + * positioned over the edge + * @return {int} + */ + getOffsetTop: function () { + return this.offsetTop; + }, + + /** + * + * @param {Object} obj + */ + deserialize: function (obj, shape) { + if (obj && "undefined" != typeof obj.x && "undefined" != typeof obj.y) { + this.setPosition({x: obj.x, y: obj.y}); + + if ("undefined" != typeof obj.distance) { + var from = shape.dockers[obj.from]; + var to = shape.dockers[obj.to]; + if (from && to) { + this.setReferencePoint({ + dirty: true, + distance: obj.distance, + intersection: {x: obj.x, y: obj.y}, + orientation: obj.orientation, + segment: { + from: from, + fromIndex: obj.from, + fromPosition: from.bounds.center(), + to: to, + toIndex: obj.to, + toPosition: to.bounds.center() + } + }) + } + } + + if (obj.left) this.anchorLeft = true; + if (obj.right) this.anchorRight = true; + if (obj.top) this.anchorTop = true; + if (obj.bottom) this.anchorBottom = true; + if (obj.valign) this.verticalAlign(obj.valign); + if (obj.align) this.horizontalAlign(obj.align); + + } else if (obj && "undefined" != typeof obj.edge) { + this.setEdgePosition(obj.edge); + } + }, + + /** + * + * @return {Object} + */ + serialize: function () { + + // On edge position + if (this.getEdgePosition()) { + if (this.getOriginEdgePosition() !== this.getEdgePosition()) { + return {edge: this.getEdgePosition()}; + } else { + return null; + } + } + + // On self defined position + if (this.position) { + var pos = {x: this.position.x, y: this.position.y}; + if (this.isAnchorLeft() && this.isAnchorLeft() !== this.isOriginAnchorLeft()) { + pos.left = true; + } + if (this.isAnchorRight() && this.isAnchorRight() !== this.isOriginAnchorRight()) { + pos.right = true; + } + if (this.isAnchorTop() && this.isAnchorTop() !== this.isOriginAnchorTop()) { + pos.top = true; + } + if (this.isAnchorBottom() && this.isAnchorBottom() !== this.isOriginAnchorBottom()) { + pos.bottom = true; + } + + if (this.getOriginVerticalAlign() !== this.verticalAlign()) { + pos.valign = this.verticalAlign(); + } + if (this.getOriginHorizontalAlign() !== this.horizontalAlign()) { + pos.align = this.horizontalAlign(); + } + + return pos; + } + + // On reference point which is interesting for edges + if (this.getReferencePoint()) { + var ref = this.getReferencePoint(); + return { + distance: ref.distance, + x: ref.intersection.x, + y: ref.intersection.y, + from: ref.segment.fromIndex, + to: ref.segment.toIndex, + orientation: ref.orientation, + valign: this.verticalAlign(), + align: this.horizontalAlign() + } + } + return null; + }, + + toString: function () { + return "Label " + this.id + } +});/* * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. * License rights for this program may be obtained from Alfresco Software, Ltd. * pursuant to a written agreement and any use of this program without such an @@ -12610,2426 +5386,14714 @@ ORYX.Editor.checkClassType = function( classInst, classType ) { /** * Init namespaces */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} - - -new function(){ - - ORYX.Core.UIEnableDrag = function(event, uiObj, option) { - - this.uiObj = uiObj; - var upL = uiObj.bounds.upperLeft(); - - var a = uiObj.node.getScreenCTM(); - this.faktorXY= {x: a.a, y: a.d}; - - this.scrollNode = uiObj.node.ownerSVGElement.parentNode.parentNode; - - this.offSetPosition = { - x: Event.pointerX(event) - (upL.x * this.faktorXY.x), - y: Event.pointerY(event) - (upL.y * this.faktorXY.y)}; - - this.offsetScroll = {x:this.scrollNode.scrollLeft,y:this.scrollNode.scrollTop}; - - this.dragCallback = ORYX.Core.UIDragCallback.bind(this); - this.disableCallback = ORYX.Core.UIDisableDrag.bind(this); - - this.movedCallback = option ? option.movedCallback : undefined; - this.upCallback = option ? option.upCallback : undefined; - - document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.disableCallback, true); - document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.dragCallback , false); - - }; - - ORYX.Core.UIDragCallback = function(event) { - - var position = { - x: Event.pointerX(event) - this.offSetPosition.x, - y: Event.pointerY(event) - this.offSetPosition.y} - - position.x -= this.offsetScroll.x - this.scrollNode.scrollLeft; - position.y -= this.offsetScroll.y - this.scrollNode.scrollTop; - - position.x /= this.faktorXY.x; - position.y /= this.faktorXY.y; - - this.uiObj.bounds.moveTo(position); - //this.uiObj.update(); - - if(this.movedCallback) - this.movedCallback(event); - - //Event.stop(event); - - }; - - ORYX.Core.UIDisableDrag = function(event) { - document.documentElement.removeEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.dragCallback, false); - document.documentElement.removeEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.disableCallback, true); - - if(this.upCallback) - this.upCallback(event); - - this.upCallback = undefined; - this.movedCallback = undefined; - - Event.stop(event); - }; - - - - - /** - * Implements a command to move docker by an offset. - * - * @class ORYX.Core.MoveDockersCommand - * @param {Object} object An object with the docker id as key and docker and offset as object value - * - */ - ORYX.Core.MoveDockersCommand = ORYX.Core.Command.extend({ - construct: function(dockers){ - this.dockers = $H(dockers); - this.edges = $H({}); - }, - execute: function(){ - if (this.changes) { - this.executeAgain(); - return; - } else { - this.changes = $H({}); - } - - this.dockers.values().each(function(docker){ - var edge = docker.docker.parent; - if (!edge){ return } - - if (!this.changes[edge.getId()]) { - this.changes[edge.getId()] = { - edge : edge, - oldDockerPositions : edge.dockers.map(function(r){ return r.bounds.center() }) - } - } - docker.docker.bounds.moveBy(docker.offset); - this.edges[edge.getId()] = edge; - docker.docker.update(); - }.bind(this)); - this.edges.each(function(edge){ - this.updateEdge(edge.value); - if (this.changes[edge.value.getId()]) - this.changes[edge.value.getId()].dockerPositions = edge.value.dockers.map(function(r){ return r.bounds.center() }) - }.bind(this)); - }, - updateEdge: function(edge){ - edge._update(true); - [edge.getOutgoingShapes(), edge.getIncomingShapes()].flatten().invoke("_update", [true]) - }, - executeAgain: function(){ - this.changes.values().each(function(change){ - // Reset the dockers - this.removeAllDocker(change.edge); - change.dockerPositions.each(function(pos, i){ - if (i==0||i==change.dockerPositions.length-1){ return } - var docker = change.edge.createDocker(undefined, pos); - docker.bounds.centerMoveTo(pos); - docker.update(); - }.bind(this)); - this.updateEdge(change.edge); - }.bind(this)); - }, - rollback: function(){ - this.changes.values().each(function(change){ - // Reset the dockers - this.removeAllDocker(change.edge); - change.oldDockerPositions.each(function(pos, i){ - if (i==0||i==change.oldDockerPositions.length-1){ return } - var docker = change.edge.createDocker(undefined, pos); - docker.bounds.centerMoveTo(pos); - docker.update(); - }.bind(this)); - this.updateEdge(change.edge); - }.bind(this)); - }, - removeAllDocker: function(edge){ - edge.dockers.slice(1, edge.dockers.length-1).each(function(docker){ - edge.removeDocker(docker); - }) - } - }); - -}(); -/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} +if (!ORYX.Core.Math) { + ORYX.Core.Math = {}; +} /** - * Init namespaces + * Calculate the middle point between two given points + * @param {x:double, y:double} point1 + * @param {x:double, y:double} point2 + * @return the middle point */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} +ORYX.Core.Math.midPoint = function (point1, point2) { + return { + x: (point1.x + point2.x) / 2.0, + y: (point1.y + point2.y) / 2.0 + } +} /** - * @classDescription Base class for Shapes. - * @extends ORYX.Core.AbstractShape + * Returns a TRUE if the point is over a line (defined by + * point1 and point 2). In Addition a threshold can be set, + * which defines the weight of those line. + * + * @param {int} pointX - Point X + * @param {int} pointY - Point Y + * @param {int} lPoint1X - Line first Point X + * @param {int} lPoint1Y - Line first Point Y + * @param {int} lPoint2X - Line second Point X + * @param {int} lPoint2Y - Line second Point y + * @param {int} offset {optional} - maximal distance to line + * @class ORYX.Core.Math.prototype */ -ORYX.Core.Shape = { +ORYX.Core.Math.isPointInLine = function (pointX, pointY, lPoint1X, lPoint1Y, lPoint2X, lPoint2Y, offset) { - /** - * Constructor - */ - construct: function(options, stencil, facade) { - // call base class constructor - arguments.callee.$.construct.apply(this, arguments); - - this.facade = facade; - this.dockers = []; - this.magnets = []; - - this._defaultMagnet; - - this.incoming = []; - this.outgoing = []; - - this.nodes = []; - - this._dockerChangedCallback = this._dockerChanged.bind(this); - - //Hash map for all labels. Labels are not treated as children of shapes. - this._labels = new Hash(); - - // create SVG node - this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", - null, - ['g', {id:"svg-" + this.resourceId}, - ['g', {"class": "stencils"}, - ['g', {"class": "me"}], - ['g', {"class": "children", style:"overflow:hidden"}], - ['g', {"class": "edge"}] - ], - ['g', {"class": "controls"}, - ['g', {"class": "dockers"}], - ['g', {"class": "magnets"}] - ] - ]); - }, + offset = offset ? Math.abs(offset) : 1; - /** - * If changed flag is set, refresh method is called. - */ - update: function() { - //if(this.isChanged) { - //this.layout(); - //} - }, - - /** - * !!!Not called from any sub class!!! - */ - _update: function() { + // Check if the edge is vertical + if (Math.abs(lPoint1X - lPoint2X) <= offset && Math.abs(pointX - lPoint1X) <= offset && pointY - Math.max(lPoint1Y, lPoint2Y) <= offset && Math.min(lPoint1Y, lPoint2Y) - pointY <= offset) { + return true + } - }, - - /** - * Calls the super class refresh method - * and updates the svg elements that are referenced by a property. - */ - refresh: function() { - //call base class refresh method - arguments.callee.$.refresh.apply(this, arguments); - - if(this.node.ownerDocument) { - //adjust SVG to properties' values - var me = this; - this.propertiesChanged.each((function(propChanged) { - if(propChanged.value) { - var prop = this.properties[propChanged.key]; - var property = this.getStencil().property(propChanged.key); - if (property != undefined) { - this.propertiesChanged[propChanged.key] = false; - - //handle choice properties - if(property.type() == ORYX.CONFIG.TYPE_CHOICE) { - //iterate all references to SVG elements - property.refToView().each((function(ref) { - //if property is referencing a label, update the label - if(ref !== "") { - var label = this._labels[this.id + ref]; - if (label && property.item(prop)) { - label.text(property.item(prop).title()); - } - } - }).bind(this)); - - //if the choice's items are referencing SVG elements - // show the selected and hide all other referenced SVG - // elements - var refreshedSvgElements = new Hash(); - property.items().each((function(item) { - item.refToView().each((function(itemRef) { - if(itemRef == "") { return; } - - var svgElem = this.node.ownerDocument.getElementById(this.id + itemRef); - - if(!svgElem) { return; } - - - /* Do not refresh the same svg element multiple times */ - if(!refreshedSvgElements[svgElem.id] || prop == item.value()) { - svgElem.setAttributeNS(null, 'display', ((prop == item.value()) ? 'inherit' : 'none')); - refreshedSvgElements[svgElem.id] = svgElem; - } - - // Reload the href if there is an image-tag - if(ORYX.Editor.checkClassType(svgElem, SVGImageElement)) { - svgElem.setAttributeNS('http://www.w3.org/1999/xlink', 'href', svgElem.getAttributeNS('http://www.w3.org/1999/xlink', 'href')); - } - }).bind(this)); - }).bind(this)); - - } else { //handle properties that are not of type choice - //iterate all references to SVG elements - property.refToView().each((function(ref) { - //if the property does not reference an SVG element, - // do nothing - - if(ref === "") { return; } - - var refId = this.id + ref; - - if (property.type() === ORYX.CONFIG.TYPE_KISBPM_MULTIINSTANCE) - { - if (ref === "multiinstance") { - - var svgElemParallel = this.node.ownerDocument.getElementById(this.id + 'parallel'); - if(svgElemParallel) - { - if (prop === 'Parallel') - { - svgElemParallel.setAttributeNS(null, 'display', 'inherit'); - } - else - { - svgElemParallel.setAttributeNS(null, 'display', 'none'); - } - } - - var svgElemSequential = this.node.ownerDocument.getElementById(this.id + 'sequential'); - - if(svgElemSequential) - { - if (prop === 'Sequential') - { - svgElemSequential.setAttributeNS(null, 'display', 'inherit'); - } - else - { - svgElemSequential.setAttributeNS(null, 'display', 'none'); - } - } - } - return; - - } - else if (property.type() === "cancelactivity") - { - var svgElemFrame = this.node.ownerDocument.getElementById(this.id + 'frame'); - var svgElemFrame2 = this.node.ownerDocument.getElementById(this.id + 'frame2'); - - if (prop === 'true') - { - svgElemFrame.setAttributeNS(null, 'display', 'inherit'); - svgElemFrame2.setAttributeNS(null, 'display', 'inherit'); - } - else - { - svgElemFrame.setAttributeNS(null, 'display', 'none'); - svgElemFrame2.setAttributeNS(null, 'display', 'none'); - } - } - - //get the SVG element - var svgElem = this.node.ownerDocument.getElementById(refId); - - //if the SVG element can not be found - if(!svgElem || !(svgElem.ownerSVGElement)) { - //if the referenced SVG element is a SVGAElement, it cannot - // be found with getElementById (Firefox bug). - // this is a work around - if(property.type() === ORYX.CONFIG.TYPE_URL || property.type() === ORYX.CONFIG.TYPE_DIAGRAM_LINK) { - var svgElems = this.node.ownerDocument.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'a'); - - svgElem = $A(svgElems).find(function(elem) { - return elem.getAttributeNS(null, 'id') === refId; - }); - - if(!svgElem) { return; } - } else { - //this.propertiesChanged[propChanged.key] = true; - return; - } - } - - if (property.complexAttributeToView()) { - var label = this._labels[refId]; - if (label) { - try { - propJson = prop.evalJSON(); - var value = propJson[property.complexAttributeToView()] - label.text(value ? value : prop); - } catch (e) { - label.text(prop); - } - } - - } else { - switch (property.type()) { - case ORYX.CONFIG.TYPE_BOOLEAN: - if (typeof prop == "string") - prop = prop === "true" - - svgElem.setAttributeNS(null, 'display', (!(prop === property.inverseBoolean())) ? 'inherit' : 'none'); - - break; - case ORYX.CONFIG.TYPE_COLOR: - if(property.fill()) { - if (svgElem.tagName.toLowerCase() === "stop"){ - if (prop){ - - if (property.lightness() && property.lightness() !== 1){ - prop = ORYX.Utils.adjustLightness(prop, property.lightness()); - } - - svgElem.setAttributeNS(null, "stop-color", prop); - - // Adjust stop color of the others - if (svgElem.parentNode.tagName.toLowerCase() === "radialgradient"){ - ORYX.Utils.adjustGradient(svgElem.parentNode, svgElem); - } - } - - // If there is no value, set opaque - if (svgElem.parentNode.tagName.toLowerCase() === "radialgradient"){ - $A(svgElem.parentNode.getElementsByTagName('stop')).each(function(stop){ - stop.setAttributeNS(null, "stop-opacity", prop ? stop.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'default-stop-opacity') || 1 : 0); - }.bind(this)) - } - } else { - svgElem.setAttributeNS(null, 'fill', prop); - } - } - if(property.stroke()) { - svgElem.setAttributeNS(null, 'stroke', prop); - } - break; - case ORYX.CONFIG.TYPE_STRING: - var label = this._labels[refId]; - if (label) { - label.text(prop); - } - break; - case ORYX.CONFIG.TYPE_EXPRESSION: - var label = this._labels[refId]; - if (label) { - label.text(prop); - } - break; - case ORYX.CONFIG.TYPE_DATASOURCE: - var label = this._labels[refId]; - if (label) { - label.text(prop); - } - break; - case ORYX.CONFIG.TYPE_INTEGER: - var label = this._labels[refId]; - if (label) { - label.text(prop); - } - break; - case ORYX.CONFIG.TYPE_FLOAT: - if(property.fillOpacity()) { - svgElem.setAttributeNS(null, 'fill-opacity', prop); - } - if(property.strokeOpacity()) { - svgElem.setAttributeNS(null, 'stroke-opacity', prop); - } - if(!property.fillOpacity() && !property.strokeOpacity()) { - var label = this._labels[refId]; - if (label) { - label.text(prop); - } - } - break; - - case ORYX.CONFIG.TYPE_FORM_LINK: - if (ref == "pimg") { - var onclickAttr = svgElem.getAttributeNodeNS('', 'onclick'); - if(onclickAttr) { - if(prop && ("" + prop).length > 0) { - onclickAttr.textContent = "window.location = '../service/editor?id=" + prop + "_form'"; - } else { - newFormFacade = this.facade; - onclickAttr.textContent = "displayNewFormDialog('" + this.resourceId + "');"; - } - } - } else if (ref == "linkIndicator") { - if (prop && prop.length > 0) { - svgElem.setAttributeNS(null, 'display', 'inherit'); - } else { - svgElem.setAttributeNS(null, 'display', 'none'); - } - } - break; - case ORYX.CONFIG.TYPE_URL: - case ORYX.CONFIG.TYPE_DIAGRAM_LINK: - //TODO what is the dafault path? - var hrefAttr = svgElem.getAttributeNodeNS('http://www.w3.org/1999/xlink', 'xlink:href'); - if(hrefAttr) { - hrefAttr.textContent = prop; - } else { - svgElem.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', prop); - } - break; - - } - } - }).bind(this)); - - - } - } - - } - }).bind(this)); - - //update labels - this._labels.values().each(function(label) { - label.update(); - }); - } - }, - - layout: function() { - //this.getStencil().layout(this) - var layoutEvents = this.getStencil().layout() - if (layoutEvents) { - layoutEvents.each(function(event) { - - // setup additional attributes - event.shape = this; - event.forceExecution = true; - - // do layouting - this._delegateEvent(event); - }.bind(this)) - - } - }, - - /** - * Returns an array of Label objects. - */ - getLabels: function() { - return this._labels.values(); - }, - - /** - * Returns the label for a given ref - * @return {ORYX.Core.Label} Returns null if there is no label - */ - getLabel: function(ref){ - if (!ref){ - return null; - } - return (this._labels.find(function(o){ - return o.key.endsWith(ref); - })||{}).value || null; - }, - - /** - * Hides all related labels - * - */ - hideLabels: function(){ - this.getLabels().invoke("hide"); - }, + // Check if the edge is horizontal + if (Math.abs(lPoint1Y - lPoint2Y) <= offset && Math.abs(pointY - lPoint1Y) <= offset && pointX - Math.max(lPoint1X, lPoint2X) <= offset && Math.min(lPoint1X, lPoint2X) - pointX <= offset) { + return true + } - /** - * Shows all related labels - * - */ - showLabels: function(){ - var labels = this.getLabels(); - labels.invoke("show"); - labels.each(function(label) { - label.update(); - }); - }, - - setOpacity: function(value, animate){ - - value = Math.max(Math.min((typeof value == "number" ? value : 1.0), 1.0), 0.0); - - if (value !== 1.0){ - value = String(value); - this.node.setAttributeNS(null, "fill-opacity", value) - this.node.setAttributeNS(null, "stroke-opacity", value) - } else { - this.node.removeAttributeNS(null, "fill-opacity"); - this.node.removeAttributeNS(null, "stroke-opacity"); - } - }, - - /** - * Returns an array of dockers of this object. - */ - getDockers: function() { - return this.dockers; - }, - - getMagnets: function() { - return this.magnets; - }, - - getDefaultMagnet: function() { - if(this._defaultMagnet) { - return this._defaultMagnet; - } else if (this.magnets.length > 0) { - return this.magnets[0]; - } else { - return undefined; - } - }, + if (pointX > Math.max(lPoint1X, lPoint2X) || pointX < Math.min(lPoint1X, lPoint2X)) { + return false + } - getParentShape: function() { - return this.parent; - }, - - getIncomingShapes: function(iterator) { - if(iterator) { - this.incoming.each(iterator); - } - return this.incoming; - }, - - getIncomingNodes: function(iterator) { - return this.incoming.select(function(incoming){ - var isNode = (incoming instanceof ORYX.Core.Node); - if(isNode && iterator) iterator(incoming); - return isNode; - }); - }, - - - getOutgoingShapes: function(iterator) { - if(iterator) { - this.outgoing.each(iterator); - } - return this.outgoing; - }, - - getOutgoingNodes: function(iterator) { - return this.outgoing.select(function(out){ - var isNode = (out instanceof ORYX.Core.Node); - if(isNode && iterator) iterator(out); - return isNode; - }); - }, - - getAllDockedShapes: function(iterator) { - var result = this.incoming.concat(this.outgoing); - if(iterator) { - result.each(iterator); - } - return result - }, + if (pointY > Math.max(lPoint1Y, lPoint2Y) || pointY < Math.min(lPoint1Y, lPoint2Y)) { + return false + } - getCanvas: function() { - if(this.parent instanceof ORYX.Core.Canvas) { - return this.parent; - } else if(this.parent instanceof ORYX.Core.Shape) { - return this.parent.getCanvas(); - } else { - return undefined; - } - }, - - /** - * - * @param {Object} deep - * @param {Object} iterator - */ - getChildNodes: function(deep, iterator) { - if(!deep && !iterator) { - return this.nodes.clone(); - } else { - var result = []; - this.nodes.each(function(uiObject) { - if(!uiObject.isVisible){return} - if(iterator) { - iterator(uiObject); - } - result.push(uiObject); - - if(deep && uiObject instanceof ORYX.Core.Shape) { - result = result.concat(uiObject.getChildNodes(deep, iterator)); - } - }); - - return result; - } - }, - - /** - * Overrides the UIObject.add method. Adds uiObject to the correct sub node. - * @param {UIObject} uiObject - * @param {Number} index - */ - add: function(uiObject, index, silent) { - //parameter has to be an UIObject, but - // must not be an Edge. - if(uiObject instanceof ORYX.Core.UIObject - && !(uiObject instanceof ORYX.Core.Edge)) { - - if (!(this.children.member(uiObject))) { - //if uiObject is child of another parent, remove it from that parent. - if(uiObject.parent) { - uiObject.parent.remove(uiObject, true); - } - - //add uiObject to this Shape - if(index != undefined) - this.children.splice(index, 0, uiObject); - else - this.children.push(uiObject); - - //set parent reference - uiObject.parent = this; - - //add uiObject.node to this.node depending on the type of uiObject - var parent; - if(uiObject instanceof ORYX.Core.Node) { - parent = this.node.childNodes[0].childNodes[1]; - this.nodes.push(uiObject); - } else if(uiObject instanceof ORYX.Core.Controls.Control) { - var ctrls = this.node.childNodes[1]; - if(uiObject instanceof ORYX.Core.Controls.Docker) { - parent = ctrls.childNodes[0]; - if (this.dockers.length >= 2){ - this.dockers.splice(index!==undefined?Math.min(index, this.dockers.length-1):this.dockers.length-1, 0, uiObject); - } else { - this.dockers.push(uiObject); - } - } else if(uiObject instanceof ORYX.Core.Controls.Magnet) { - parent = ctrls.childNodes[1]; - this.magnets.push(uiObject); - } else { - parent = ctrls; - } - } else { //UIObject - parent = this.node; - } - - if(index != undefined && index < parent.childNodes.length) - uiObject.node = parent.insertBefore(uiObject.node, parent.childNodes[index]); - else - uiObject.node = parent.appendChild(uiObject.node); - - this._changed(); - //uiObject.bounds.registerCallback(this._changedCallback); - - - if(this.eventHandlerCallback && silent !== true) - this.eventHandlerCallback({type:ORYX.CONFIG.EVENT_SHAPEADDED,shape:uiObject}) - - } else { + var s = (lPoint1Y - lPoint2Y) / (lPoint1X - lPoint2X); - ORYX.Log.warn("add: ORYX.Core.UIObject is already a child of this object."); - } - } else { + return Math.abs(pointY - ((s * pointX) + lPoint1Y - s * lPoint1X)) < offset +} - ORYX.Log.warn("add: Parameter is not of type ORYX.Core.UIObject."); - } - }, +/** + * Get a boolean if the point is in the polygone + * + */ +ORYX.Core.Math.isPointInEllipse = function (pointX, pointY, cx, cy, rx, ry) { - /** - * Overrides the UIObject.remove method. Removes uiObject. - * @param {UIObject} uiObject - */ - remove: function(uiObject, silent) { - //if uiObject is a child of this object, remove it. - if (this.children.member(uiObject)) { - //remove uiObject from children - var parent = uiObject.parent; - - this.children = this.children.without(uiObject); - - //delete parent reference of uiObject - uiObject.parent = undefined; - - //delete uiObject.node from this.node - if(uiObject instanceof ORYX.Core.Shape) { - if(uiObject instanceof ORYX.Core.Edge) { - uiObject.removeMarkers(); - uiObject.node = this.node.childNodes[0].childNodes[2].removeChild(uiObject.node); - } else { - uiObject.node = this.node.childNodes[0].childNodes[1].removeChild(uiObject.node); - this.nodes = this.nodes.without(uiObject); - } - } else if(uiObject instanceof ORYX.Core.Controls.Control) { - if (uiObject instanceof ORYX.Core.Controls.Docker) { - uiObject.node = this.node.childNodes[1].childNodes[0].removeChild(uiObject.node); - this.dockers = this.dockers.without(uiObject); - } else if (uiObject instanceof ORYX.Core.Controls.Magnet) { - uiObject.node = this.node.childNodes[1].childNodes[1].removeChild(uiObject.node); - this.magnets = this.magnets.without(uiObject); - } else { - uiObject.node = this.node.childNodes[1].removeChild(uiObject.node); - } - } + if (cx === undefined || cy === undefined || rx === undefined || ry === undefined) { + throw "ORYX.Core.Math.isPointInEllipse needs a ellipse with these properties: x, y, radiusX, radiusY" + } - if(this.eventHandlerCallback && silent !== true) - this.eventHandlerCallback({type: ORYX.CONFIG.EVENT_SHAPEREMOVED, shape: uiObject, parent: parent}); - - this._changed(); - //uiObject.bounds.unregisterCallback(this._changedCallback); - } else { + var tx = (pointX - cx) / rx; + var ty = (pointY - cy) / ry; - ORYX.Log.warn("remove: ORYX.Core.UIObject is not a child of this object."); - } - }, - - /** - * Calculate the Border Intersection Point between two points - * @param {PointA} - * @param {PointB} - */ - getIntersectionPoint: function() { - - var pointAX, pointAY, pointBX, pointBY; - - // Get the the two Points - switch(arguments.length) { - case 2: - pointAX = arguments[0].x; - pointAY = arguments[0].y; - pointBX = arguments[1].x; - pointBY = arguments[1].y; - break; - case 4: - pointAX = arguments[0]; - pointAY = arguments[1]; - pointBX = arguments[2]; - pointBY = arguments[3]; - break; - default: - throw "getIntersectionPoints needs two or four arguments"; - } - - - - // Defined an include and exclude point - var includePointX, includePointY, excludePointX, excludePointY; - - var bounds = this.absoluteBounds(); - - if(this.isPointIncluded(pointAX, pointAY, bounds)){ - includePointX = pointAX; - includePointY = pointAY; - } else { - excludePointX = pointAX; - excludePointY = pointAY; - } + return tx * tx + ty * ty < 1.0; +} - if(this.isPointIncluded(pointBX, pointBY, bounds)){ - includePointX = pointBX; - includePointY = pointBY; - } else { - excludePointX = pointBX; - excludePointY = pointBY; - } - - // If there is no inclue or exclude Shape, than return - if(!includePointX || !includePointY || !excludePointX || !excludePointY) { - return undefined; - } +/** + * Get a boolean if the point is in the polygone + * @param {int} pointX + * @param {int} pointY + * @param {[int]} Cornerpoints of the Polygone (x,y,x,y,...) + */ +ORYX.Core.Math.isPointInPolygone = function (pointX, pointY, polygone) { - var midPointX = 0; - var midPointY = 0; - - var refPointX, refPointY; - - var minDifferent = 1; - // Get the UpperLeft and LowerRight - //var ul = bounds.upperLeft(); - //var lr = bounds.lowerRight(); - - var i = 0; - - while(true) { - // Calculate the midpoint of the current to points - var midPointX = Math.min(includePointX, excludePointX) + ((Math.max(includePointX, excludePointX) - Math.min(includePointX, excludePointX)) / 2.0); - var midPointY = Math.min(includePointY, excludePointY) + ((Math.max(includePointY, excludePointY) - Math.min(includePointY, excludePointY)) / 2.0); - - - // Set the new midpoint by the means of the include of the bounds - if(this.isPointIncluded(midPointX, midPointY, bounds)){ - includePointX = midPointX; - includePointY = midPointY; - } else { - excludePointX = midPointX; - excludePointY = midPointY; - } - - // Calc the length of the line - var length = Math.sqrt(Math.pow(includePointX - excludePointX, 2) + Math.pow(includePointY - excludePointY, 2)) - // Calc a point one step from the include point - refPointX = includePointX + ((excludePointX - includePointX) / length), - refPointY = includePointY + ((excludePointY - includePointY) / length) - - - // If the reference point not in the bounds, break - if(!this.isPointIncluded(refPointX, refPointY, bounds)) { - break - } - - - } + if (arguments.length < 3) { + throw "ORYX.Core.Math.isPointInPolygone needs two arguments" + } - // Return the last includepoint - return {x:refPointX , y:refPointY}; - }, + var lastIndex = polygone.length - 1; - - - /** - * Calculate if the point is inside the Shape - * @param {PointX} - * @param {PointY} - */ - isPointIncluded: function(){ - return false - }, + if (polygone[0] !== polygone[lastIndex - 1] || polygone[1] !== polygone[lastIndex]) { + polygone.push(polygone[0]); + polygone.push(polygone[1]); + } - /** - * Returns TRUE if the given node - * is a child node of the shapes node - * @param {Element} node - * @return {Boolean} - * - */ - containsNode: function(node){ - var me = this.node.firstChild.firstChild; - while(node){ - if (node == me){ - return true; - } - node = node.parentNode; - } - return false - }, - - /** - * Calculate if the point is over an special offset area - * @param {Point} - */ - isPointOverOffset: function(){ - return this.isPointIncluded.apply( this , arguments ) - }, - - _dockerChanged: function() { + var crossings = 0; - }, - - /** - * Create a Docker for this Edge - * - */ - createDocker: function(index, position) { - var docker = new ORYX.Core.Controls.Docker({eventHandlerCallback: this.eventHandlerCallback}); - docker.bounds.registerCallback(this._dockerChangedCallback); - if (position) { - docker.bounds.centerMoveTo(position); - } - this.add(docker, index); - - return docker - }, + var x1, y1, x2, y2, d; - /** - * Get the serialized object - * return Array with hash-entrees (prefix, name, value) - * Following values will given: - * Bounds - * Outgoing Shapes - * Parent - */ - serialize: function() { - var serializedObject = arguments.callee.$.serialize.apply(this); + for (var i = 0; i < polygone.length - 3;) { + x1 = polygone[i]; + y1 = polygone[++i]; + x2 = polygone[++i]; + y2 = polygone[i + 1]; + d = (pointY - y1) * (x2 - x1) - (pointX - x1) * (y2 - y1); - // Add the bounds - serializedObject.push({name: 'bounds', prefix:'oryx', value: this.bounds.serializeForERDF(), type: 'literal'}); + if ((y1 >= pointY) != (y2 >= pointY)) { + crossings += y2 - y1 >= 0 ? d >= 0 : d <= 0; + } + if (!d && Math.min(x1, x2) <= pointX && pointX <= Math.max(x1, x2) + && Math.min(y1, y2) <= pointY && pointY <= Math.max(y1, y2)) { + return true; + } + } + return (crossings % 2) ? true : false; +} - // Add the outgoing shapes - this.getOutgoingShapes().each((function(followingShape){ - serializedObject.push({name: 'outgoing', prefix:'raziel', value: '#'+ERDF.__stripHashes(followingShape.resourceId), type: 'resource'}); - }).bind(this)); +/** + * Calculates the distance between a point and a line. It is also testable, if + * the distance orthogonal to the line, matches the segment of the line. + * + * @param {float} lineP1 + * The starting point of the line segment + * @param {float} lineP2 + * The end point of the line segment + * @param {Point} point + * The point to calculate the distance to. + * @param {boolean} toSegmentOnly + * Flag to signal if only the segment of the line shell be evaluated. + */ +ORYX.Core.Math.distancePointLinie = function ( + lineP1, + lineP2, + point, + toSegmentOnly) { + + var intersectionPoint = + ORYX.Core.Math.getPointOfIntersectionPointLine(lineP1, + lineP2, + point, + toSegmentOnly); + + if (!intersectionPoint) { + return null; + } - // Add the parent shape, if the parent not the canvas - //if(this.parent instanceof ORYX.Core.Shape){ - serializedObject.push({name: 'parent', prefix:'raziel', value: '#'+ERDF.__stripHashes(this.parent.resourceId), type: 'resource'}); - //} - - return serializedObject; - }, - - - deserialize: function(serialize, json){ - arguments.callee.$.deserialize.apply(this, arguments); - - // Set the Bounds - var bounds = serialize.find(function(ser){ return 'oryx-bounds' === (ser.prefix+"-"+ser.name) }); - if (bounds) { - var b = bounds.value.replace(/,/g, " ").split(" ").without(""); - if (this instanceof ORYX.Core.Edge) { - if (!this.dockers.first().isChanged) - this.dockers.first().bounds.centerMoveTo(parseFloat(b[0]), parseFloat(b[1])); - if (!this.dockers.last().isChanged) - this.dockers.last().bounds.centerMoveTo(parseFloat(b[2]), parseFloat(b[3])); - } else { - this.bounds.set(parseFloat(b[0]), parseFloat(b[1]), parseFloat(b[2]), parseFloat(b[3])); - } - } - - if (json && json.labels instanceof Array){ - json.labels.each(function(slabel){ - var label = this.getLabel(slabel.ref); - if (label){ - label.deserialize(slabel, this); - } - }.bind(this)) - } - }, - - toJSON: function(){ - var json = arguments.callee.$.toJSON.apply(this, arguments); - - var labels = [], id = this.id; - this._labels.each(function(obj){ - var slabel = obj.value.serialize(); - if (slabel){ - slabel.ref = obj.key.replace(id, ''); - labels.push(slabel); - } - }); - - if (labels.length > 0){ - json.labels = labels; - } - return json; - }, + return ORYX.Core.Math.getDistancePointToPoint(point, intersectionPoint); +}; - - /** - * Private methods. - */ +/** + * Calculates the distance between two points. + * + * @param {point} point1 + * @param {point} point2 + */ +ORYX.Core.Math.getDistancePointToPoint = function (point1, point2) { + return Math.sqrt(Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2)); +}; - /** - * Child classes have to overwrite this method for initializing a loaded - * SVG representation. - * @param {SVGDocument} svgDocument - */ - _init: function(svgDocument) { - //adjust ids - this._adjustIds(svgDocument, 0); - }, +/** + * Calculates the relative distance of a point which is between two other points. + * + * @param {point} between1 + * @param {point} between2 + * @param {point} point + */ +ORYX.Core.Math.getDistanceBetweenTwoPoints = function (between1, between2, point) { + return ORYX.Core.Math.getDistancePointToPoint(point, between1) / + ORYX.Core.Math.getDistancePointToPoint(between1, between2); +}; - _adjustIds: function(element, idIndex) { - if(element instanceof Element) { - var eid = element.getAttributeNS(null, 'id'); - if(eid && eid !== "") { - element.setAttributeNS(null, 'id', this.id + eid); - } else { - element.setAttributeNS(null, 'id', this.id + "_" + this.id + "_" + idIndex); - idIndex++; - } - - // Replace URL in fill attribute - var fill = element.getAttributeNS(null, 'fill'); - if (fill&&fill.include("url(#")){ - fill = fill.replace(/url\(#/g, 'url(#'+this.id); - element.setAttributeNS(null, 'fill', fill); - } - - if(element.hasChildNodes()) { - for(var i = 0; i < element.childNodes.length; i++) { - idIndex = this._adjustIds(element.childNodes[i], idIndex); - } - } - } - return idIndex; - }, - toString: function() { return "ORYX.Core.Shape " + this.getId() } -}; -ORYX.Core.Shape = ORYX.Core.AbstractShape.extend(ORYX.Core.Shape);/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved +/** + * Returns true, if the point is of the left hand + * side of the regarding the line. + * + * @param {point} lineP1 Line first point + * @param {point} lineP2 Line second point + * @param {point} point */ +ORYX.Core.Math.pointIsLeftOfLine = function (lineP1, lineP2, point) { + + var vec1 = ORYX.Core.Math.getVector(lineP1, lineP2); + var vec2 = ORYX.Core.Math.getVector(lineP1, point); + // if the cross produkt is more than 0 + return ((vec1.x * vec2.y) - (vec2.x * vec1.y)) > 0 +}; /** - * Init namespaces + * Calculates the a point which is relatively between two other points. + * + * @param {point} point1 + * @param {point} point2 + * @param {number} relative Relative which is between 0 and 1 */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} -if(!ORYX.Core.Controls) {ORYX.Core.Controls = {};} +ORYX.Core.Math.getPointBetweenTwoPoints = function (point1, point2, relative) { + relative = Math.max(Math.min(relative || 0, 1), 0); + + if (relative === 0) { + return point1; + } else if (relative === 1) { + return point2; + } + + return { + x: point1.x + ((point2.x - point1.x) * relative), + y: point1.y + ((point2.y - point1.y) * relative) + } +}; /** - * @classDescription Abstract base class for all Controls. - */ -ORYX.Core.Controls.Control = ORYX.Core.UIObject.extend({ - - toString: function() { return "Control " + this.id; } - });/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved + * Returns the vector of the both points + * + * @param {point} point1 + * @param {point} point2 */ +ORYX.Core.Math.getVector = function (point1, point2) { + return { + x: point2.x - point1.x, + y: point2.y - point1.y + } +} /** - * Init namespaces + * Returns the an identity vector of the given vector, + * which has the length ot one. + * + * @param {point} vector + * or + * @param {point} point1 + * @param {point} point2 */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} -if(!ORYX.Core.Controls) {ORYX.Core.Controls = {};} +ORYX.Core.Math.getIdentityVector = function (vector) { + if (arguments.length == 2) { + vector = ORYX.Core.Math.getVector(arguments[0], arguments[1]); + } -/** - * @classDescription Represents a movable docker that can be bound to a shape. Dockers are used - * for positioning shape objects. - * @extends {Control} - * - * TODO absoluteXY und absoluteCenterXY von einem Docker liefern falsche Werte!!! - */ -ORYX.Core.Controls.Docker = ORYX.Core.Controls.Control.extend({ - /** - * Constructor - */ - construct: function() { - arguments.callee.$.construct.apply(this, arguments); - - this.isMovable = true; // Enables movability - this.bounds.set(0, 0, 16, 16); // Set the bounds - this.referencePoint = undefined; // Refrenzpoint - this._dockedShapeBounds = undefined; - this._dockedShape = undefined; - this._oldRefPoint1 = undefined; - this._oldRefPoint2 = undefined; - - //this.anchors = []; - this.anchorLeft; - this.anchorRight; - this.anchorTop; - this.anchorBottom; - - this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", - null, - ['g']); - - // The DockerNode reprasentation - this._dockerNode = ORYX.Editor.graft("http://www.w3.org/2000/svg", - this.node, - ['g', {"pointer-events":"all"}, - ['circle', {cx:"8", cy:"8", r:"8", stroke:"none", fill:"none"}], - ['circle', {cx:"8", cy:"8", r:"3", stroke:"black", fill:"red", "stroke-width":"1"}] - ]); - - // The ReferenzNode reprasentation - this._referencePointNode = ORYX.Editor.graft("http://www.w3.org/2000/svg", - this.node, - ['g', {"pointer-events":"none"}, - ['circle', {cx: this.bounds.upperLeft().x, cy: this.bounds.upperLeft().y, r: 3, fill:"red", "fill-opacity":0.4}]]); - - // Hide the Docker - this.hide(); - - //Add to the EventHandler - this.addEventHandlers(this._dockerNode); - - // Buffer the Update Callback for un-/register on Event-Handler - this._updateCallback = this._changed.bind(this); - }, - - update: function() { - // If there have an DockedShape - if(this._dockedShape) { - if(this._dockedShapeBounds && this._dockedShape instanceof ORYX.Core.Node) { - // Calc the delta of width and height of the lastBounds and the current Bounds - var dswidth = this._dockedShapeBounds.width(); - var dsheight = this._dockedShapeBounds.height(); - if(!dswidth) - dswidth = 1; - if(!dsheight) - dsheight = 1; - var widthDelta = this._dockedShape.bounds.width() / dswidth; - var heightDelta = this._dockedShape.bounds.height() / dsheight; - - // If there is an different - if(widthDelta !== 1.0 || heightDelta !== 1.0) { - // Set the delta - this.referencePoint.x *= widthDelta; - this.referencePoint.y *= heightDelta; - } - - // Clone these bounds - this._dockedShapeBounds = this._dockedShape.bounds.clone(); - } - - // Get the first and the last Docker of the parent Shape - var dockerIndex = this.parent.dockers.indexOf(this) - var dock1 = this; - var dock2 = this.parent.dockers.length > 1 ? - (dockerIndex === 0? // If there is the first element - this.parent.dockers[dockerIndex + 1]: // then take the next docker - this.parent.dockers[dockerIndex - 1]): // if not, then take the docker before - undefined; - - // Calculate the first absolute Refenzpoint - var absoluteReferenzPoint1 = dock1.getDockedShape() ? - dock1.getAbsoluteReferencePoint() : - dock1.bounds.center(); - - // Calculate the last absolute Refenzpoint - var absoluteReferenzPoint2 = dock2 && dock2.getDockedShape() ? - dock2.getAbsoluteReferencePoint() : - dock2 ? - dock2.bounds.center() : - undefined; - - // If there is no last absolute Referenzpoint - if(!absoluteReferenzPoint2) { - // Calculate from the middle of the DockedShape - var center = this._dockedShape.absoluteCenterXY(); - var minDimension = this._dockedShape.bounds.width() * this._dockedShape.bounds.height(); - absoluteReferenzPoint2 = { - x: absoluteReferenzPoint1.x + (center.x - absoluteReferenzPoint1.x) * -minDimension, - y: absoluteReferenzPoint1.y + (center.y - absoluteReferenzPoint1.y) * -minDimension - } - } - - var newPoint = undefined; - - /*if (!this._oldRefPoint1 || !this._oldRefPoint2 || - absoluteReferenzPoint1.x !== this._oldRefPoint1.x || - absoluteReferenzPoint1.y !== this._oldRefPoint1.y || - absoluteReferenzPoint2.x !== this._oldRefPoint2.x || - absoluteReferenzPoint2.y !== this._oldRefPoint2.y) {*/ - - // Get the new point for the Docker, calucalted by the intersection point of the Shape and the two points - newPoint = this._dockedShape.getIntersectionPoint(absoluteReferenzPoint1, absoluteReferenzPoint2); - - // If there is new point, take the referencepoint as the new point - if(!newPoint) { - newPoint = this.getAbsoluteReferencePoint(); - } - - if(this.parent && this.parent.parent) { - var grandParentPos = this.parent.parent.absoluteXY(); - newPoint.x -= grandParentPos.x; - newPoint.y -= grandParentPos.y; - } - - // Set the bounds to the new point - this.bounds.centerMoveTo(newPoint) - - this._oldRefPoint1 = absoluteReferenzPoint1; - this._oldRefPoint2 = absoluteReferenzPoint2; - } - /*else { - newPoint = this.bounds.center(); - }*/ - - - // } - - // Call the super class - arguments.callee.$.update.apply(this, arguments); - }, + var length = Math.sqrt((vector.x * vector.x) + (vector.y * vector.y)) + return { + x: vector.x / (length || 1), + y: vector.y / (length || 1) + } +} - /** - * Calls the super class refresh method and updates the view of the docker. - */ - refresh: function() { - arguments.callee.$.refresh.apply(this, arguments); - - // Refresh the dockers node - var p = this.bounds.upperLeft(); - this._dockerNode.setAttributeNS(null, 'transform','translate(' + p.x + ', ' + p.y + ')'); - - // Refresh the referencepoints node - p = Object.clone(this.referencePoint); - - if(p && this._dockedShape){ - var upL - if(this.parent instanceof ORYX.Core.Edge) { - upL = this._dockedShape.absoluteXY(); - } else { - upL = this._dockedShape.bounds.upperLeft(); - } - p.x += upL.x; - p.y += upL.y; - } else { - p = this.bounds.center(); - } - this._referencePointNode.setAttributeNS(null, 'transform','translate(' + p.x + ', ' + p.y + ')'); - }, +ORYX.Core.Math.getOrthogonalIdentityVector = function (point1, point2) { + var vec = arguments.length == 1 ? point1 : ORYX.Core.Math.getIdentityVector(point1, point2); + return { + x: vec.y, + y: -vec.x + } +} - /** - * Set the reference point - * @param {Object} point - */ - setReferencePoint: function(point) { - // Set the referencepoint - if(this.referencePoint !== point && - (!this.referencePoint || - !point || - this.referencePoint.x !== point.x || - this.referencePoint.y !== point.y)) { - - this.referencePoint = point; - this._changed(); - } - - // Update directly, because the referencepoint has no influence of the bounds - //this.refresh(); - }, - - /** - * Get the absolute referencepoint - */ - getAbsoluteReferencePoint: function() { - if(!this.referencePoint || !this._dockedShape) { - return undefined; - } else { - var absUL = this._dockedShape.absoluteXY(); - return { - x: this.referencePoint.x + absUL.x, - y: this.referencePoint.y + absUL.y - } - } - }, - - /** - * Set the docked Shape from the docker - * @param {Object} shape +/** + * Returns the intersection point of a line and a point that defines a line + * orthogonal to the given line. + * + * @param {float} lineP1 + * The starting point of the line segment + * @param {float} lineP2 + * The end point of the line segment + * @param {Point} point + * The point to calculate the distance to. + * @param {boolean} onSegmentOnly + * Flag to signal if only the segment of the line shell be evaluated. + */ +ORYX.Core.Math.getPointOfIntersectionPointLine = function ( + lineP1, + lineP2, + point, + onSegmentOnly) { + + /* + * [P3 - P1 - u(P2 - P1)] dot (P2 - P1) = 0 + * u =((x3-x1)(x2-x1)+(y3-y1)(y2-y1))/(p2-p1)?? */ - setDockedShape: function(shape) { - - // If there is an old docked Shape - if(this._dockedShape) { - this._dockedShape.bounds.unregisterCallback(this._updateCallback) - - // Delete the Shapes from the incoming and outgoing array - // If this Docker the incoming of the Shape - if(this === this.parent.dockers.first()) { - - this.parent.incoming = this.parent.incoming.without(this._dockedShape); - this._dockedShape.outgoing = this._dockedShape.outgoing.without(this.parent); - - // If this Docker the outgoing of the Shape - } else if (this === this.parent.dockers.last()){ - - this.parent.outgoing = this.parent.outgoing.without(this._dockedShape); - this._dockedShape.incoming = this._dockedShape.incoming.without(this.parent); - - } - - } + var denominator = Math.pow(lineP2.x - lineP1.x, 2) + + Math.pow(lineP2.y - lineP1.y, 2); + if (denominator == 0) { + return undefined; + } - - // Set the new Shape - this._dockedShape = shape; - this._dockedShapeBounds = undefined; - var referencePoint = undefined; - - // If there is an Shape, register the updateCallback if there are changes in the shape bounds - if(this._dockedShape) { - - // Add the Shapes to the incoming and outgoing array - // If this Docker the incoming of the Shape - if(this === this.parent.dockers.first()) { - - this.parent.incoming.push(shape); - shape.outgoing.push(this.parent); - - // If this Docker the outgoing of the Shape - } else if (this === this.parent.dockers.last()){ - - this.parent.outgoing.push(shape); - shape.incoming.push(this.parent); - - } - - // Get the bounds and set the new referencepoint - var bounds = this.bounds; - var absUL = shape.absoluteXY(); - - /*if(shape.parent){ - var b = shape.parent.bounds.upperLeft(); - absUL.x -= b.x; - absUL.y -= b.y; - }*/ - - referencePoint = { - x: bounds.center().x - absUL.x, - y: bounds.center().y - absUL.y - } - - this._dockedShapeBounds = this._dockedShape.bounds.clone(); - - this._dockedShape.bounds.registerCallback(this._updateCallback); - - // Set the color of the docker as docked - this.setDockerColor(ORYX.CONFIG.DOCKER_DOCKED_COLOR); - } else { - // Set the color of the docker as undocked - this.setDockerColor(ORYX.CONFIG.DOCKER_UNDOCKED_COLOR); - } + var u = ((point.x - lineP1.x) * (lineP2.x - lineP1.x) + + (point.y - lineP1.y) * (lineP2.y - lineP1.y)) + / denominator; - // Set the referencepoint - this.setReferencePoint(referencePoint); - this._changed(); - //this.update(); - }, - - /** - * Get the docked Shape - */ - getDockedShape: function() { - return this._dockedShape; - }, + if (onSegmentOnly) { + if (!(0 <= u && u <= 1)) { + return undefined; + } + } - /** - * Returns TRUE if the docker has a docked shape - */ - isDocked: function() { - return !!this._dockedShape; - }, - - /** - * Set the Color of the Docker - * @param {Object} color - */ - setDockerColor: function(color) { - this._dockerNode.lastChild.setAttributeNS(null, "fill", color); - }, - - preventHiding: function(prevent){ - this._preventHiding = Math.max(0, (this._preventHiding||0) + (prevent ? 1 : -1)); - }, - - /** - * Hides this UIObject and all its children. - */ - hide: function() { - if (this._preventHiding){ - return false; - } - - // Hide docker and reference point - this.node.setAttributeNS(null, 'visibility', 'hidden'); - this._referencePointNode.setAttributeNS(null, 'visibility', 'hidden'); - - this.children.each(function(uiObj) { - uiObj.hide(); - }); - }, - - /** - * Enables visibility of this UIObject and all its children. - */ - show: function() { - // Show docker - this.node.setAttributeNS(null, 'visibility', 'visible'); - - // Hide reference point if the connected shape is an edge - if (this.getDockedShape() instanceof ORYX.Core.Edge){ - this._referencePointNode.setAttributeNS(null, 'visibility', 'hidden'); - } else { - this._referencePointNode.setAttributeNS(null, 'visibility', 'visible'); - } - - this.children.each(function(uiObj) { - uiObj.show(); - }); - }, - - toString: function() { return "Docker " + this.id } -});/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + pointOfIntersection = new Object(); + pointOfIntersection.x = lineP1.x + u * (lineP2.x - lineP1.x); + pointOfIntersection.y = lineP1.y + u * (lineP2.y - lineP1.y); + + return pointOfIntersection; +}; /** - * Init namespaces + * Translated the point with the given matrix. + * @param {Point} point + * @param {Matrix} matrix + * @return {Object} Includes x, y */ -if(!ORYX) {var ORYX = {};} -if(!ORYX.Core) {ORYX.Core = {};} -if(!ORYX.Core.Controls) {ORYX.Core.Controls = {};} +ORYX.Core.Math.getTranslatedPoint = function (point, matrix) { + var x = matrix.a * point.x + matrix.c * point.y + matrix.e * 1; + var y = matrix.b * point.x + matrix.d * point.y + matrix.f * 1; + return {x: x, y: y} +} /** - * @classDescription Represents a magnet that is part of another shape and can - * be attached to dockers. Magnets are used for linking edge objects - * to other Shape objects. - * @extends {Control} + * Returns the inverse matrix of the given SVG transformation matrix + * @param {SVGTransformationMatrix} matrix + * @return {Matrix} */ -ORYX.Core.Controls.Magnet = ORYX.Core.Controls.Control.extend({ - - /** - * Constructor - */ - construct: function() { - arguments.callee.$.construct.apply(this, arguments); - - //this.anchors = []; - this.anchorLeft; - this.anchorRight; - this.anchorTop; - this.anchorBottom; - - this.bounds.set(0, 0, 16, 16); - - //graft magnet's root node into owner's control group. - this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", - null, - ['g', {"pointer-events":"all"}, - ['circle', {cx:"8", cy:"8", r:"4", stroke:"none", fill:"red", "fill-opacity":"0.3"}], - ]); - - this.hide(); - }, - - update: function() { - arguments.callee.$.update.apply(this, arguments); - - //this.isChanged = true; - }, - - _update: function() { - arguments.callee.$.update.apply(this, arguments); - - //this.isChanged = true; - }, - - refresh: function() { - arguments.callee.$.refresh.apply(this, arguments); +ORYX.Core.Math.getInverseMatrix = function (matrix) { + + var det = ORYX.Core.Math.getDeterminant(matrix), m = matrix; + // +- -+ + // | a c e | + // | b d f | + // | 0 0 1 | + // +- -+ + return { + a: det * ((m.d * 1) - (m.f * 0)), + b: det * ((m.f * 0) - (m.b * 1)), + c: det * ((m.e * 0) - (m.c * 1)), + d: det * ((m.a * 1) - (m.e * 0)), + e: det * ((m.c * m.f) - (m.e * m.d)), + f: det * ((m.e * m.b) - (m.a * m.f)) + } +} - var p = this.bounds.upperLeft(); - /*if(this.parent) { - var parentPos = this.parent.bounds.upperLeft(); - p.x += parentPos.x; - p.y += parentPos.y; - }*/ - - this.node.setAttributeNS(null, 'transform','translate(' + p.x + ', ' + p.y + ')'); - }, - - show: function() { - //this.refresh(); - arguments.callee.$.show.apply(this, arguments); - }, - - toString: function() { - return "Magnet " + this.id; - } -}); -/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. +/** + * Returns the determinant of the svg transformation matrix + * @param {SVGTranformationMatrix} matrix + * @return {Number} + * */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved +ORYX.Core.Math.getDeterminant = function (m) { + // a11a22a33+a12a23a31+a13a21a32-a13a22a31-a12a21a33-a11a23a32 + return (m.a * m.d * 1) + (m.c * m.f * 0) + (m.e * m.b * 0) - (m.e * m.d * 0) - (m.c * m.b * 1) - (m.a * m.f * 0); +} + +/** + * Returns the bounding box of the given node. Translates the + * origin bounding box with the tranlation matrix. + * @param {SVGElement} node + * @return {Object} Includes x, y, width, height */ +ORYX.Core.Math.getTranslatedBoundingBox = function (node) { + var matrix = node.getCTM(); + var bb = node.getBBox(); + var ul = ORYX.Core.Math.getTranslatedPoint({x: bb.x, y: bb.y}, matrix); + var ll = ORYX.Core.Math.getTranslatedPoint({x: bb.x, y: bb.y + bb.height}, matrix); + var ur = ORYX.Core.Math.getTranslatedPoint({x: bb.x + bb.width, y: bb.y}, matrix); + var lr = ORYX.Core.Math.getTranslatedPoint({x: bb.x + bb.width, y: bb.y + bb.height}, matrix); + + var minPoint = { + x: Math.min(ul.x, ll.x, ur.x, lr.x), + y: Math.min(ul.y, ll.y, ur.y, lr.y) + } + var maxPoint = { + x: Math.max(ul.x, ll.x, ur.x, lr.x), + y: Math.max(ul.y, ll.y, ur.y, lr.y) + } + return { + x: minPoint.x, + y: minPoint.y, + width: maxPoint.x - minPoint.x, + height: maxPoint.y - minPoint.y + } +}; + /** - * Init namespaces + * Returns the angle of the given line, which is representated by the two points + * @param {Point} p1 + * @param {Point} p2 + * @return {Number} 0 <= x <= 359.99999 */ -if (!ORYX) { - var ORYX = {}; -} -if (!ORYX.Core) { - ORYX.Core = {}; -} +ORYX.Core.Math.getAngle = function (p1, p2) { + if (p1.x == p2.x && p1.y == p2.y) + return 0; + + var angle = Math.asin(Math.sqrt(Math.pow(p1.y - p2.y, 2)) + / (Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p1.y - p2.y, 2)))) + * 180 / Math.PI; + + if (p2.x >= p1.x && p2.y <= p1.y) + return angle; + else if (p2.x < p1.x && p2.y <= p1.y) + return 180 - angle; + else if (p2.x < p1.x && p2.y > p1.y) + return 180 + angle; + else + return 360 - angle; +}; + /** - * @classDescription Abstract base class for all Nodes. - * @extends ORYX.Core.Shape + * Implementation of the cohen-sutherland algorithm */ -ORYX.Core.Node = { +new function () { + + var RIGHT = 2, TOP = 8, BOTTOM = 4, LEFT = 1; + + function computeOutCode(x, y, xmin, ymin, xmax, ymax) { + var code = 0; + if (y > ymax) + code |= TOP; + else if (y < ymin) + code |= BOTTOM; + if (x > xmax) + code |= RIGHT; + else if (x < xmin) + code |= LEFT; + return code; + } /** - * Constructor - * @param options {Object} A container for arguments. - * @param stencil {Stencil} + * Returns TRUE if the rectangle is over the edge and has intersection points or includes it + * @param {Object} x1 Point A of the line + * @param {Object} y1 + * @param {Object} x2 Point B of the line + * @param {Object} y2 + * @param {Object} xmin Point A of the rectangle + * @param {Object} ymin + * @param {Object} xmax Point B of the rectangle + * @param {Object} ymax */ - construct: function(options, stencil, facade){ - arguments.callee.$.construct.apply(this, arguments); - - this.isSelectable = true; - this.isMovable = true; - this._dockerUpdated = false; - this.facade = facade; - - this._oldBounds = new ORYX.Core.Bounds(); //init bounds with undefined values - this._svgShapes = []; //array of all SVGShape objects of - // SVG representation - - //TODO vielleicht in shape verschieben? - this.minimumSize = undefined; // {width:..., height:...} - this.maximumSize = undefined; - - //TODO vielleicht in shape oder uiobject verschieben? - // vielleicht sogar isResizable ersetzen? - this.isHorizontallyResizable = false; - this.isVerticallyResizable = false; - - this.dataId = undefined; - - this._init(this._stencil.view()); - this.forcedHeight = -1; - }, - - /** - * This method checks whether the shape is resized correctly and calls the - * super class update method. - */ - _update: function(){ - - this.dockers.invoke("update"); - if (this.isChanged) { + ORYX.Core.Math.isRectOverLine = function (x1, y1, x2, y2, xmin, ymin, xmax, ymax) { + return !!ORYX.Core.Math.clipLineOnRect.apply(ORYX.Core.Math, arguments); + } - var bounds = this.bounds; - var oldBounds = this._oldBounds; - - if (this.isResized) { - - var widthDelta = bounds.width() / oldBounds.width(); - var heightDelta = bounds.height() / oldBounds.height(); - - //iterate over all relevant svg elements and resize them - this._svgShapes.each(function(svgShape){ - //adjust width - if (svgShape.isHorizontallyResizable) { - svgShape.width = svgShape.oldWidth * widthDelta; - } - //adjust height - if (svgShape.isVerticallyResizable) { - svgShape.height = svgShape.oldHeight * heightDelta; - } - - //check, if anchors are set - var anchorOffset; - var leftIncluded = svgShape.anchorLeft; - var rightIncluded = svgShape.anchorRight; - - if (rightIncluded) { - anchorOffset = oldBounds.width() - (svgShape.oldX + svgShape.oldWidth); - if (leftIncluded) { - svgShape.width = bounds.width() - svgShape.x - anchorOffset; - } - else { - svgShape.x = bounds.width() - (anchorOffset + svgShape.width); - } - } - else - if (!leftIncluded) { - svgShape.x = widthDelta * svgShape.oldX; - if (!svgShape.isHorizontallyResizable) { - svgShape.x = svgShape.x + svgShape.width * widthDelta / 2 - svgShape.width / 2; - } - } - - var topIncluded = svgShape.anchorTop; - var bottomIncluded = svgShape.anchorBottom; - - if (bottomIncluded) { - anchorOffset = oldBounds.height() - (svgShape.oldY + svgShape.oldHeight); - if (topIncluded) { - svgShape.height = bounds.height() - svgShape.y - anchorOffset; - } - else { - // Hack for choreography task layouting - if (!svgShape._isYLocked) { - svgShape.y = bounds.height() - (anchorOffset + svgShape.height); - } - } - } - else - if (!topIncluded) { - svgShape.y = heightDelta * svgShape.oldY; - if (!svgShape.isVerticallyResizable) { - svgShape.y = svgShape.y + svgShape.height * heightDelta / 2 - svgShape.height / 2; - } - } - }); - - //check, if the current bounds is unallowed horizontally or vertically resized - var p = { - x: 0, - y: 0 - }; - if (!this.isHorizontallyResizable && bounds.width() !== oldBounds.width()) { - p.x = oldBounds.width() - bounds.width(); - } - if (!this.isVerticallyResizable && bounds.height() !== oldBounds.height()) { - p.y = oldBounds.height() - bounds.height(); - } - if (p.x !== 0 || p.y !== 0) { - bounds.extend(p); - } - - //check, if the current bounds are between maximum and minimum bounds - p = { - x: 0, - y: 0 - }; - var widthDifference, heightDifference; - if (this.minimumSize) { - - ORYX.Log.debug("Shape (%0)'s min size: (%1x%2)", this, this.minimumSize.width, this.minimumSize.height); - widthDifference = this.minimumSize.width - bounds.width(); - if (widthDifference > 0) { - p.x += widthDifference; - } - heightDifference = this.minimumSize.height - bounds.height(); - if (heightDifference > 0) { - p.y += heightDifference; - } - } - if (this.maximumSize) { - - ORYX.Log.debug("Shape (%0)'s max size: (%1x%2)", this, this.maximumSize.width, this.maximumSize.height); - widthDifference = bounds.width() - this.maximumSize.width; - if (widthDifference > 0) { - p.x -= widthDifference; - } - heightDifference = bounds.height() - this.maximumSize.height; - if (heightDifference > 0) { - p.y -= heightDifference; - } - } - if (p.x !== 0 || p.y !== 0) { - bounds.extend(p); - } - - //update magnets - - var widthDelta = bounds.width() / oldBounds.width(); - var heightDelta = bounds.height() / oldBounds.height(); - - var leftIncluded, rightIncluded, topIncluded, bottomIncluded, center, newX, newY; - - this.magnets.each(function(magnet){ - leftIncluded = magnet.anchorLeft; - rightIncluded = magnet.anchorRight; - topIncluded = magnet.anchorTop; - bottomIncluded = magnet.anchorBottom; - - center = magnet.bounds.center(); - - if (leftIncluded) { - newX = center.x; - } - else - if (rightIncluded) { - newX = bounds.width() - (oldBounds.width() - center.x) - } - else { - newX = center.x * widthDelta; - } - - if (topIncluded) { - newY = center.y; - } - else - if (bottomIncluded) { - newY = bounds.height() - (oldBounds.height() - center.y); - } - else { - newY = center.y * heightDelta; - } - - if (center.x !== newX || center.y !== newY) { - magnet.bounds.centerMoveTo(newX, newY); - } - }); - - //set new position of labels - this.getLabels().each(function(label){ - // Set the position dependings on it anchor - if (!label.isAnchorLeft()) { - if (label.isAnchorRight()) { - label.setX(bounds.width() - (oldBounds.width() - label.oldX)) - } else { - label.setX((label.position?label.position.x:label.x) * widthDelta); - } - } - if (!label.isAnchorTop()) { - if (label.isAnchorBottom()) { - label.setY(bounds.height() - (oldBounds.height() - label.oldY)); - } else { - label.setY((label.position?label.position.y:label.y) * heightDelta); - } - } - - // If there is an position, - // set the origin position as well - if (label.position){ - if (!label.isOriginAnchorLeft()) { - if (label.isOriginAnchorRight()) { - label.setOriginX(bounds.width() - (oldBounds.width() - label.oldX)) - } else { - label.setOriginX(label.x * widthDelta); - } - } - if (!label.isOriginAnchorTop()) { - if (label.isOriginAnchorBottom()) { - label.setOriginY(bounds.height() - (oldBounds.height() - label.oldY)); - } else { - label.setOriginY(label.y * heightDelta); - } - } - } - }); - - //update docker - var docker = this.dockers[0]; - if (docker) { - docker.bounds.unregisterCallback(this._dockerChangedCallback); - if (!this._dockerUpdated) { - docker.bounds.centerMoveTo(this.bounds.center()); - this._dockerUpdated = false; - } - - docker.update(); - docker.bounds.registerCallback(this._dockerChangedCallback); - } - this.isResized = false; - } - - this.refresh(); - - this.isChanged = false; - - this._oldBounds = this.bounds.clone(); - } - - this.children.each(function(value) { - if(!(value instanceof ORYX.Core.Controls.Docker)) { - value._update(); - } - }); - - if (this.dockers.length > 0&&!this.dockers.first().getDockedShape()) { - this.dockers.each(function(docker){ - docker.bounds.centerMoveTo(this.bounds.center()) - }.bind(this)) - } - - /*this.incoming.each((function(edge) { - if(!(this.dockers[0] && this.dockers[0].getDockedShape() instanceof ORYX.Core.Node)) - edge._update(true); - }).bind(this)); - - this.outgoing.each((function(edge) { - if(!(this.dockers[0] && this.dockers[0].getDockedShape() instanceof ORYX.Core.Node)) - edge._update(true); - }).bind(this)); */ - }, - - /** - * This method repositions and resizes the SVG representation - * of the shape. - */ - refresh: function(){ - arguments.callee.$.refresh.apply(this, arguments); - - /** Movement */ - var x = this.bounds.upperLeft().x; - var y = this.bounds.upperLeft().y; - - // Move owner element - this.node.firstChild.setAttributeNS(null, "transform", "translate(" + x + ", " + y + ")"); - // Move magnets - this.node.childNodes[1].childNodes[1].setAttributeNS(null, "transform", "translate(" + x + ", " + y + ")"); - - /** Resize */ - - //iterate over all relevant svg elements and update them - this._svgShapes.each(function(svgShape){ - svgShape.update(); - }); - }, - - _dockerChanged: function(){ - var docker = this.dockers[0]; - - //set the bounds of the the association - this.bounds.centerMoveTo(docker.bounds.center()); - - this._dockerUpdated = true; - //this._update(true); - }, - /** - * This method traverses a tree of SVGElements and returns - * all SVGShape objects. For each basic shape or path element - * a SVGShape object is initialized. + * Returns the clipped line on the given rectangle. If there is + * no intersection, it will return NULL. * - * @param svgNode {SVGElement} - * @return {Array} Array of SVGShape objects + * @param {Object} x1 Point A of the line + * @param {Object} y1 + * @param {Object} x2 Point B of the line + * @param {Object} y2 + * @param {Object} xmin Point A of the rectangle + * @param {Object} ymin + * @param {Object} xmax Point B of the rectangle + * @param {Object} ymax */ - _initSVGShapes: function(svgNode){ - var svgShapes = []; - try { - var svgShape = new ORYX.Core.SVG.SVGShape(svgNode); - svgShapes.push(svgShape); - } - catch (e) { - //do nothing - } - - if (svgNode.hasChildNodes()) { - for (var i = 0; i < svgNode.childNodes.length; i++) { - svgShapes = svgShapes.concat(this._initSVGShapes(svgNode.childNodes[i])); + ORYX.Core.Math.clipLineOnRect = function (x1, y1, x2, y2, xmin, ymin, xmax, ymax) { + //Outcodes for P0, P1, and whatever point lies outside the clip rectangle + var outcode0, outcode1, outcodeOut, hhh = 0; + var accept = false, done = false; + + //compute outcodes + outcode0 = computeOutCode(x1, y1, xmin, ymin, xmax, ymax); + outcode1 = computeOutCode(x2, y2, xmin, ymin, xmax, ymax); + + do { + if ((outcode0 | outcode1) == 0) { + accept = true; + done = true; + } else if ((outcode0 & outcode1) > 0) { + done = true; + } else { + //failed both tests, so calculate the line segment to clip + //from an outside point to an intersection with clip edge + var x = 0, y = 0; + //At least one endpoint is outside the clip rectangle; pick it. + outcodeOut = outcode0 != 0 ? outcode0 : outcode1; + //Now find the intersection point; + //use formulas y = y0 + slope * (x - x0), x = x0 + (1/slope)* (y - y0) + if ((outcodeOut & TOP) > 0) { + x = x1 + (x2 - x1) * (ymax - y1) / (y2 - y1); + y = ymax; + } else if ((outcodeOut & BOTTOM) > 0) { + x = x1 + (x2 - x1) * (ymin - y1) / (y2 - y1); + y = ymin; + } else if ((outcodeOut & RIGHT) > 0) { + y = y1 + (y2 - y1) * (xmax - x1) / (x2 - x1); + x = xmax; + } else if ((outcodeOut & LEFT) > 0) { + y = y1 + (y2 - y1) * (xmin - x1) / (x2 - x1); + x = xmin; + } + + //Now we move outside point to intersection point to clip + //and get ready for next pass. + if (outcodeOut == outcode0) { + x1 = x; + y1 = y; + outcode0 = computeOutCode(x1, y1, xmin, ymin, xmax, ymax); + } else { + x2 = x; + y2 = y; + outcode1 = computeOutCode(x2, y2, xmin, ymin, xmax, ymax); + } } + hhh++; + } while (done != true && hhh < 5000); + + if (accept) { + return {a: {x: x1, y: y1}, b: {x: x2, y: y2}}; } - - return svgShapes; - }, - - /** - * Calculate if the point is inside the Shape - * @param {PointX} - * @param {PointY} - * @param {absoluteBounds} optional: for performance - */ - isPointIncluded: function(pointX, pointY, absoluteBounds){ - // If there is an arguments with the absoluteBounds - var absBounds = absoluteBounds && absoluteBounds instanceof ORYX.Core.Bounds ? absoluteBounds : this.absoluteBounds(); - - if (!absBounds.isIncluded(pointX, pointY)) { - return false; - } else { - - } - - - //point = Object.clone(point); - var ul = absBounds.upperLeft(); - var x = pointX - ul.x; - var y = pointY - ul.y; - - var i=0; - do { - var isPointIncluded = this._svgShapes[i++].isPointIncluded( x, y ); - } while( !isPointIncluded && i < this._svgShapes.length) - - return isPointIncluded; + return null; + } +}(); + + +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespace + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} +if (!ORYX.Core.StencilSet) { + ORYX.Core.StencilSet = {}; +} + +/** + * Class Stencil + * uses Prototpye 1.5.0 + * uses Inheritance + * + * This class represents one stencil of a stencil set. + */ +ORYX.Core.StencilSet.Stencil = { - /*return this._svgShapes.any(function(svgShape){ - return svgShape.isPointIncluded(point); - });*/ - }, - - /** - * Calculate if the point is over an special offset area - * @param {Point} + * Constructor */ - isPointOverOffset: function( pointX, pointY ){ - var isOverEl = arguments.callee.$.isPointOverOffset.apply( this , arguments ); - - if (isOverEl) { - - // If there is an arguments with the absoluteBounds - var absBounds = this.absoluteBounds(); - absBounds.widen( - ORYX.CONFIG.BORDER_OFFSET ); - - if ( !absBounds.isIncluded( pointX, pointY )) { - return true; - } - } - - return false; - - }, - - serialize: function(){ - var result = arguments.callee.$.serialize.apply(this); - - // Add the docker's bounds - // nodes only have at most one docker! - this.dockers.each((function(docker){ - if (docker.getDockedShape()) { - var center = docker.referencePoint; - center = center ? center : docker.bounds.center(); - result.push({ - name: 'docker', - prefix: 'oryx', - value: $H(center).values().join(','), - type: 'literal' - }); - } + construct: function (jsonStencil, namespace, source, stencilSet, propertyPackages, defaultPosition) { + arguments.callee.$.construct.apply(this, arguments); // super(); + + // check arguments and set defaults. + if (!jsonStencil) throw "Stencilset seems corrupt."; + if (!namespace) throw "Stencil does not provide namespace."; + if (!source) throw "Stencil does not provide SVG source."; + if (!stencilSet) throw "Fatal internal error loading stencilset."; + //if(!propertyPackages) throw "Fatal internal error loading stencilset."; + + this._source = source; + this._jsonStencil = jsonStencil; + this._stencilSet = stencilSet; + this._namespace = namespace; + this._propertyPackages = propertyPackages; + + if (defaultPosition && !this._jsonStencil.position) + this._jsonStencil.position = defaultPosition; + + this._view; + this._properties = new Hash(); + + // check stencil consistency and set defaults. + /*with(this._jsonStencil) { + + if(!type) throw "Stencil does not provide type."; + if((type != "edge") && (type != "node")) + throw "Stencil type must be 'edge' or 'node'."; + if(!id || id == "") throw "Stencil does not provide valid id."; + if(!title || title == "") + throw "Stencil does not provide title"; + if(!description) { description = ""; }; + if(!groups) { groups = []; } + if(!roles) { roles = []; } + + // add id of stencil to its roles + roles.push(id); + }*/ + + //init all JSON values + if (!this._jsonStencil.type || !(this._jsonStencil.type === "edge" || this._jsonStencil.type === "node")) { + throw "ORYX.Core.StencilSet.Stencil(construct): Type is not defined."; + } + if (!this._jsonStencil.id || this._jsonStencil.id === "") { + throw "ORYX.Core.StencilSet.Stencil(construct): Id is not defined."; + } + if (!this._jsonStencil.title || this._jsonStencil.title === "") { + throw "ORYX.Core.StencilSet.Stencil(construct): Title is not defined."; + } + + if (!this._jsonStencil.description) { + this._jsonStencil.description = ""; + } + ; + if (!this._jsonStencil.groups) { + this._jsonStencil.groups = []; + } + if (!this._jsonStencil.roles) { + this._jsonStencil.roles = []; + } + + //add id of stencil to its roles + this._jsonStencil.roles.push(this._jsonStencil.id); + + //prepend namespace to each role + this._jsonStencil.roles.each((function (role, index) { + this._jsonStencil.roles[index] = namespace + role; }).bind(this)); - - // Get the spezific serialized object from the stencil - try { - //result = this.getStencil().serialize(this, result); - var serializeEvent = this.getStencil().serialize(); - - /* - * call serialize callback by reference, result should be found - * in serializeEvent.result - */ - if(serializeEvent.type) { - serializeEvent.shape = this; - serializeEvent.data = result; - serializeEvent.result = undefined; - serializeEvent.forceExecution = true; - - this._delegateEvent(serializeEvent); - - if(serializeEvent.result) { - result = serializeEvent.result; - } - } - } - catch (e) { + //delete duplicate roles + this._jsonStencil.roles = this._jsonStencil.roles.uniq(); + + //make id unique by prepending namespace of stencil set + this._jsonStencil.id = namespace + this._jsonStencil.id; + + this.postProcessProperties(); + + // init serialize callback + if (!this._jsonStencil.serialize) { + this._jsonStencil.serialize = {}; + //this._jsonStencil.serialize = function(shape, data) { return data;}; } - return result; - }, - - deserialize: function(data) { - arguments.callee.$.deserialize.apply(this, arguments); - - try { - //data = this.getStencil().deserialize(this, data); - var deserializeEvent = this.getStencil().deserialize(); - - /* - * call serialize callback by reference, result should be found - * in serializeEventInfo.result - */ - if(deserializeEvent.type) { - deserializeEvent.shape = this; - deserializeEvent.data = data; - deserializeEvent.result = undefined; - deserializeEvent.forceExecution = true; - - this._delegateEvent(deserializeEvent); - if(deserializeEvent.result) { - data = deserializeEvent.result; - } - } - } - catch (e) { - } - - // Set the outgoing shapes - var outgoing = data.findAll(function(ser){ return (ser.prefix+"-"+ser.name) == 'raziel-outgoing'}); - outgoing.each((function(obj){ - // TODO: Look at Canvas - if(!this.parent) {return}; - - // Set outgoing Shape - var next = this.getCanvas().getChildShapeByResourceId(obj.value); - - if(next){ - if(next instanceof ORYX.Core.Edge) { - //Set the first docker of the next shape - next.dockers.first().setDockedShape(this); - next.dockers.first().setReferencePoint(next.dockers.first().bounds.center()); - } else if(next.dockers.length > 0) { //next is a node and next has a docker - next.dockers.first().setDockedShape(this); - //next.dockers.first().setReferencePoint({x: this.bounds.width() / 2.0, y: this.bounds.height() / 2.0}); - } - } - - }).bind(this)); - - if (this.dockers.length === 1) { - var dockerPos; - dockerPos = data.find(function(entry){ - return (entry.prefix + "-" + entry.name === "oryx-dockers"); - }); - - if (dockerPos) { - var points = dockerPos.value.replace(/,/g, " ").split(" ").without("").without("#"); - if (points.length === 2 && this.dockers[0].getDockedShape()) { - this.dockers[0].setReferencePoint({ - x: parseFloat(points[0]), - y: parseFloat(points[1]) - }); - } - else { - this.dockers[0].bounds.centerMoveTo(parseFloat(points[0]), parseFloat(points[1])); - } + // init deserialize callback + if (!this._jsonStencil.deserialize) { + this._jsonStencil.deserialize = {}; + //this._jsonStencil.deserialize = function(shape, data) { return data;}; + } + + // init layout callback + if (!this._jsonStencil.layout) { + this._jsonStencil.layout = [] + //this._jsonStencil.layout = function() {return true;} + } + + //TODO does not work correctly, if the url does not exist + //How to guarantee that the view is loaded correctly before leaving the constructor??? + var url = source + "view/" + jsonStencil.view; + // override content type when this is webkit. + + if (this._jsonStencil.view.trim().match(/ 0); + }, + + getRepositoryEntries: function () { + return (this._jsonStencil.repositoryEntries) ? + $A(this._jsonStencil.repositoryEntries) : $A([]); + }, + + properties: function () { + return this._properties.values(); + }, + + property: function (id) { + return this._properties[id]; + }, + + roles: function () { + return this._jsonStencil.roles; + }, + + defaultAlign: function () { + if (!this._jsonStencil.defaultAlign) + return "east"; + return this._jsonStencil.defaultAlign; + }, + + serialize: function (shape, data) { + return this._jsonStencil.serialize; + //return this._jsonStencil.serialize(shape, data); + }, + + deserialize: function (shape, data) { + return this._jsonStencil.deserialize; + //return this._jsonStencil.deserialize(shape, data); + }, + + // in which case is targetShape used? +// layout: function(shape, targetShape) { +// return this._jsonStencil.layout(shape, targetShape); +// }, + // layout property to store events for layouting in plugins + layout: function (shape) { + return this._jsonStencil.layout + }, + + addProperty: function (property, namespace) { + if (property && namespace) { + var oProp = new ORYX.Core.StencilSet.Property(property, namespace, this); + this._properties[oProp.prefix() + "-" + oProp.id()] = oProp; + } + }, + + removeProperty: function (propertyId) { + if (propertyId) { + var oProp = this._properties.values().find(function (prop) { + return (propertyId == prop.id()); + }); + if (oProp) + delete this._properties[oProp.prefix() + "-" + oProp.id()]; + } + }, + + _loadSVGOnSuccess: function (result) { + + var xml = null; + + /* + * We want to get a dom object for the requested file. Unfortunately, + * safari has some issues here. this is meant as a fallback for all + * browsers that don't recognize the svg mimetype as XML but support + * data: urls on Ajax calls. + */ + + // responseXML != undefined. + // if(!(result.responseXML)) + + // get the dom by data: url. + // xml = _evenMoreEvilHack(result.responseText, 'text/xml'); + + // else + + // get it the usual way. + xml = result.responseXML; + + //check if result is a SVG document + if (ORYX.Editor.checkClassType(xml.documentElement, SVGSVGElement)) { + + this._view = xml.documentElement; + + } else { + throw "ORYX.Core.StencilSet.Stencil(_loadSVGOnSuccess): The response is not a SVG document." + } + }, + + _loadSVGOnFailure: function (result) { + throw "ORYX.Core.StencilSet.Stencil(_loadSVGOnFailure): Loading SVG document failed." + }, + + toString: function () { + return "Stencil " + this.title() + " (" + this.id() + ")"; + } +}; + +ORYX.Core.StencilSet.Stencil = Clazz.extend(ORYX.Core.StencilSet.Stencil); + +/** + * Transform a string into an xml document, the Safari way, as long as + * the nightlies are broken. Even more evil version. + * @param {Object} str + * @param {Object} contentType + */ +function _evenMoreEvilHack(str, contentType) { + + /* + * This even more evil hack was taken from + * http://web-graphics.com/mtarchive/001606.php#chatty004999 + */ + + if (window.ActiveXObject) { + var d = new ActiveXObject("MSXML.DomDocument"); + d.loadXML(str); + return d; + } else if (window.XMLHttpRequest) { + var req = new XMLHttpRequest; + req.open("GET", "data:" + (contentType || "application/xml") + + ";charset=utf-8," + encodeURIComponent(str), false); + if (req.overrideMimeType) { + req.overrideMimeType(contentType); + } + req.send(null); + return req.responseXML; + } +} + +/** + * Transform a string into an xml document, the Safari way, as long as + * the nightlies are broken. + * @param {Object} result the xml document object. + */ +function _evilSafariHack(serializedXML) { + + /* + * The Dave way. Taken from: + * http://web-graphics.com/mtarchive/001606.php + * + * There is another possibility to parse XML in Safari, by implementing + * the DOMParser in javascript. However, in the latest nightlies of + * WebKit, DOMParser is already available, but still buggy. So, this is + * the best compromise for the time being. + */ + + var xml = serializedXML; + var url = "data:text/xml;charset=utf-8," + encodeURIComponent(xml); + var dom = null; + + // your standard AJAX stuff + var req = new XMLHttpRequest(); + req.open("GET", url); + req.onload = function () { + dom = req.responseXML; + } + req.send(null); + + return dom; +} + +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespace + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} +if (!ORYX.Core.StencilSet) { + ORYX.Core.StencilSet = {}; +} + +/** + * Class Property + * uses Prototpye 1.5.0 + * uses Inheritance + */ +ORYX.Core.StencilSet.Property = Clazz.extend({ + + /** + * Constructor + */ + construct: function (jsonProp, namespace, stencil) { + arguments.callee.$.construct.apply(this, arguments); + + this._jsonProp = jsonProp || ORYX.Log.error("Parameter jsonProp is not defined."); + this._namespace = namespace || ORYX.Log.error("Parameter namespace is not defined."); + this._stencil = stencil || ORYX.Log.error("Parameter stencil is not defined."); + + this._items = {}; + this._complexItems = {}; + + // Flag to indicate whether or not the property should be hidden + // This can be for example when the stencil set is upgraded, but the model + // has a value for that specific property filled in which we still want to show. + // If the value is missing, the property can simply be not shown. + this._hidden = false; + + jsonProp.id = jsonProp.id || ORYX.Log.error("ORYX.Core.StencilSet.Property(construct): Id is not defined."); + jsonProp.id = jsonProp.id.toLowerCase(); + + if (!jsonProp.type) { + ORYX.Log.info("Type is not defined for stencil '%0', id '%1'. Falling back to 'String'.", stencil, jsonProp.id); + jsonProp.type = "string"; + } else { + jsonProp.type = jsonProp.type.toLowerCase(); + } + + jsonProp.prefix = jsonProp.prefix || "oryx"; + jsonProp.title = jsonProp.title || ""; + jsonProp.value = jsonProp.value || ""; + jsonProp.description = jsonProp.description || ""; + jsonProp.readonly = jsonProp.readonly || false; + jsonProp.optional = jsonProp.optional !== false; + + //init refToView + if (this._jsonProp.refToView) { + if (!(this._jsonProp.refToView instanceof Array)) { + this._jsonProp.refToView = [this._jsonProp.refToView]; + } + } else { + this._jsonProp.refToView = []; + } + + var globalMin = this.getMinForType(jsonProp.type); + if (jsonProp.min === undefined || jsonProp.min === null) { + jsonProp.min = globalMin; + } else if (jsonProp.min < globalMin) { + jsonProp.min = globalMin; + } + + var globalMax = this.getMaxForType(jsonProp.type); + if (jsonProp.max === undefined || jsonProp.max === null) { + jsonProp.max = globalMax; + } else if (jsonProp.max > globalMax) { + jsonProp.min = globalMax; + } + + if (!jsonProp.fillOpacity) { + jsonProp.fillOpacity = false; + } + + if ("number" != typeof jsonProp.lightness) { + jsonProp.lightness = 1; + } else { + jsonProp.lightness = Math.max(0, Math.min(1, jsonProp.lightness)); + } + + if (!jsonProp.strokeOpacity) { + jsonProp.strokeOpacity = false; + } + + if (jsonProp.length === undefined || jsonProp.length === null) { + jsonProp.length = Number.MAX_VALUE; + } + + if (!jsonProp.wrapLines) { + jsonProp.wrapLines = false; + } + + if (!jsonProp.dateFormat) { + jsonProp.dateFormat = ORYX.I18N.PropertyWindow.dateFormat || "m/d/y"; + } + + if (!jsonProp.fill) { + jsonProp.fill = false; + } + + if (!jsonProp.stroke) { + jsonProp.stroke = false; + } + + if (!jsonProp.inverseBoolean) { + jsonProp.inverseBoolean = false; + } + + if (!jsonProp.directlyEditable && jsonProp.directlyEditable != false) { + jsonProp.directlyEditable = true; + } + + if (jsonProp.visible !== false) { + jsonProp.visible = true; + } + + if (jsonProp.isList !== true) { + jsonProp.isList = false; + + if (!jsonProp.list || !(jsonProp.list instanceof Array)) { + jsonProp.list = []; + } + } + + if (!jsonProp.category) { + if (jsonProp.popular) { + jsonProp.category = "popular"; + } else { + jsonProp.category = "others"; + } + } + + if (!jsonProp.alwaysAppearInMultiselect) { + jsonProp.alwaysAppearInMultiselect = false; + } + + if (jsonProp.type === ORYX.CONFIG.TYPE_CHOICE) { + if (jsonProp.items && jsonProp.items instanceof Array) { + jsonProp.items.each((function (jsonitem) { + // why is the item's value used as the key??? + this._items[jsonItem.value.toLowerCase()] = new ORYX.Core.StencilSet.PropertyItem(jsonItem, namespace, this); + }).bind(this)); + } else { + throw "ORYX.Core.StencilSet.Property(construct): No property items defined." + } + // extended by Kerstin (start) + } else if (jsonProp.type === ORYX.CONFIG.TYPE_COMPLEX || jsonProp.type == ORYX.CONFIG.TYPE_MULTIPLECOMPLEX) { + if (jsonProp.complexItems && jsonProp.complexItems instanceof Array) { + jsonProp.complexItems.each((function (jsonComplexitem) { + this._complexItems[jsonComplexItem.id.toLowerCase()] = new ORYX.Core.StencilSet.ComplexPropertyItem(jsonComplexItem, namespace, this); + }).bind(this)); + } + } + // extended by Kerstin (end) + }, + + getMinForType: function (type) { + if (type.toLowerCase() == ORYX.CONFIG.TYPE_INTEGER) { + return -Math.pow(2, 31) + } else { + return -Number.MAX_VALUE + 1; + } + }, + getMaxForType: function (type) { + if (type.toLowerCase() == ORYX.CONFIG.TYPE_INTEGER) { + return Math.pow(2, 31) - 1 + } else { + return Number.MAX_VALUE; + } + }, + + /** + * @param {ORYX.Core.StencilSet.Property} property + * @return {Boolean} True, if property has the same namespace and id. + */ + equals: function (property) { + return (this._namespace === property.namespace() && + this.id() === property.id()) ? true : false; + }, + + namespace: function () { + return this._namespace; + }, + + stencil: function () { + return this._stencil; + }, + + id: function () { + return this._jsonProp.id; + }, + + prefix: function () { + return this._jsonProp.prefix; + }, + + type: function () { + return this._jsonProp.type; + }, + + inverseBoolean: function () { + return this._jsonProp.inverseBoolean; + }, + + category: function () { + return this._jsonProp.category; + }, + + setCategory: function (value) { + this._jsonProp.category = value; + }, + + directlyEditable: function () { + return this._jsonProp.directlyEditable; + }, + + visible: function () { + return this._jsonProp.visible; + }, + + title: function () { + return ORYX.Core.StencilSet.getTranslation(this._jsonProp, "title"); + }, + + value: function () { + return this._jsonProp.value; + }, + + readonly: function () { + return this._jsonProp.readonly; + }, + + optional: function () { + return this._jsonProp.optional; + }, + + description: function () { + return ORYX.Core.StencilSet.getTranslation(this._jsonProp, "description"); + }, + + /** + * An optional link to a SVG element so that the property affects the + * graphical representation of the stencil. + */ + refToView: function () { + return this._jsonProp.refToView; + }, + + /** + * If type is integer or float, min is the lower bounds of value. + */ + min: function () { + return this._jsonProp.min; + }, + + /** + * If type ist integer or float, max is the upper bounds of value. + */ + max: function () { + return this._jsonProp.max; + }, + + /** + * If type is float, this method returns if the fill-opacity property should + * be set. + * @return {Boolean} + */ + fillOpacity: function () { + return this._jsonProp.fillOpacity; + }, + + /** + * If type is float, this method returns if the stroke-opacity property should + * be set. + * @return {Boolean} + */ + strokeOpacity: function () { + return this._jsonProp.strokeOpacity; + }, + + /** + * If type is string or richtext, length is the maximum length of the text. + * TODO how long can a string be. + */ + length: function () { + return this._jsonProp.length ? this._jsonProp.length : Number.MAX_VALUE; + }, + + wrapLines: function () { + return this._jsonProp.wrapLines; + }, + + /** + * If type is date, dateFormat specifies the format of the date. The format + * specification of the ext library is used: + * + * Format Output Description + * ------ ---------- -------------------------------------------------------------- + * d 10 Day of the month, 2 digits with leading zeros + * D Wed A textual representation of a day, three letters + * j 10 Day of the month without leading zeros + * l Wednesday A full textual representation of the day of the week + * S th English ordinal day of month suffix, 2 chars (use with j) + * w 3 Numeric representation of the day of the week + * z 9 The julian date, or day of the year (0-365) + * W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52) + * F January A full textual representation of the month + * m 01 Numeric representation of a month, with leading zeros + * M Jan Month name abbreviation, three letters + * n 1 Numeric representation of a month, without leading zeros + * t 31 Number of days in the given month + * L 0 Whether its a leap year (1 if it is a leap year, else 0) + * Y 2007 A full numeric representation of a year, 4 digits + * y 07 A two digit representation of a year + * a pm Lowercase Ante meridiem and Post meridiem + * A PM Uppercase Ante meridiem and Post meridiem + * g 3 12-hour format of an hour without leading zeros + * G 15 24-hour format of an hour without leading zeros + * h 03 12-hour format of an hour with leading zeros + * H 15 24-hour format of an hour with leading zeros + * i 05 Minutes with leading zeros + * s 01 Seconds, with leading zeros + * O -0600 Difference to Greenwich time (GMT) in hours + * T CST Timezone setting of the machine running the code + * Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east) + * + * Example: + * F j, Y, g:i a -> January 10, 2007, 3:05 pm + */ + dateFormat: function () { + return this._jsonProp.dateFormat; + }, + + /** + * If type is color, this method returns if the fill property should + * be set. + * @return {Boolean} + */ + fill: function () { + return this._jsonProp.fill; + }, + + /** + * Lightness defines the satiation of the color + * 0 is the pure color + * 1 is white + * @return {Integer} lightness + */ + lightness: function () { + return this._jsonProp.lightness; + }, + + /** + * If type is color, this method returns if the stroke property should + * be set. + * @return {Boolean} + */ + stroke: function () { + return this._jsonProp.stroke; + }, + + /** + * If type is choice, items is a hash map with all alternative values + * (PropertyItem objects) with id as keys. + */ + items: function () { + return $H(this._items).values(); + }, + + item: function (value) { + if (value) { + return this._items[value.toLowerCase()]; + } else { + return null; + } + }, + + toString: function () { + return "Property " + this.title() + " (" + this.id() + ")"; + }, + + complexItems: function () { + return $H(this._complexItems).values(); + }, + + complexItem: function (id) { + if (id) { + return this._complexItems[id.toLowerCase()]; + } else { + return null; + } + + }, + + complexAttributeToView: function () { + return this._jsonProp.complexAttributeToView || ""; + }, + + isList: function () { + return !!this._jsonProp.isList; + }, + + getListItems: function () { + return this._jsonProp.list; + }, + + /** + * If type is glossary link, the + * type of category can be defined where + * the link only can go to. + * @return {String} The glossary category id + */ + linkableType: function () { + return this._jsonProp.linkableType || ""; + }, + + alwaysAppearInMultiselect: function () { + return this._jsonProp.alwaysAppearInMultiselect; + }, + + popular: function () { + return this._jsonProp.popular || false; + }, + + setPopular: function () { + this._jsonProp.popular = true; + }, + + hide: function () { + this._hidden = true; + }, + + isHidden: function () { + return this._hidden; + }, + + // Skyeye---自定义自己的属性函数 + readOnly: function () { + return this._jsonProp.readOnly || false; + } + +}); +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespace + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} +if (!ORYX.Core.StencilSet) { + ORYX.Core.StencilSet = {}; +} + +/** + * Class Stencil + * uses Prototpye 1.5.0 + * uses Inheritance + */ +ORYX.Core.StencilSet.PropertyItem = Clazz.extend({ + + /** + * Constructor + */ + construct: function (jsonItem, namespace, property) { + arguments.callee.$.construct.apply(this, arguments); + + if (!jsonItem) { + throw "ORYX.Core.StencilSet.PropertyItem(construct): Parameter jsonItem is not defined."; + } + if (!namespace) { + throw "ORYX.Core.StencilSet.PropertyItem(construct): Parameter namespace is not defined."; + } + if (!property) { + throw "ORYX.Core.StencilSet.PropertyItem(construct): Parameter property is not defined."; + } + + this._jsonItem = jsonItem; + this._namespace = namespace; + this._property = property; + + //init all values + if (!jsonItem.value) { + throw "ORYX.Core.StencilSet.PropertyItem(construct): Value is not defined."; + } + + if (this._jsonItem.refToView) { + if (!(this._jsonItem.refToView instanceof Array)) { + this._jsonItem.refToView = [this._jsonItem.refToView]; + } + } else { + this._jsonItem.refToView = []; + } + }, + + /** + * @param {ORYX.Core.StencilSet.PropertyItem} item + * @return {Boolean} True, if item has the same namespace and id. + */ + equals: function (item) { + return (this.property().equals(item.property()) && + this.value() === item.value()); + }, + + namespace: function () { + return this._namespace; + }, + + property: function () { + return this._property; + }, + + value: function () { + return this._jsonItem.value; + }, + + title: function () { + return ORYX.Core.StencilSet.getTranslation(this._jsonItem, "title"); + }, + + refToView: function () { + return this._jsonItem.refToView; + }, + + icon: function () { + return (this._jsonItem.icon) ? this.property().stencil()._source + "icons/" + this._jsonItem.icon : ""; + }, + + toString: function () { + return "PropertyItem " + this.property() + " (" + this.value() + ")"; + } +});/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespaces + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} +if (!ORYX.Core.StencilSet) { + ORYX.Core.StencilSet = {}; +} + +/** + * Class Stencil + * uses Prototpye 1.5.0 + * uses Inheritance + */ +ORYX.Core.StencilSet.ComplexPropertyItem = Clazz.extend({ + + /** + * Constructor + */ + construct: function (jsonItem, namespace, property) { + arguments.callee.$.construct.apply(this, arguments); + + if (!jsonItem) { + throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Parameter jsonItem is not defined."; + } + if (!namespace) { + throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Parameter namespace is not defined."; + } + if (!property) { + throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Parameter property is not defined."; + } + + this._jsonItem = jsonItem; + this._namespace = namespace; + this._property = property; + this._items = new Hash(); + this._complexItems = new Hash(); + + //init all values + if (!jsonItem.name) { + throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Name is not defined."; + } + + if (!jsonItem.type) { + throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Type is not defined."; + } else { + jsonItem.type = jsonItem.type.toLowerCase(); + } + + if (jsonItem.type === ORYX.CONFIG.TYPE_CHOICE) { + if (jsonItem.items && jsonItem.items instanceof Array) { + jsonItem.items.each((function (item) { + this._items[item.value] = new ORYX.Core.StencilSet.PropertyItem(item, namespace, this); + }).bind(this)); + } else { + throw "ORYX.Core.StencilSet.Property(construct): No property items defined." + } + } else if (jsonItem.type === ORYX.CONFIG.TYPE_COMPLEX) { + if (jsonItem.complexItems && jsonItem.complexItems instanceof Array) { + jsonItem.complexItems.each((function (complexItem) { + this._complexItems[complexItem.id] = new ORYX.Core.StencilSet.ComplexPropertyItem(complexItem, namespace, this); + }).bind(this)); + } else { + throw "ORYX.Core.StencilSet.Property(construct): No property items defined." + } + } + }, + + /** + * @param {ORYX.Core.StencilSet.PropertyItem} item + * @return {Boolean} True, if item has the same namespace and id. + */ + equals: function (item) { + return (this.property().equals(item.property()) && + this.name() === item.name()); + }, + + namespace: function () { + return this._namespace; + }, + + property: function () { + return this._property; + }, + + name: function () { + return ORYX.Core.StencilSet.getTranslation(this._jsonItem, "name"); + }, + + id: function () { + return this._jsonItem.id; + }, + + type: function () { + return this._jsonItem.type; + }, + + optional: function () { + return this._jsonItem.optional; + }, + + width: function () { + return this._jsonItem.width; + }, + + value: function () { + return this._jsonItem.value; + }, + + items: function () { + return this._items.values(); + }, + + complexItems: function () { + return this._complexItems.values(); + }, + + disable: function () { + return this._jsonItem.disable; + } +});/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespaces + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} +if (!ORYX.Core.StencilSet) { + ORYX.Core.StencilSet = {}; +} + +/** + * Class Rules uses Prototpye 1.5.0 uses Inheritance + * + * This class implements the API to check the stencil sets' rules. + */ +ORYX.Core.StencilSet.Rules = { + + /** + * Constructor + */ + construct: function () { + arguments.callee.$.construct.apply(this, arguments); + + this._stencilSets = []; + this._stencils = []; + this._containerStencils = []; + + this._cachedConnectSET = new Hash(); + this._cachedConnectSE = new Hash(); + this._cachedConnectTE = new Hash(); + this._cachedCardSE = new Hash(); + this._cachedCardTE = new Hash(); + this._cachedContainPC = new Hash(); + this._cachedMorphRS = new Hash(); + + this._connectionRules = new Hash(); + this._cardinalityRules = new Hash(); + this._containmentRules = new Hash(); + this._morphingRules = new Hash(); + this._layoutRules = new Hash(); + }, + + /** + * Call this method to initialize the rules for a stencil set and all of its + * active extensions. + * + * @param {Object} + * stencilSet + */ + initializeRules: function (stencilSet) { + + var existingSS = this._stencilSets.find(function (ss) { + return (ss.namespace() == stencilSet.namespace()); + }); + if (existingSS) { + // reinitialize all rules + var stencilsets = this._stencilSets.clone(); + stencilsets = stencilsets.without(existingSS); + stencilsets.push(stencilSet); + + this._stencilSets = []; + this._stencils = []; + this._containerStencils = []; + + this._cachedConnectSET = new Hash(); + this._cachedConnectSE = new Hash(); + this._cachedConnectTE = new Hash(); + this._cachedCardSE = new Hash(); + this._cachedCardTE = new Hash(); + this._cachedContainPC = new Hash(); + this._cachedMorphRS = new Hash(); + + this._connectionRules = new Hash(); + this._cardinalityRules = new Hash(); + this._containmentRules = new Hash(); + this._morphingRules = new Hash(); + this._layoutRules = new Hash(); + + stencilsets.each(function (ss) { + this.initializeRules(ss); + }.bind(this)); + return; + } else { + this._stencilSets.push(stencilSet); + + var jsonRules = new Hash(stencilSet.jsonRules()); + var namespace = stencilSet.namespace(); + var stencils = stencilSet.stencils(); + + stencilSet.extensions().values().each(function (extension) { + if (extension.rules) { + if (extension.rules.connectionRules) + jsonRules.connectionRules = jsonRules.connectionRules.concat(extension.rules.connectionRules); + if (extension.rules.cardinalityRules) + jsonRules.cardinalityRules = jsonRules.cardinalityRules.concat(extension.rules.cardinalityRules); + if (extension.rules.containmentRules) + jsonRules.containmentRules = jsonRules.containmentRules.concat(extension.rules.containmentRules); + if (extension.rules.morphingRules) + jsonRules.morphingRules = jsonRules.morphingRules.concat(extension.rules.morphingRules); + } + if (extension.stencils) + stencils = stencils.concat(extension.stencils); + }); + + this._stencils = this._stencils.concat(stencilSet.stencils()); + + // init connection rules + var cr = this._connectionRules; + if (jsonRules.connectionRules) { + jsonRules.connectionRules.each((function (rules) { + if (this._isRoleOfOtherNamespace(rules.role)) { + if (!cr[rules.role]) { + cr[rules.role] = new Hash(); + } + } else { + if (!cr[namespace + rules.role]) + cr[namespace + rules.role] = new Hash(); + } + + rules.connects.each((function (connect) { + var toRoles = []; + if (connect.to) { + if (!(connect.to instanceof Array)) { + connect.to = [connect.to]; + } + connect.to.each((function (to) { + if (this._isRoleOfOtherNamespace(to)) { + toRoles.push(to); + } else { + toRoles.push(namespace + to); + } + }).bind(this)); + } + + var role, from; + if (this._isRoleOfOtherNamespace(rules.role)) + role = rules.role; + else + role = namespace + rules.role; + + if (this._isRoleOfOtherNamespace(connect.from)) + from = connect.from; + else + from = namespace + connect.from; + + if (!cr[role][from]) + cr[role][from] = toRoles; + else + cr[role][from] = cr[role][from].concat(toRoles); + + }).bind(this)); + }).bind(this)); + } + + // init cardinality rules + var cardr = this._cardinalityRules; + if (jsonRules.cardinalityRules) { + jsonRules.cardinalityRules.each((function (rules) { + var cardrKey; + if (this._isRoleOfOtherNamespace(rules.role)) { + cardrKey = rules.role; + } else { + cardrKey = namespace + rules.role; + } + + if (!cardr[cardrKey]) { + cardr[cardrKey] = {}; + for (i in rules) { + cardr[cardrKey][i] = rules[i]; + } + } + + var oe = new Hash(); + if (rules.outgoingEdges) { + rules.outgoingEdges.each((function (rule) { + if (this._isRoleOfOtherNamespace(rule.role)) { + oe[rule.role] = rule; + } else { + oe[namespace + rule.role] = rule; + } + }).bind(this)); + } + cardr[cardrKey].outgoingEdges = oe; + var ie = new Hash(); + if (rules.incomingEdges) { + rules.incomingEdges.each((function (rule) { + if (this._isRoleOfOtherNamespace(rule.role)) { + ie[rule.role] = rule; + } else { + ie[namespace + rule.role] = rule; + } + }).bind(this)); + } + cardr[cardrKey].incomingEdges = ie; + }).bind(this)); + } + + // init containment rules + var conr = this._containmentRules; + if (jsonRules.containmentRules) { + jsonRules.containmentRules.each((function (rules) { + var conrKey; + if (this._isRoleOfOtherNamespace(rules.role)) { + conrKey = rules.role; + } else { + this._containerStencils.push(namespace + rules.role); + conrKey = namespace + rules.role; + } + if (!conr[conrKey]) { + conr[conrKey] = []; + } + (rules.contains || []).each((function (containRole) { + if (this._isRoleOfOtherNamespace(containRole)) { + conr[conrKey].push(containRole); + } else { + conr[conrKey].push(namespace + containRole); + } + }).bind(this)); + }).bind(this)); + } + + // init morphing rules + var morphr = this._morphingRules; + if (jsonRules.morphingRules) { + jsonRules.morphingRules.each((function (rules) { + var morphrKey; + if (this._isRoleOfOtherNamespace(rules.role)) { + morphrKey = rules.role; + } else { + morphrKey = namespace + rules.role; + } + if (!morphr[morphrKey]) { + morphr[morphrKey] = []; + } + if (!rules.preserveBounds) { + rules.preserveBounds = false; + } + rules.baseMorphs.each((function (baseMorphStencilId) { + var morphStencil = this._getStencilById(namespace + baseMorphStencilId); + if (morphStencil) { + morphr[morphrKey].push(morphStencil); + } + }).bind(this)); + }).bind(this)); + } + + // init layouting rules + var layoutRules = this._layoutRules; + if (jsonRules.layoutRules) { + + var getDirections = function (o) { + return { + "edgeRole": o.edgeRole || undefined, + "t": o["t"] || 1, + "r": o["r"] || 1, + "b": o["b"] || 1, + "l": o["l"] || 1 + } + } + + jsonRules.layoutRules.each(function (rules) { + var layoutKey; + if (this._isRoleOfOtherNamespace(rules.role)) { + layoutKey = rules.role; + } else { + layoutKey = namespace + rules.role; + } + if (!layoutRules[layoutKey]) { + layoutRules[layoutKey] = {}; + } + if (rules["in"]) { + layoutRules[layoutKey]["in"] = getDirections(rules["in"]); + } + if (rules["ins"]) { + layoutRules[layoutKey]["ins"] = (rules["ins"] || []).map(function (e) { + return getDirections(e) + }) + } + if (rules["out"]) { + layoutRules[layoutKey]["out"] = getDirections(rules["out"]); + } + if (rules["outs"]) { + layoutRules[layoutKey]["outs"] = (rules["outs"] || []).map(function (e) { + return getDirections(e) + }) + } + }.bind(this)); + } + } + }, + + _getStencilById: function (id) { + return this._stencils.find(function (stencil) { + return stencil.id() == id; + }); + }, + + _cacheConnect: function (args) { + result = this._canConnect(args); + + if (args.sourceStencil && args.targetStencil) { + var source = this._cachedConnectSET[args.sourceStencil.id()]; + + if (!source) { + source = new Hash(); + this._cachedConnectSET[args.sourceStencil.id()] = source; + } + + var edge = source[args.edgeStencil.id()]; + + if (!edge) { + edge = new Hash(); + source[args.edgeStencil.id()] = edge; + } + + edge[args.targetStencil.id()] = result; + + } else if (args.sourceStencil) { + var source = this._cachedConnectSE[args.sourceStencil.id()]; + + if (!source) { + source = new Hash(); + this._cachedConnectSE[args.sourceStencil.id()] = source; + } + + source[args.edgeStencil.id()] = result; + + } else { + var target = this._cachedConnectTE[args.targetStencil.id()]; + + if (!target) { + target = new Hash(); + this._cachedConnectTE[args.targetStencil.id()] = target; + } + + target[args.edgeStencil.id()] = result; + } + + return result; + }, + + _cacheCard: function (args) { + + if (args.sourceStencil) { + var source = this._cachedCardSE[args.sourceStencil.id()] + + if (!source) { + source = new Hash(); + this._cachedCardSE[args.sourceStencil.id()] = source; + } + + var max = this._getMaximumNumberOfOutgoingEdge(args); + if (max == undefined) + max = -1; + + source[args.edgeStencil.id()] = max; + } + + if (args.targetStencil) { + var target = this._cachedCardTE[args.targetStencil.id()] + + if (!target) { + target = new Hash(); + this._cachedCardTE[args.targetStencil.id()] = target; + } + + var max = this._getMaximumNumberOfIncomingEdge(args); + if (max == undefined) + max = -1; + + target[args.edgeStencil.id()] = max; + } + }, + + _cacheContain: function (args) { + + var result = [this._canContain(args), + this._getMaximumOccurrence(args.containingStencil, args.containedStencil)] + + if (result[1] == undefined) + result[1] = -1; + + var children = this._cachedContainPC[args.containingStencil.id()]; + + if (!children) { + children = new Hash(); + this._cachedContainPC[args.containingStencil.id()] = children; + } + + children[args.containedStencil.id()] = result; + + return result; + }, + + /** + * Returns all stencils belonging to a morph group. (calculation result is + * cached) + */ + _cacheMorph: function (role) { + + var morphs = this._cachedMorphRS[role]; + + if (!morphs) { + morphs = []; + + if (this._morphingRules.keys().include(role)) { + morphs = this._stencils.select(function (stencil) { + return stencil.roles().include(role); + }); + } + + this._cachedMorphRS[role] = morphs; + } + return morphs; + }, + + /** Begin connection rules' methods */ + + /** + * + * @param {Object} + * args sourceStencil: ORYX.Core.StencilSet.Stencil | undefined + * sourceShape: ORYX.Core.Shape | undefined + * + * At least sourceStencil or sourceShape has to be specified + * + * @return {Array} Array of stencils of edges that can be outgoing edges of + * the source. + */ + outgoingEdgeStencils: function (args) { + // check arguments + if (!args.sourceShape && !args.sourceStencil) { + return []; + } + + // init arguments + if (args.sourceShape) { + args.sourceStencil = args.sourceShape.getStencil(); + } + + var _edges = []; + + // test each edge, if it can connect to source + this._stencils.each((function (stencil) { + if (stencil.type() === "edge") { + var newArgs = Object.clone(args); + newArgs.edgeStencil = stencil; + if (this.canConnect(newArgs)) { + _edges.push(stencil); + } + } + }).bind(this)); + + return _edges; + }, + + /** + * + * @param {Object} + * args targetStencil: ORYX.Core.StencilSet.Stencil | undefined + * targetShape: ORYX.Core.Shape | undefined + * + * At least targetStencil or targetShape has to be specified + * + * @return {Array} Array of stencils of edges that can be incoming edges of + * the target. + */ + incomingEdgeStencils: function (args) { + // check arguments + if (!args.targetShape && !args.targetStencil) { + return []; + } + + // init arguments + if (args.targetShape) { + args.targetStencil = args.targetShape.getStencil(); + } + + var _edges = []; + + // test each edge, if it can connect to source + this._stencils.each((function (stencil) { + if (stencil.type() === "edge") { + var newArgs = Object.clone(args); + newArgs.edgeStencil = stencil; + if (this.canConnect(newArgs)) { + _edges.push(stencil); + } + } + }).bind(this)); + + return _edges; + }, + + /** + * + * @param {Object} + * args edgeStencil: ORYX.Core.StencilSet.Stencil | undefined + * edgeShape: ORYX.Core.Edge | undefined targetStencil: + * ORYX.Core.StencilSet.Stencil | undefined targetShape: + * ORYX.Core.Node | undefined + * + * At least edgeStencil or edgeShape has to be specified!!! + * + * @return {Array} Returns an array of stencils that can be source of the + * specified edge. + */ + sourceStencils: function (args) { + // check arguments + if (!args || + !args.edgeShape && !args.edgeStencil) { + return []; + } + + // init arguments + if (args.targetShape) { + args.targetStencil = args.targetShape.getStencil(); + } + + if (args.edgeShape) { + args.edgeStencil = args.edgeShape.getStencil(); + } + + var _sources = []; + + // check each stencil, if it can be a source + this._stencils.each((function (stencil) { + var newArgs = Object.clone(args); + newArgs.sourceStencil = stencil; + if (this.canConnect(newArgs)) { + _sources.push(stencil); + } + }).bind(this)); + + return _sources; + }, + + /** + * + * @param {Object} + * args edgeStencil: ORYX.Core.StencilSet.Stencil | undefined + * edgeShape: ORYX.Core.Edge | undefined sourceStencil: + * ORYX.Core.StencilSet.Stencil | undefined sourceShape: + * ORYX.Core.Node | undefined + * + * At least edgeStencil or edgeShape has to be specified!!! + * + * @return {Array} Returns an array of stencils that can be target of the + * specified edge. + */ + targetStencils: function (args) { + // check arguments + if (!args || + !args.edgeShape && !args.edgeStencil) { + return []; + } + + // init arguments + if (args.sourceShape) { + args.sourceStencil = args.sourceShape.getStencil(); + } + + if (args.edgeShape) { + args.edgeStencil = args.edgeShape.getStencil(); + } + + var _targets = []; + + // check stencil, if it can be a target + this._stencils.each((function (stencil) { + var newArgs = Object.clone(args); + newArgs.targetStencil = stencil; + if (this.canConnect(newArgs)) { + _targets.push(stencil); + } + }).bind(this)); + + return _targets; + }, + + /** + * + * @param {Object} + * args edgeStencil: ORYX.Core.StencilSet.Stencil edgeShape: + * ORYX.Core.Edge |undefined sourceStencil: + * ORYX.Core.StencilSet.Stencil | undefined sourceShape: + * ORYX.Core.Node |undefined targetStencil: + * ORYX.Core.StencilSet.Stencil | undefined targetShape: + * ORYX.Core.Node |undefined + * + * At least source or target has to be specified!!! + * + * @return {Boolean} Returns, if the edge can connect source and target. + */ + canConnect: function (args) { + // check arguments + if (!args || + (!args.sourceShape && !args.sourceStencil && + !args.targetShape && !args.targetStencil) || + !args.edgeShape && !args.edgeStencil) { + return false; + } + + // init arguments + if (args.sourceShape) { + args.sourceStencil = args.sourceShape.getStencil(); + } + if (args.targetShape) { + args.targetStencil = args.targetShape.getStencil(); + } + if (args.edgeShape) { + args.edgeStencil = args.edgeShape.getStencil(); + } + + var result; + + if (args.sourceStencil && args.targetStencil) { + var source = this._cachedConnectSET[args.sourceStencil.id()]; + + if (!source) + result = this._cacheConnect(args); + else { + var edge = source[args.edgeStencil.id()]; + + if (!edge) + result = this._cacheConnect(args); + else { + var target = edge[args.targetStencil.id()]; + + if (target == undefined) + result = this._cacheConnect(args); + else + result = target; + } + } + } else if (args.sourceStencil) { + var source = this._cachedConnectSE[args.sourceStencil.id()]; + + if (!source) + result = this._cacheConnect(args); + else { + var edge = source[args.edgeStencil.id()]; + + if (edge == undefined) + result = this._cacheConnect(args); + else + result = edge; + } + } else { // args.targetStencil + var target = this._cachedConnectTE[args.targetStencil.id()]; + + if (!target) + result = this._cacheConnect(args); + else { + var edge = target[args.edgeStencil.id()]; + + if (edge == undefined) + result = this._cacheConnect(args); + else + result = edge; + } + } + + // check cardinality + if (result) { + if (args.sourceShape) { + var source = this._cachedCardSE[args.sourceStencil.id()]; + + if (!source) { + this._cacheCard(args); + source = this._cachedCardSE[args.sourceStencil.id()]; + } + + var max = source[args.edgeStencil.id()]; + + if (max == undefined) { + this._cacheCard(args); + } + + max = source[args.edgeStencil.id()]; + + if (max != -1) { + result = args.sourceShape.getOutgoingShapes().all(function (cs) { + if ((cs.getStencil().id() === args.edgeStencil.id()) && + ((args.edgeShape) ? cs !== args.edgeShape : true)) { + max--; + return (max > 0) ? true : false; + } else { + return true; + } + }); + } + } + + if (args.targetShape) { + var target = this._cachedCardTE[args.targetStencil.id()]; + + if (!target) { + this._cacheCard(args); + target = this._cachedCardTE[args.targetStencil.id()]; + } + + var max = target[args.edgeStencil.id()]; + + if (max == undefined) { + this._cacheCard(args); + } + + max = target[args.edgeStencil.id()]; + + if (max != -1) { + result = args.targetShape.getIncomingShapes().all(function (cs) { + if ((cs.getStencil().id() === args.edgeStencil.id()) && + ((args.edgeShape) ? cs !== args.edgeShape : true)) { + max--; + return (max > 0) ? true : false; + } else { + return true; + } + }); + } + } + } + + return result; + }, + + /** + * + * @param {Object} + * args edgeStencil: ORYX.Core.StencilSet.Stencil edgeShape: + * ORYX.Core.Edge |undefined sourceStencil: + * ORYX.Core.StencilSet.Stencil | undefined sourceShape: + * ORYX.Core.Node |undefined targetStencil: + * ORYX.Core.StencilSet.Stencil | undefined targetShape: + * ORYX.Core.Node |undefined + * + * At least source or target has to be specified!!! + * + * @return {Boolean} Returns, if the edge can connect source and target. + */ + _canConnect: function (args) { + // check arguments + if (!args || + (!args.sourceShape && !args.sourceStencil && + !args.targetShape && !args.targetStencil) || + !args.edgeShape && !args.edgeStencil) { + return false; + } + + // init arguments + if (args.sourceShape) { + args.sourceStencil = args.sourceShape.getStencil(); + } + if (args.targetShape) { + args.targetStencil = args.targetShape.getStencil(); + } + if (args.edgeShape) { + args.edgeStencil = args.edgeShape.getStencil(); + } + + // 1. check connection rules + var resultCR; + + // get all connection rules for this edge + var edgeRules = this._getConnectionRulesOfEdgeStencil(args.edgeStencil); + + // check connection rules, if the source can be connected to the target + // with the specified edge. + if (edgeRules.keys().length === 0) { + resultCR = false; + } else { + if (args.sourceStencil) { + resultCR = args.sourceStencil.roles().any(function (sourceRole) { + var targetRoles = edgeRules[sourceRole]; + + if (!targetRoles) { + return false; + } + + if (args.targetStencil) { + return (targetRoles.any(function (targetRole) { + return args.targetStencil.roles().member(targetRole); + })); + } else { + return true; + } + }); + } else { // !args.sourceStencil -> there is args.targetStencil + resultCR = edgeRules.values().any(function (targetRoles) { + return args.targetStencil.roles().any(function (targetRole) { + return targetRoles.member(targetRole); + }); + }); + } + } + + return resultCR; + }, + + /** End connection rules' methods */ + + + /** Begin containment rules' methods */ + + isContainer: function (shape) { + return this._containerStencils.member(shape.getStencil().id()); + }, + + /** + * + * @param {Object} + * args containingStencil: ORYX.Core.StencilSet.Stencil + * containingShape: ORYX.Core.AbstractShape containedStencil: + * ORYX.Core.StencilSet.Stencil containedShape: ORYX.Core.Shape + */ + canContain: function (args) { + if (!args || + !args.containingStencil && !args.containingShape || + !args.containedStencil && !args.containedShape) { + return false; + } + + // init arguments + if (args.containedShape) { + args.containedStencil = args.containedShape.getStencil(); + } + + if (args.containingShape) { + args.containingStencil = args.containingShape.getStencil(); + } + + //if(args.containingStencil.type() == 'edge' || args.containedStencil.type() == 'edge') + // return false; + if (args.containedStencil.type() == 'edge') + return false; + + var childValues; + + var parent = this._cachedContainPC[args.containingStencil.id()]; + + if (!parent) + childValues = this._cacheContain(args); + else { + childValues = parent[args.containedStencil.id()]; + + if (!childValues) + childValues = this._cacheContain(args); + } + + if (!childValues[0]) + return false; + else if (childValues[1] == -1) + return true; + else { + if (args.containingShape) { + var max = childValues[1]; + return args.containingShape.getChildShapes(false).all(function (as) { + if (as.getStencil().id() === args.containedStencil.id()) { + max--; + return (max > 0) ? true : false; + } else { + return true; + } + }); + } else { + return true; + } + } + }, + + /** + * + * @param {Object} + * args containingStencil: ORYX.Core.StencilSet.Stencil + * containingShape: ORYX.Core.AbstractShape containedStencil: + * ORYX.Core.StencilSet.Stencil containedShape: ORYX.Core.Shape + */ + _canContain: function (args) { + if (!args || + !args.containingStencil && !args.containingShape || + !args.containedStencil && !args.containedShape) { + return false; + } + + // init arguments + if (args.containedShape) { + args.containedStencil = args.containedShape.getStencil(); + } + + if (args.containingShape) { + args.containingStencil = args.containingShape.getStencil(); + } + +// if(args.containingShape) { +// if(args.containingShape instanceof ORYX.Core.Edge) { +// // edges cannot contain other shapes +// return false; +// } +// } + + + var result; + + // check containment rules + result = args.containingStencil.roles().any((function (role) { + var roles = this._containmentRules[role]; + if (roles) { + return roles.any(function (role) { + return args.containedStencil.roles().member(role); + }); + } else { + return false; + } + }).bind(this)); + + return result; + }, + + /** End containment rules' methods */ + + + /** Begin morphing rules' methods */ + + /** + * + * @param {Object} + * args + * stencil: ORYX.Core.StencilSet.Stencil | undefined + * shape: ORYX.Core.Shape | undefined + * + * At least stencil or shape has to be specified + * + * @return {Array} Array of stencils that the passed stencil/shape can be + * transformed to (including the current stencil itself) + */ + morphStencils: function (args) { + // check arguments + if (!args.stencil && !args.shape) { + return []; + } + + // init arguments + if (args.shape) { + args.stencil = args.shape.getStencil(); + } + + var _morphStencils = []; + args.stencil.roles().each(function (role) { + this._cacheMorph(role).each(function (stencil) { + _morphStencils.push(stencil); + }) + }.bind(this)); + + + var baseMorphs = this.baseMorphs(); + // BaseMorphs should be in the front of the array + _morphStencils = _morphStencils.uniq().sort(function (a, b) { + return baseMorphs.include(a) && !baseMorphs.include(b) ? -1 : (baseMorphs.include(b) && !baseMorphs.include(a) ? 1 : 0) + }) + return _morphStencils; + }, + + /** + * @return {Array} An array of all base morph stencils + */ + baseMorphs: function () { + var _baseMorphs = []; + this._morphingRules.each(function (pair) { + pair.value.each(function (baseMorph) { + _baseMorphs.push(baseMorph); + }); + }); + return _baseMorphs; + }, + + /** + * Returns true if there are morphing rules defines + * @return {boolean} + */ + containsMorphingRules: function () { + return this._stencilSets.any(function (ss) { + return !!ss.jsonRules().morphingRules + }); + }, + + /** + * + * @param {Object} + * args + * sourceStencil: + * ORYX.Core.StencilSet.Stencil | undefined + * sourceShape: + * ORYX.Core.Node |undefined + * targetStencil: + * ORYX.Core.StencilSet.Stencil | undefined + * targetShape: + * ORYX.Core.Node |undefined + * + * + * @return {Stencil} Returns, the stencil for the connecting edge + * or null if connection is not possible + */ + connectMorph: function (args) { + // check arguments + if (!args || + (!args.sourceShape && !args.sourceStencil && + !args.targetShape && !args.targetStencil)) { + return false; + } + + // init arguments + if (args.sourceShape) { + args.sourceStencil = args.sourceShape.getStencil(); + } + if (args.targetShape) { + args.targetStencil = args.targetShape.getStencil(); + } + + var incoming = this.incomingEdgeStencils(args); + var outgoing = this.outgoingEdgeStencils(args); + + var edgeStencils = incoming.select(function (e) { + return outgoing.member(e); + }); // intersection of sets + var baseEdgeStencils = this.baseMorphs().select(function (e) { + return edgeStencils.member(e); + }); // again: intersection of sets + + if (baseEdgeStencils.size() > 0) + return baseEdgeStencils[0]; // return any of the possible base morphs + else if (edgeStencils.size() > 0) + return edgeStencils[0]; // return any of the possible stencils + + return null; //connection not possible + }, + + /** + * Return true if the stencil should be located in the shape menu + * @param {ORYX.Core.StencilSet.Stencil} morph + * @return {Boolean} Returns true if the morphs in the morph group of the + * specified morph shall be displayed in the shape menu + */ + showInShapeMenu: function (stencil) { + return this._stencilSets.any(function (ss) { + return ss.jsonRules().morphingRules + .any(function (r) { + return stencil.roles().include(ss.namespace() + r.role) + && r.showInShapeMenu !== false; + }) + }); + }, + + preserveBounds: function (stencil) { + return this._stencilSets.any(function (ss) { + return ss.jsonRules().morphingRules.any(function (r) { + + + return stencil.roles().include(ss.namespace() + r.role) + && r.preserveBounds; + }) + }) + }, + + /** End morphing rules' methods */ + + + /** Begin layouting rules' methods */ + + /** + * Returns a set on "in" and "out" layouting rules for a given shape + * @param {Object} shape + * @param {Object} edgeShape (Optional) + * @return {Object} "in" and "out" with a default value of {"t":1, "r":1, "b":1, "r":1} if not specified in the json + */ + getLayoutingRules: function (shape, edgeShape) { + + if (!shape || !(shape instanceof ORYX.Core.Shape)) { + return + } + + var layout = {"in": {}, "out": {}}; + + var parseValues = function (o, v) { + if (o && o[v]) { + ["t", "r", "b", "l"].each(function (d) { + layout[v][d] = Math.max(o[v][d], layout[v][d] || 0); + }); + } + if (o && o[v + "s"] instanceof Array) { + ["t", "r", "b", "l"].each(function (d) { + var defaultRule = o[v + "s"].find(function (e) { + return !e.edgeRole + }); + var edgeRule; + if (edgeShape instanceof ORYX.Core.Edge) { + edgeRule = o[v + "s"].find(function (e) { + return this._hasRole(edgeShape, e.edgeRole) + }.bind(this)); + } + layout[v][d] = Math.max(edgeRule ? edgeRule[d] : defaultRule[d], layout[v][d] || 0); + }.bind(this)); + } + }.bind(this) + + // For each role + shape.getStencil().roles().each(function (role) { + // check if there are layout information + if (this._layoutRules[role]) { + // if so, parse those information to the 'layout' variable + parseValues(this._layoutRules[role], "in"); + parseValues(this._layoutRules[role], "out"); + } + }.bind(this)); + + // Make sure, that every attribute has an value, + // otherwise set 1 + ["in", "out"].each(function (v) { + ["t", "r", "b", "l"].each(function (d) { + layout[v][d] = layout[v][d] !== undefined ? layout[v][d] : 1; + }); + }) + + return layout; + }, + + /** End layouting rules' methods */ + + /** Helper methods */ + + /** + * Checks wether a shape contains the given role or the role is equal the stencil id + * @param {ORYX.Core.Shape} shape + * @param {String} role + */ + _hasRole: function (shape, role) { + if (!(shape instanceof ORYX.Core.Shape) || !role) { + return + } + var isRole = shape.getStencil().roles().any(function (r) { + return r == role + }); + + return isRole || shape.getStencil().id() == (shape.getStencil().namespace() + role); + }, + + /** + * + * @param {String} + * role + * + * @return {Array} Returns an array of stencils that can act as role. + */ + _stencilsWithRole: function (role) { + return this._stencils.findAll(function (stencil) { + return (stencil.roles().member(role)) ? true : false; + }); + }, + + /** + * + * @param {String} + * role + * + * @return {Array} Returns an array of stencils that can act as role and + * have the type 'edge'. + */ + _edgesWithRole: function (role) { + return this._stencils.findAll(function (stencil) { + return (stencil.roles().member(role) && stencil.type() === "edge") ? true : false; + }); + }, + + /** + * + * @param {String} + * role + * + * @return {Array} Returns an array of stencils that can act as role and + * have the type 'node'. + */ + _nodesWithRole: function (role) { + return this._stencils.findAll(function (stencil) { + return (stencil.roles().member(role) && stencil.type() === "node") ? true : false; + }); + }, + + /** + * + * @param {ORYX.Core.StencilSet.Stencil} + * parent + * @param {ORYX.Core.StencilSet.Stencil} + * child + * + * @returns {Boolean} Returns the maximum occurrence of shapes of the + * stencil's type inside the parent. + */ + _getMaximumOccurrence: function (parent, child) { + var max; + child.roles().each((function (role) { + var cardRule = this._cardinalityRules[role]; + if (cardRule && cardRule.maximumOccurrence) { + if (max) { + max = Math.min(max, cardRule.maximumOccurrence); + } else { + max = cardRule.maximumOccurrence; + } + } + }).bind(this)); + + return max; + }, + + + /** + * + * @param {Object} + * args sourceStencil: ORYX.Core.Node edgeStencil: + * ORYX.Core.StencilSet.Stencil + * + * @return {Boolean} Returns, the maximum number of outgoing edges of the + * type specified by edgeStencil of the sourceShape. + */ + _getMaximumNumberOfOutgoingEdge: function (args) { + if (!args || + !args.sourceStencil || + !args.edgeStencil) { + return false; + } + + var max; + args.sourceStencil.roles().each((function (role) { + var cardRule = this._cardinalityRules[role]; + + if (cardRule && cardRule.outgoingEdges) { + args.edgeStencil.roles().each(function (edgeRole) { + var oe = cardRule.outgoingEdges[edgeRole]; + + if (oe && oe.maximum) { + if (max) { + max = Math.min(max, oe.maximum); + } else { + max = oe.maximum; + } + } + }); + } + }).bind(this)); + + return max; + }, + + /** + * + * @param {Object} + * args targetStencil: ORYX.Core.StencilSet.Stencil edgeStencil: + * ORYX.Core.StencilSet.Stencil + * + * @return {Boolean} Returns the maximum number of incoming edges of the + * type specified by edgeStencil of the targetShape. + */ + _getMaximumNumberOfIncomingEdge: function (args) { + if (!args || + !args.targetStencil || + !args.edgeStencil) { + return false; + } + + var max; + args.targetStencil.roles().each((function (role) { + var cardRule = this._cardinalityRules[role]; + if (cardRule && cardRule.incomingEdges) { + args.edgeStencil.roles().each(function (edgeRole) { + var ie = cardRule.incomingEdges[edgeRole]; + if (ie && ie.maximum) { + if (max) { + max = Math.min(max, ie.maximum); + } else { + max = ie.maximum; + } + } + }); + } + }).bind(this)); + + return max; + }, + + /** + * + * @param {ORYX.Core.StencilSet.Stencil} + * edgeStencil + * + * @return {Hash} Returns a hash map of all connection rules for + * edgeStencil. + */ + _getConnectionRulesOfEdgeStencil: function (edgeStencil) { + var edgeRules = new Hash(); + edgeStencil.roles().each((function (role) { + if (this._connectionRules[role]) { + this._connectionRules[role].each(function (cr) { + if (edgeRules[cr.key]) { + edgeRules[cr.key] = edgeRules[cr.key].concat(cr.value); + } else { + edgeRules[cr.key] = cr.value; + } + }); + } + }).bind(this)); + + return edgeRules; + }, + + _isRoleOfOtherNamespace: function (role) { + return (role.indexOf("#") > 0); + }, + + toString: function () { + return "Rules"; + } +} +ORYX.Core.StencilSet.Rules = Clazz.extend(ORYX.Core.StencilSet.Rules); +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespace + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} +if (!ORYX.Core.StencilSet) { + ORYX.Core.StencilSet = {}; +} + +/** + * This class represents a stencil set. It offers methods for accessing + * the attributes of the stencil set description JSON file and the stencil set's + * stencils. + */ +ORYX.Core.StencilSet.StencilSet = Clazz.extend({ + + /** + * Constructor + * @param source {URL} A reference to the stencil set specification. + * + */ + construct: function (source, modelMetaData, editorId) { + arguments.callee.$.construct.apply(this, arguments); + + if (!source) { + throw "ORYX.Core.StencilSet.StencilSet(construct): Parameter 'source' is not defined."; + } + + if (source.endsWith("/")) { + source = source.substr(0, source.length - 1); + } + + this._extensions = new Hash(); + + this._source = source; + this._baseUrl = source.substring(0, source.lastIndexOf("/") + 1); + + this._jsonObject = {}; + + this._stencils = new Hash(); + this._availableStencils = new Hash(); + + if (ORYX.CONFIG.BACKEND_SWITCH) { + this._baseUrl = "editor/stencilsets/bpmn2.0/"; + this._source = "stencilsets/bpmn2.0/bpmn2.0.json"; + + new Ajax.Request(ACTIVITI.CONFIG.contextRoot + '/editor/stencilset?version=' + Date.now(), { + asynchronous: false, + method: 'get', + onSuccess: this._init.bind(this), + onFailure: this._cancelInit.bind(this) + }); + + } else { + new Ajax.Request(source, { + asynchronous: false, + method: 'get', + onSuccess: this._init.bind(this), + onFailure: this._cancelInit.bind(this) + }); + } + + if (this.errornous) + throw "Loading stencil set " + source + " failed."; + }, + + /** + * Finds a root stencil in this stencil set. There may be many of these. If + * there are, the first one found will be used. In Firefox, this is the + * topmost definition in the stencil set description file. + */ + findRootStencilName: function () { + + // find any stencil that may be root. + var rootStencil = this._stencils.values().find(function (stencil) { + return stencil._jsonStencil.mayBeRoot + }); + + // if there is none, just guess the first. + if (!rootStencil) { + ORYX.Log.warn("Did not find any stencil that may be root. Taking a guess."); + rootStencil = this._stencils.values()[0]; + } + + // return its id. + return rootStencil.id(); + }, + + /** + * @param {ORYX.Core.StencilSet.StencilSet} stencilSet + * @return {Boolean} True, if stencil set has the same namespace. + */ + equals: function (stencilSet) { + return (this.namespace() === stencilSet.namespace()); + }, + + /** + * + * @param {Oryx.Core.StencilSet.Stencil} rootStencil If rootStencil is defined, it only returns stencils + * that could be (in)direct child of that stencil. + */ + stencils: function (rootStencil, rules, sortByGroup) { + if (rootStencil && rules) { + var stencils = this._availableStencils.values(); + var containers = [rootStencil]; + var checkedContainers = []; + + var result = []; + + while (containers.size() > 0) { + var container = containers.pop(); + checkedContainers.push(container); + var children = stencils.findAll(function (stencil) { + var args = { + containingStencil: container, + containedStencil: stencil + }; + return rules.canContain(args); + }); + for (var i = 0; i < children.size(); i++) { + if (!checkedContainers.member(children[i])) { + containers.push(children[i]); + } + } + result = result.concat(children).uniq(); + } + + // Sort the result to the origin order + result = result.sortBy(function (stencil) { + return stencils.indexOf(stencil); + }); + + + if (sortByGroup) { + result = result.sortBy(function (stencil) { + return stencil.groups().first(); + }); + } + + var edges = stencils.findAll(function (stencil) { + return stencil.type() == "edge"; + }); + result = result.concat(edges); + + return result; + + } else { + if (sortByGroup) { + return this._availableStencils.values().sortBy(function (stencil) { + return stencil.groups().first(); + }); + } else { + return this._availableStencils.values(); + } + } + }, + + nodes: function () { + return this._availableStencils.values().findAll(function (stencil) { + return (stencil.type() === 'node') + }); + }, + + edges: function () { + return this._availableStencils.values().findAll(function (stencil) { + return (stencil.type() === 'edge') + }); + }, + + stencil: function (id) { + return this._stencils[id]; + }, + + title: function () { + return ORYX.Core.StencilSet.getTranslation(this._jsonObject, "title"); + }, + + description: function () { + return ORYX.Core.StencilSet.getTranslation(this._jsonObject, "description"); + }, + + namespace: function () { + return this._jsonObject ? this._jsonObject.namespace : null; + }, + + jsonRules: function () { + return this._jsonObject ? this._jsonObject.rules : null; + }, + + source: function () { + return this._source; + }, + + extensions: function () { + return this._extensions; + }, + + addExtension: function (url) { + + new Ajax.Request(url, { + method: 'GET', + asynchronous: false, + onSuccess: (function (transport) { + this.addExtensionDirectly(transport.responseText); + }).bind(this), + onFailure: (function (transport) { + ORYX.Log.debug("Loading stencil set extension file failed. The request returned an error." + transport); + }).bind(this), + onException: (function (transport) { + ORYX.Log.debug("Loading stencil set extension file failed. The request returned an error." + transport); + }).bind(this) + + }); + }, + + addExtensionDirectly: function (str) { + + try { + eval("var jsonExtension = " + str); + + if (!(jsonExtension["extends"].endsWith("#"))) + jsonExtension["extends"] += "#"; + + if (jsonExtension["extends"] == this.namespace()) { + this._extensions[jsonExtension.namespace] = jsonExtension; + + var defaultPosition = this._stencils.keys().size(); + //load new stencils + if (jsonExtension.stencils) { + $A(jsonExtension.stencils).each(function (stencil) { + defaultPosition++; + var oStencil = new ORYX.Core.StencilSet.Stencil(stencil, this.namespace(), this._baseUrl, this, undefined, defaultPosition); + this._stencils[oStencil.id()] = oStencil; + this._availableStencils[oStencil.id()] = oStencil; + }.bind(this)); + } + + //load additional properties + if (jsonExtension.properties) { + var stencils = this._stencils.values(); + + stencils.each(function (stencil) { + var roles = stencil.roles(); + + jsonExtension.properties.each(function (prop) { + prop.roles.any(function (role) { + role = jsonExtension["extends"] + role; + if (roles.member(role)) { + prop.properties.each(function (property) { + stencil.addProperty(property, jsonExtension.namespace); + }); + + return true; + } else + return false; + }) + }) + }.bind(this)); + } + + //remove stencil properties + if (jsonExtension.removeproperties) { + jsonExtension.removeproperties.each(function (remprop) { + var stencil = this.stencil(jsonExtension["extends"] + remprop.stencil); + if (stencil) { + remprop.properties.each(function (propId) { + stencil.removeProperty(propId); + }); + } + }.bind(this)); + } + + //remove stencils + if (jsonExtension.removestencils) { + $A(jsonExtension.removestencils).each(function (remstencil) { + delete this._availableStencils[jsonExtension["extends"] + remstencil]; + }.bind(this)); + } + } + } catch (e) { + ORYX.Log.debug("StencilSet.addExtension: Something went wrong when initialising the stencil set extension. " + e); + } + }, + + removeExtension: function (namespace) { + var jsonExtension = this._extensions[namespace]; + if (jsonExtension) { + + //unload extension's stencils + if (jsonExtension.stencils) { + $A(jsonExtension.stencils).each(function (stencil) { + var oStencil = new ORYX.Core.StencilSet.Stencil(stencil, this.namespace(), this._baseUrl, this); + delete this._stencils[oStencil.id()]; // maybe not ?? + delete this._availableStencils[oStencil.id()]; + }.bind(this)); + } + + //unload extension's properties + if (jsonExtension.properties) { + var stencils = this._stencils.values(); + + stencils.each(function (stencil) { + var roles = stencil.roles(); + + jsonExtension.properties.each(function (prop) { + prop.roles.any(function (role) { + role = jsonExtension["extends"] + role; + if (roles.member(role)) { + prop.properties.each(function (property) { + stencil.removeProperty(property.id); + }); + + return true; + } else + return false; + }) + }) + }.bind(this)); + } + + //restore removed stencil properties + if (jsonExtension.removeproperties) { + jsonExtension.removeproperties.each(function (remprop) { + var stencil = this.stencil(jsonExtension["extends"] + remprop.stencil); + if (stencil) { + var stencilJson = $A(this._jsonObject.stencils).find(function (s) { + return s.id == stencil.id() + }); + remprop.properties.each(function (propId) { + var propertyJson = $A(stencilJson.properties).find(function (p) { + return p.id == propId + }); + stencil.addProperty(propertyJson, this.namespace()); + }.bind(this)); + } + }.bind(this)); + } + + //restore removed stencils + if (jsonExtension.removestencils) { + $A(jsonExtension.removestencils).each(function (remstencil) { + var sId = jsonExtension["extends"] + remstencil; + this._availableStencils[sId] = this._stencils[sId]; + }.bind(this)); + } + } + delete this._extensions[namespace]; + }, + + __handleStencilset: function (response) { + + try { + // using eval instead of prototype's parsing, + // since there are functions in this JSON. + eval("this._jsonObject =" + response.responseText); + } catch (e) { + throw "Stenciset corrupt: " + e; + } + + // assert it was parsed. + if (!this._jsonObject) { + throw "Error evaluating stencilset. It may be corrupt."; + } + + with (this._jsonObject) { + + // assert there is a namespace. + if (!namespace || namespace === "") + throw "Namespace definition missing in stencilset."; + + if (!(stencils instanceof Array)) + throw "Stencilset corrupt."; + + // assert namespace ends with '#'. + if (!namespace.endsWith("#")) + namespace = namespace + "#"; + + // assert title and description are strings. + if (!title) + title = ""; + if (!description) + description = ""; + } + }, + + /** + * This method is called when the HTTP request to get the requested stencil + * set succeeds. The response is supposed to be a JSON representation + * according to the stencil set specification. + * @param {Object} response The JSON representation according to the + * stencil set specification. + */ + _init: function (response) { + + // init and check consistency. + this.__handleStencilset(response); + + var pps = new Hash(); + + // init property packages + if (this._jsonObject.propertyPackages) { + $A(this._jsonObject.propertyPackages).each((function (pp) { + pps[pp.name] = pp.properties; + }).bind(this)); + } + + var defaultPosition = 0; + + // init each stencil + $A(this._jsonObject.stencils).each((function (stencil) { + defaultPosition++; + + // instantiate normally. + var oStencil = new ORYX.Core.StencilSet.Stencil(stencil, this.namespace(), this._baseUrl, this, pps, defaultPosition); + this._stencils[oStencil.id()] = oStencil; + this._availableStencils[oStencil.id()] = oStencil; + + }).bind(this)); + }, + + _cancelInit: function (response) { + this.errornous = true; + }, + + toString: function () { + return "StencilSet " + this.title() + " (" + this.namespace() + ")"; + } +}); +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespace + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} +if (!ORYX.Core.StencilSet) { + ORYX.Core.StencilSet = {}; +} + +/** + * Class StencilSets + * uses Prototpye 1.5.0 + * uses Inheritance + * + * Singleton + */ +//storage for loaded stencil sets by namespace +ORYX.Core.StencilSet._stencilSetsByNamespace = new Hash(); + +//storage for stencil sets by url +ORYX.Core.StencilSet._stencilSetsByUrl = new Hash(); + +//storage for stencil set namespaces by editor instances +ORYX.Core.StencilSet._StencilSetNSByEditorInstance = new Hash(); + +//storage for rules by editor instances +ORYX.Core.StencilSet._rulesByEditorInstance = new Hash(); + +/** + * + * @param {String} editorId + * + * @return {Hash} Returns a hash map with all stencil sets that are loaded by + * the editor with the editorId. + */ +ORYX.Core.StencilSet.stencilSets = function (editorId) { + var stencilSetNSs = ORYX.Core.StencilSet._StencilSetNSByEditorInstance[editorId]; + var stencilSets = new Hash(); + if (stencilSetNSs) { + stencilSetNSs.each(function (stencilSetNS) { + var stencilSet = ORYX.Core.StencilSet.stencilSet(stencilSetNS) + stencilSets[stencilSet.namespace()] = stencilSet; + }); + } + return stencilSets; +}; + +/** + * + * @param {String} namespace + * + * @return {ORYX.Core.StencilSet.StencilSet} Returns the stencil set with the specified + * namespace. + * + * The method can handle namespace strings like + * http://www.example.org/stencilset + * http://www.example.org/stencilset# + * http://www.example.org/stencilset#ANode + */ +ORYX.Core.StencilSet.stencilSet = function (namespace) { + ORYX.Log.trace("Getting stencil set %0", namespace); + var splitted = namespace.split("#", 1); + if (splitted.length === 1) { + ORYX.Log.trace("Getting stencil set %0", splitted[0]); + return ORYX.Core.StencilSet._stencilSetsByNamespace[splitted[0] + "#"]; + } else { + return undefined; + } +}; + +/** + * + * @param {String} id + * + * @return {ORYX.Core.StencilSet.Stencil} Returns the stencil specified by the id. + * + * The id must be unique and contains the namespace of the stencil's stencil set. + * e.g. http://www.example.org/stencilset#ANode + */ +ORYX.Core.StencilSet.stencil = function (id) { + ORYX.Log.trace("Getting stencil for %0", id); + var ss = ORYX.Core.StencilSet.stencilSet(id); + if (ss) { + return ss.stencil(id); + } else { + + ORYX.Log.trace("Cannot fild stencil for %0", id); + return undefined; + } +}; + +/** + * + * @param {String} editorId + * + * @return {ORYX.Core.StencilSet.Rules} Returns the rules object for the editor + * specified by its editor id. + */ +ORYX.Core.StencilSet.rules = function (editorId) { + if (!ORYX.Core.StencilSet._rulesByEditorInstance[editorId]) { + ORYX.Core.StencilSet._rulesByEditorInstance[editorId] = new ORYX.Core.StencilSet.Rules(); + } + return ORYX.Core.StencilSet._rulesByEditorInstance[editorId]; +}; + +/** + * + * @param {String} url + * @param {String} editorId + * + * Loads a stencil set from url, if it is not already loaded. + * It also stores which editor instance loads the stencil set and + * initializes the Rules object for the editor instance. + */ +ORYX.Core.StencilSet.loadStencilSet = function (url, modelMetaData, editorId) { + + // Alfresco: disable cache, because stencil sets are now flexible + + //var stencilSet = ORYX.Core.StencilSet._stencilSetsByUrl[url]; + + //if(!stencilSet) { + //load stencil set + stencilSet = new ORYX.Core.StencilSet.StencilSet(url, modelMetaData, editorId); + + //store stencil set + ORYX.Core.StencilSet._stencilSetsByNamespace[stencilSet.namespace()] = stencilSet; + + //store stencil set by url + ORYX.Core.StencilSet._stencilSetsByUrl[url] = stencilSet; + //} + + var namespace = stencilSet.namespace(); + + //store which editorInstance loads the stencil set + if (ORYX.Core.StencilSet._StencilSetNSByEditorInstance[editorId]) { + ORYX.Core.StencilSet._StencilSetNSByEditorInstance[editorId].push(namespace); + } else { + ORYX.Core.StencilSet._StencilSetNSByEditorInstance[editorId] = [namespace]; + } + + //store the rules for the editor instance + if (ORYX.Core.StencilSet._rulesByEditorInstance[editorId]) { + ORYX.Core.StencilSet._rulesByEditorInstance[editorId].initializeRules(stencilSet); + } else { + var rules = new ORYX.Core.StencilSet.Rules(); + rules.initializeRules(stencilSet); + ORYX.Core.StencilSet._rulesByEditorInstance[editorId] = rules; + } +}; + +/** + * Returns the translation of an attribute in jsonObject specified by its name + * according to navigator.language + */ +ORYX.Core.StencilSet.getTranslation = function (jsonObject, name) { + var lang = ORYX.I18N.Language.toLowerCase(); + + var result = jsonObject[name + "_" + lang]; + + if (result) + return result; + + result = jsonObject[name + "_" + lang.substr(0, 2)]; + + if (result) + return result; + + return jsonObject[name]; +}; +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespaces + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} + + +/** + * @classDescription With Bounds you can set and get position and size of UIObjects. + */ +ORYX.Core.Command = Clazz.extend({ + + /** + * Constructor + */ + construct: function () { + + }, + + execute: function () { + throw "Command.execute() has to be implemented!" + }, + + rollback: function () { + throw "Command.rollback() has to be implemented!" + } + + +});/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespaces + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} + + +/** + * @classDescription With Bounds you can set and get position and size of UIObjects. + */ +ORYX.Core.Bounds = { + + /** + * Constructor + */ + construct: function () { + this._changedCallbacks = []; //register a callback with changedCallacks.push(this.method.bind(this)); + this.a = {}; + this.b = {}; + this.set.apply(this, arguments); + this.suspendChange = false; + this.changedWhileSuspend = false; + }, + + /** + * Calls all registered callbacks. + */ + _changed: function (sizeChanged) { + if (!this.suspendChange) { + this._changedCallbacks.each(function (callback) { + callback(this, sizeChanged); + }.bind(this)); + this.changedWhileSuspend = false; + } else + this.changedWhileSuspend = true; + }, + + /** + * Registers a callback that is called, if the bounds changes. + * @param callback {Function} The callback function. + */ + registerCallback: function (callback) { + if (!this._changedCallbacks.member(callback)) { + this._changedCallbacks.push(callback); + } + }, + + /** + * Unregisters a callback. + * @param callback {Function} The callback function. + */ + unregisterCallback: function (callback) { + this._changedCallbacks = this._changedCallbacks.without(callback); + }, + + /** + * Sets position and size of the shape dependent of four coordinates + * (set(ax, ay, bx, by);), two points (set({x: ax, y: ay}, {x: bx, y: by});) + * or one bound (set({a: {x: ax, y: ay}, b: {x: bx, y: by}});). + */ + set: function () { + + var changed = false; + + switch (arguments.length) { + + case 1: + if (this.a.x !== arguments[0].a.x) { + changed = true; + this.a.x = arguments[0].a.x; + } + if (this.a.y !== arguments[0].a.y) { + changed = true; + this.a.y = arguments[0].a.y; + } + if (this.b.x !== arguments[0].b.x) { + changed = true; + this.b.x = arguments[0].b.x; + } + if (this.b.y !== arguments[0].b.y) { + changed = true; + this.b.y = arguments[0].b.y; + } + break; + + case 2: + var ax = Math.min(arguments[0].x, arguments[1].x); + var ay = Math.min(arguments[0].y, arguments[1].y); + var bx = Math.max(arguments[0].x, arguments[1].x); + var by = Math.max(arguments[0].y, arguments[1].y); + if (this.a.x !== ax) { + changed = true; + this.a.x = ax; + } + if (this.a.y !== ay) { + changed = true; + this.a.y = ay; + } + if (this.b.x !== bx) { + changed = true; + this.b.x = bx; + } + if (this.b.y !== by) { + changed = true; + this.b.y = by; + } + break; + + case 4: + var ax = Math.min(arguments[0], arguments[2]); + var ay = Math.min(arguments[1], arguments[3]); + var bx = Math.max(arguments[0], arguments[2]); + var by = Math.max(arguments[1], arguments[3]); + if (this.a.x !== ax) { + changed = true; + this.a.x = ax; + } + if (this.a.y !== ay) { + changed = true; + this.a.y = ay; + } + if (this.b.x !== bx) { + changed = true; + this.b.x = bx; + } + if (this.b.y !== by) { + changed = true; + this.b.y = by; + } + break; + } + + if (changed) { + this._changed(true); + } + }, + + /** + * Moves the bounds so that the point p will be the new upper left corner. + * @param {Point} p + * or + * @param {Number} x + * @param {Number} y + */ + moveTo: function () { + + var currentPosition = this.upperLeft(); + switch (arguments.length) { + case 1: + this.moveBy({ + x: arguments[0].x - currentPosition.x, + y: arguments[0].y - currentPosition.y + }); + break; + case 2: + this.moveBy({ + x: arguments[0] - currentPosition.x, + y: arguments[1] - currentPosition.y + }); + break; + default: + //TODO error + } + + }, + + /** + * Moves the bounds relatively by p. + * @param {Point} p + * or + * @param {Number} x + * @param {Number} y + * + */ + moveBy: function () { + var changed = false; + + switch (arguments.length) { + case 1: + var p = arguments[0]; + if (p.x !== 0 || p.y !== 0) { + changed = true; + this.a.x += p.x; + this.b.x += p.x; + this.a.y += p.y; + this.b.y += p.y; + } + break; + case 2: + var x = arguments[0]; + var y = arguments[1]; + if (x !== 0 || y !== 0) { + changed = true; + this.a.x += x; + this.b.x += x; + this.a.y += y; + this.b.y += y; + } + break; + default: + //TODO error + } + + if (changed) { + this._changed(); + } + }, + + /*** + * Includes the bounds b into the current bounds. + * @param {Bounds} b + */ + include: function (b) { + + if ((this.a.x === undefined) && (this.a.y === undefined) && + (this.b.x === undefined) && (this.b.y === undefined)) { + return b; + } + ; + + var cx = Math.min(this.a.x, b.a.x); + var cy = Math.min(this.a.y, b.a.y); + + var dx = Math.max(this.b.x, b.b.x); + var dy = Math.max(this.b.y, b.b.y); + + + this.set(cx, cy, dx, dy); + }, + + /** + * Relatively extends the bounds by p. + * @param {Point} p + */ + extend: function (p) { + + if (p.x !== 0 || p.y !== 0) { + // this is over cross for the case that a and b have same coordinates. + //((this.a.x > this.b.x) ? this.a : this.b).x += p.x; + //((this.b.y > this.a.y) ? this.b : this.a).y += p.y; + this.b.x += p.x; + this.b.y += p.y; + + this._changed(true); + } + }, + + /** + * Widens the scope of the bounds by x. + * @param {Number} x + */ + widen: function (x) { + if (x !== 0) { + this.suspendChange = true; + this.moveBy({x: -x, y: -x}); + this.extend({x: 2 * x, y: 2 * x}); + this.suspendChange = false; + if (this.changedWhileSuspend) { + this._changed(true); + } + } + }, + + /** + * Returns the upper left corner's point regardless of the + * bound delimiter points. + */ + upperLeft: function () { + var result = {}; + result.x = this.a.x; + result.y = this.a.y; + return result; + }, + + /** + * Returns the lower Right left corner's point regardless of the + * bound delimiter points. + */ + lowerRight: function () { + var result = {}; + result.x = this.b.x; + result.y = this.b.y; + return result; + }, + + /** + * @return {Number} Width of bounds. + */ + width: function () { + return this.b.x - this.a.x; + }, + + /** + * @return {Number} Height of bounds. + */ + height: function () { + return this.b.y - this.a.y; + }, + + /** + * @return {Point} The center point of this bounds. + */ + center: function () { + var center = {}; + center.x = (this.a.x + this.b.x) / 2.0; + center.y = (this.a.y + this.b.y) / 2.0; + return center; + }, + + + /** + * @return {Point} The center point of this bounds relative to upperLeft. + */ + midPoint: function () { + + var midpoint = {}; + midpoint.x = (this.b.x - this.a.x) / 2.0; + midpoint.y = (this.b.y - this.a.y) / 2.0; + return midpoint; + }, + + /** + * Moves the center point of this bounds to the new position. + * @param p {Point} + * or + * @param x {Number} + * @param y {Number} + */ + centerMoveTo: function () { + var currentPosition = this.center(); + + switch (arguments.length) { + + case 1: + this.moveBy(arguments[0].x - currentPosition.x, + arguments[0].y - currentPosition.y); + break; + + case 2: + this.moveBy(arguments[0] - currentPosition.x, + arguments[1] - currentPosition.y); + break; + } + }, + + isIncluded: function (point, offset) { + + var pointX, pointY, offset; + + // Get the the two Points + switch (arguments.length) { + case 1: + pointX = arguments[0].x; + pointY = arguments[0].y; + offset = 0; + + break; + case 2: + if (arguments[0].x && arguments[0].y) { + pointX = arguments[0].x; + pointY = arguments[0].y; + offset = Math.abs(arguments[1]); + } else { + pointX = arguments[0]; + pointY = arguments[1]; + offset = 0; + } + break; + case 3: + pointX = arguments[0]; + pointY = arguments[1]; + offset = Math.abs(arguments[2]); + break; + default: + throw "isIncluded needs one, two or three arguments"; + } + + var ul = this.upperLeft(); + var lr = this.lowerRight(); + + if (pointX >= ul.x - offset + && pointX <= lr.x + offset && pointY >= ul.y - offset + && pointY <= lr.y + offset) + return true; + else + return false; + }, + + /** + * @return {Bounds} A copy of this bounds. + */ + clone: function () { + + //Returns a new bounds object without the callback + // references of the original bounds + return new ORYX.Core.Bounds(this); + }, + + toString: function () { + + return "( " + this.a.x + " | " + this.a.y + " )/( " + this.b.x + " | " + this.b.y + " )"; + }, + + serializeForERDF: function () { + + return this.a.x + "," + this.a.y + "," + this.b.x + "," + this.b.y; + } +}; + +ORYX.Core.Bounds = Clazz.extend(ORYX.Core.Bounds);/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespaces + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} + + +/** + * @classDescription Abstract base class for all objects that have a graphical representation + * within the editor. + * @extends Clazz + */ +ORYX.Core.UIObject = { + /** + * Constructor of the UIObject class. + */ + construct: function (options) { + + this.isChanged = true; //Flag, if UIObject has been changed since last update. + this.isResized = true; + this.isVisible = true; //Flag, if UIObject's display attribute is set to 'inherit' or 'none' + this.isSelectable = false; //Flag, if UIObject is selectable. + this.isResizable = false; //Flag, if UIObject is resizable. + this.isMovable = false; //Flag, if UIObject is movable. + + this.id = ORYX.Editor.provideId(); //get unique id + this.parent = undefined; //parent is defined, if this object is added to another uiObject. + this.node = undefined; //this is a reference to the SVG representation, either locally or in DOM. + this.children = []; //array for all add uiObjects + + this.bounds = new ORYX.Core.Bounds(); //bounds with undefined values + + this._changedCallback = this._changed.bind(this); //callback reference for calling _changed + this.bounds.registerCallback(this._changedCallback); //set callback in bounds + + if (options && options.eventHandlerCallback) { + this.eventHandlerCallback = options.eventHandlerCallback; + } + }, + + /** + * Sets isChanged flag to true. Callback for the bounds object. + */ + _changed: function (bounds, isResized) { + this.isChanged = true; + if (this.bounds == bounds) + this.isResized = isResized || this.isResized; + }, + + /** + * If something changed, this method calls the refresh method that must be implemented by subclasses. + */ + update: function () { + if (this.isChanged) { + this.refresh(); + this.isChanged = false; + + //call update of all children + this.children.each(function (value) { + value.update(); + }); + } + }, + + /** + * Is called in update method, if isChanged is set to true. Sub classes should call the super class method. + */ + refresh: function () { + + }, + + /** + * @return {Array} Array of all child UIObjects. + */ + getChildren: function () { + return this.children.clone(); + }, + + /** + * @return {Array} Array of all parent UIObjects. + */ + getParents: function () { + var parents = []; + var parent = this.parent; + while (parent) { + parents.push(parent); + parent = parent.parent; + } + return parents; + }, + + /** + * Returns TRUE if the given parent is one of the UIObjects parents or the UIObject themselves, otherwise FALSE. + * @param {UIObject} parent + * @return {Boolean} + */ + isParent: function (parent) { + var cparent = this; + while (cparent) { + if (cparent === parent) { + return true; + } + cparent = cparent.parent; + } + return false; + }, + + /** + * @return {String} Id of this UIObject + */ + getId: function () { + return this.id; + }, + + /** + * Method for accessing child uiObjects by id. + * @param {String} id + * @param {Boolean} deep + * + * @return {UIObject} If found, it returns the UIObject with id. + */ + getChildById: function (id, deep) { + return this.children.find(function (uiObj) { + if (uiObj.getId() === id) { + return uiObj; + } else { + if (deep) { + var obj = uiObj.getChildById(id, deep); + if (obj) { + return obj; + } + } + } + }); + }, + + /** + * Adds an UIObject to this UIObject and sets the parent of the + * added UIObject. It is also added to the SVG representation of this + * UIObject. + * @param {UIObject} uiObject + */ + add: function (uiObject) { + //add uiObject, if it is not already a child of this object + if (!(this.children.member(uiObject))) { + //if uiObject is child of another parent, remove it from that parent. + if (uiObject.parent) { + uiObject.remove(uiObject); + } + + //add uiObject to children + this.children.push(uiObject); + + //set parent reference + uiObject.parent = this; + + //add uiObject.node to this.node + uiObject.node = this.node.appendChild(uiObject.node); + + //register callback to get informed, if child is changed + uiObject.bounds.registerCallback(this._changedCallback); + + //uiObject.update(); + } else { + ORYX.Log.info("add: ORYX.Core.UIObject is already a child of this object."); + } + }, + + /** + * Removes UIObject from this UIObject. The SVG representation will also + * be removed from this UIObject's SVG representation. + * @param {UIObject} uiObject + */ + remove: function (uiObject) { + //if uiObject is a child of this object, remove it. + if (this.children.member(uiObject)) { + //remove uiObject from children + this.children = this._uiObjects.without(uiObject); + + //delete parent reference of uiObject + uiObject.parent = undefined; + + //delete uiObject.node from this.node + uiObject.node = this.node.removeChild(uiObject.node); + + //unregister callback to get informed, if child is changed + uiObject.bounds.unregisterCallback(this._changedCallback); + } else { + ORYX.Log.info("remove: ORYX.Core.UIObject is not a child of this object."); + } + + }, + + /** + * Calculates absolute bounds of this UIObject. + */ + absoluteBounds: function () { + if (this.parent) { + var absUL = this.absoluteXY(); + return new ORYX.Core.Bounds(absUL.x, absUL.y, + absUL.x + this.bounds.width(), + absUL.y + this.bounds.height()); + } else { + return this.bounds.clone(); + } + }, + + /** + * @return {Point} The absolute position of this UIObject. + */ + absoluteXY: function () { + if (this.parent) { + var pXY = this.parent.absoluteXY(); + var result = {}; + result.x = pXY.x + this.bounds.upperLeft().x; + result.y = pXY.y + this.bounds.upperLeft().y; + return result; + } else { + var result = {}; + result.x = this.bounds.upperLeft().x; + result.y = this.bounds.upperLeft().y; + return result; + } + }, + + /** + * @return {Point} The absolute position from the Center of this UIObject. + */ + absoluteCenterXY: function () { + if (this.parent) { + var pXY = this.parent.absoluteXY(); + var result = {}; + result.x = pXY.x + this.bounds.center().x; + result.y = pXY.y + this.bounds.center().y; + return result; + + } else { + var result = {}; + result.x = this.bounds.center().x; + result.y = this.bounds.center().y; + return result; + } + }, + + /** + * Hides this UIObject and all its children. + */ + hide: function () { + this.node.setAttributeNS(null, 'display', 'none'); + this.isVisible = false; + this.children.each(function (uiObj) { + uiObj.hide(); + }); + }, + + /** + * Enables visibility of this UIObject and all its children. + */ + show: function () { + this.node.setAttributeNS(null, 'display', 'inherit'); + this.isVisible = true; + this.children.each(function (uiObj) { + uiObj.show(); + }); + }, + + addEventHandlers: function (node) { + + node.addEventListener(ORYX.CONFIG.EVENT_MOUSEDOWN, this._delegateEvent.bind(this), false); + node.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this._delegateEvent.bind(this), false); + node.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this._delegateEvent.bind(this), false); + node.addEventListener(ORYX.CONFIG.EVENT_MOUSEOVER, this._delegateEvent.bind(this), false); + node.addEventListener(ORYX.CONFIG.EVENT_MOUSEOUT, this._delegateEvent.bind(this), false); + node.addEventListener('click', this._delegateEvent.bind(this), false); + node.addEventListener(ORYX.CONFIG.EVENT_DBLCLICK, this._delegateEvent.bind(this), false); + + }, + + _delegateEvent: function (event) { + if (this.eventHandlerCallback) { + this.eventHandlerCallback(event, this); + } + }, + + toString: function () { + return "UIObject " + this.id + } +}; +ORYX.Core.UIObject = Clazz.extend(ORYX.Core.UIObject);/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespaces + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} + +/** + * Top Level uiobject. + * @class ORYX.Core.AbstractShape + * @extends ORYX.Core.UIObject + */ +ORYX.Core.AbstractShape = ORYX.Core.UIObject.extend( + /** @lends ORYX.Core.AbstractShape.prototype */ + { + + /** + * Constructor + */ + construct: function (options, stencil, facade) { + + arguments.callee.$.construct.apply(this, arguments); + + this.resourceId = ORYX.Editor.provideId(); //Id of resource in DOM + + // stencil reference + this._stencil = stencil; + // if the stencil defines a super stencil that should be used for its instances, set it. + if (this._stencil._jsonStencil.superId) { + stencilId = this._stencil.id() + superStencilId = stencilId.substring(0, stencilId.indexOf("#") + 1) + stencil._jsonStencil.superId; + stencilSet = this._stencil.stencilSet(); + this._stencil = stencilSet.stencil(superStencilId); + } + + //Hash map for all properties. Only stores the values of the properties. + this.properties = new Hash(); + this.propertiesChanged = new Hash(); + + // List of properties which are not included in the stencilset, + // but which gets (de)serialized + this.hiddenProperties = new Hash(); + + + //Initialization of property map and initial value. + this._stencil.properties().each((function (property) { + var key = property.prefix() + "-" + property.id(); + this.properties[key] = property.value(); + this.propertiesChanged[key] = true; + }).bind(this)); + + // if super stencil was defined, also regard stencil's properties: + if (stencil._jsonStencil.superId) { + stencil.properties().each((function (property) { + var key = property.prefix() + "-" + property.id(); + var value = property.value(); + var oldValue = this.properties[key]; + this.properties[key] = value; + this.propertiesChanged[key] = true; + + // Raise an event, to show that the property has changed + // required for plugins like processLink.js + //window.setTimeout( function(){ + + this._delegateEvent({ + type: ORYX.CONFIG.EVENT_PROPERTY_CHANGED, + name: key, + value: value, + oldValue: oldValue + }); + + //}.bind(this), 10) + + }).bind(this)); + } + + }, + + layout: function () { + + }, + + /** + * Returns the stencil object specifiing the type of the shape. + */ + getStencil: function () { + return this._stencil; + }, + + /** + * + * @param {Object} resourceId + */ + getChildShapeByResourceId: function (resourceId) { + + resourceId = ERDF.__stripHashes(resourceId); + + return this.getChildShapes(true).find(function (shape) { + return shape.resourceId == resourceId + }); + }, + /** + * + * @param {Object} deep + * @param {Object} iterator + */ + getChildShapes: function (deep, iterator) { + var result = []; + + this.children.each(function (uiObject) { + if (uiObject instanceof ORYX.Core.Shape && uiObject.isVisible) { + if (iterator) { + iterator(uiObject); + } + result.push(uiObject); + if (deep) { + result = result.concat(uiObject.getChildShapes(deep, iterator)); + } + } + }); + + return result; + }, + + /** + * @param {Object} shape + * @return {boolean} true if any of shape's childs is given shape + */ + hasChildShape: function (shape) { + return this.getChildShapes().any(function (child) { + return (child === shape) || child.hasChildShape(shape); + }); + }, + + /** + * + * @param {Object} deep + * @param {Object} iterator + */ + getChildNodes: function (deep, iterator) { + var result = []; + + this.children.each(function (uiObject) { + if (uiObject instanceof ORYX.Core.Node && uiObject.isVisible) { + if (iterator) { + iterator(uiObject); + } + result.push(uiObject); + } + if (uiObject instanceof ORYX.Core.Shape) { + if (deep) { + result = result.concat(uiObject.getChildNodes(deep, iterator)); + } + } + }); + + return result; + }, + + /** + * + * @param {Object} deep + * @param {Object} iterator + */ + getChildEdges: function (deep, iterator) { + var result = []; + + this.children.each(function (uiObject) { + if (uiObject instanceof ORYX.Core.Edge && uiObject.isVisible) { + if (iterator) { + iterator(uiObject); + } + result.push(uiObject); + } + if (uiObject instanceof ORYX.Core.Shape) { + if (deep) { + result = result.concat(uiObject.getChildEdges(deep, iterator)); + } + } + }); + + return result; + }, + + /** + * Returns a sorted array of ORYX.Core.Node objects. + * Ordered in z Order, the last object has the highest z Order. + */ + //TODO deep iterator + getAbstractShapesAtPosition: function () { + var x, y; + switch (arguments.length) { + case 1: + x = arguments[0].x; + y = arguments[0].y; + break; + case 2: //two or more arguments + x = arguments[0]; + y = arguments[1]; + break; + default: + throw "getAbstractShapesAtPosition needs 1 or 2 arguments!" + } + + if (this.isPointIncluded(x, y)) { + + var result = []; + result.push(this); + + //check, if one child is at that position + + + var childNodes = this.getChildNodes(); + var childEdges = this.getChildEdges(); + + [childNodes, childEdges].each(function (ne) { + var nodesAtPosition = new Hash(); + + ne.each(function (node) { + if (!node.isVisible) { + return + } + var candidates = node.getAbstractShapesAtPosition(x, y); + if (candidates.length > 0) { + var nodesInZOrder = $A(node.node.parentNode.childNodes); + var zOrderIndex = nodesInZOrder.indexOf(node.node); + nodesAtPosition[zOrderIndex] = candidates; + } + }); + + nodesAtPosition.keys().sort().each(function (key) { + result = result.concat(nodesAtPosition[key]); + }); + }); + + return result; + + } else { + return []; + } + }, + + /** + * + * @param key {String} Must be 'prefix-id' of property + * @param value {Object} Can be of type String or Number according to property type. + */ + setProperty: function (key, value, force) { + var oldValue = this.properties[key]; + if (oldValue !== value || force === true) { + this.properties[key] = value; + this.propertiesChanged[key] = true; + this._changed(); + + // Raise an event, to show that the property has changed + //window.setTimeout( function(){ + + if (!this._isInSetProperty) { + this._isInSetProperty = true; + + this._delegateEvent({ + type: ORYX.CONFIG.EVENT_PROPERTY_CHANGED, + elements: [this], + name: key, + value: value, + oldValue: oldValue + }); + + delete this._isInSetProperty; + } + //}.bind(this), 10) + } + }, + + /** + * Returns TRUE if one of the properties is flagged as dirty + * @return {boolean} + */ + isPropertyChanged: function () { + return this.propertiesChanged.any(function (property) { + return property.value + }); + }, + + /** + * + * @param {String} Must be 'prefix-id' of property + * @param {Object} Can be of type String or Number according to property type. + */ + setHiddenProperty: function (key, value) { + // IF undefined, Delete + if (value === undefined) { + delete this.hiddenProperties[key]; + return; + } + var oldValue = this.hiddenProperties[key]; + if (oldValue !== value) { + this.hiddenProperties[key] = value; + } + }, + /** + * Calculate if the point is inside the Shape + * @param {Point} + */ + isPointIncluded: function (pointX, pointY, absoluteBounds) { + var absBounds = absoluteBounds ? absoluteBounds : this.absoluteBounds(); + return absBounds.isIncluded(pointX, pointY); + + }, + + /** + * Get the serialized object + * return Array with hash-entrees (prefix, name, value) + * Following values will given: + * Type + * Properties + */ + serialize: function () { + var serializedObject = []; + + // Add the type + serializedObject.push({name: 'type', prefix: 'oryx', value: this.getStencil().id(), type: 'literal'}); + + // Add hidden properties + this.hiddenProperties.each(function (prop) { + serializedObject.push({ + name: prop.key.replace("oryx-", ""), + prefix: "oryx", + value: prop.value, + type: 'literal' + }); + }.bind(this)); + + // Add all properties + this.getStencil().properties().each((function (property) { + + var prefix = property.prefix(); // Get prefix + var name = property.id(); // Get name + + //if(typeof this.properties[prefix+'-'+name] == 'boolean' || this.properties[prefix+'-'+name] != "") + serializedObject.push({ + name: name, + prefix: prefix, + value: this.properties[prefix + '-' + name], + type: 'literal' + }); + + }).bind(this)); + + return serializedObject; + }, + + + deserialize: function (serialize) { + // Search in Serialize + var initializedDocker = 0; + + // Sort properties so that the hidden properties are first in the list + serialize = serialize.sort(function (a, b) { + a = Number(this.properties.keys().member(a.prefix + "-" + a.name)); + b = Number(this.properties.keys().member(b.prefix + "-" + b.name)); + return a > b ? 1 : (a < b ? -1 : 0) + }.bind(this)); + + serialize.each((function (obj) { + + var name = obj.name; + var prefix = obj.prefix; + var value = obj.value; + + // Complex properties can be real json objects, encode them to a string + if (Object.prototype.toString.call(value) === "Object") value = JSON.stringify(value); + + switch (prefix + "-" + name) { + case 'raziel-parent': + // Set parent + if (!this.parent) { + break + } + ; + + // Set outgoing Shape + var parent = this.getCanvas().getChildShapeByResourceId(value); + if (parent) { + parent.add(this); + } + + break; + default: + // If list, eval as an array + var prop = this.getStencil().property(prefix + "-" + name); + if (prop && prop.isList() && typeof value === "string") { + if ((value || "").strip() && !value.startsWith("[") && !value.startsWith("]")) + value = "[\"" + value.strip() + "\"]"; + value = ((value || "").strip() || "[]").evalJSON(); + } + + // Set property + if (this.properties.keys().member(prefix + "-" + name)) { + this.setProperty(prefix + "-" + name, value); + } else if (!(name === "bounds" || name === "parent" || name === "target" || name === "dockers" || name === "docker" || name === "outgoing" || name === "incoming")) { + this.setHiddenProperty(prefix + "-" + name, value); + } + + } + }).bind(this)); + }, + + toString: function () { + return "ORYX.Core.AbstractShape " + this.id + }, + + /** + * Converts the shape to a JSON representation. + * @return {Object} A JSON object with included ORYX.Core.AbstractShape.JSONHelper and getShape() method. + */ + toJSON: function () { + var json = { + resourceId: this.resourceId, + properties: jQuery.extend({}, this.properties, this.hiddenProperties).inject({}, function (props, prop) { + var key = prop[0]; + var value = prop[1]; + + //If complex property, value should be a json object + if (this.getStencil().property(key) + && this.getStencil().property(key).type() === ORYX.CONFIG.TYPE_COMPLEX + && Object.prototype.toString.call(value) === "String") { + + try { + value = JSON.parse(value); + } catch (error) { + } + //try {value = JSON.parse(value);} catch(error){} + + // Parse date + } else if (value instanceof Date && this.getStencil().property(key)) { + try { + value = value.format(this.getStencil().property(key).dateFormat()); + } catch (e) { + } + } + + //Takes "my_property" instead of "oryx-my_property" as key + key = key.replace(/^[\w_]+-/, ""); + props[key] = value; + + return props; + }.bind(this)), + stencil: { + id: this.getStencil().idWithoutNs() + }, + childShapes: this.getChildShapes().map(function (shape) { + return shape.toJSON(); + }) + }; + + if (this.getOutgoingShapes) { + json.outgoing = this.getOutgoingShapes().map(function (shape) { + return { + resourceId: shape.resourceId + }; + }); + } + + if (this.bounds) { + json.bounds = { + lowerRight: this.bounds.lowerRight(), + upperLeft: this.bounds.upperLeft() + }; + } + + if (this.dockers) { + json.dockers = this.dockers.map(function (docker) { + var d = docker.getDockedShape() && docker.referencePoint ? docker.referencePoint : docker.bounds.center(); + d.getDocker = function () { + return docker; + }; + return d; + }); + } + + jQuery.extend(json, ORYX.Core.AbstractShape.JSONHelper); + + // do not pollute the json attributes (for serialization), so put the corresponding + // shape is encapsulated in a method + json.getShape = function () { + return this; + }.bind(this); + + return json; + } + }); + +/** + * @namespace Collection of methods which can be used on a shape json object (ORYX.Core.AbstractShape#toJSON()). + * @example + * jQuery.extend(shapeAsJson, ORYX.Core.AbstractShape.JSONHelper); + */ +ORYX.Core.AbstractShape.JSONHelper = { + /** + * Iterates over each child shape. + * @param {Object} iterator Iterator function getting a child shape and his parent as arguments. + * @param {boolean} [deep=false] Iterate recursively (childShapes of childShapes) + * @param {boolean} [modify=false] If true, the result of the iterator function is taken as new shape, return false to delete it. This enables modifying the object while iterating through the child shapes. + * @example + * // Increases the lowerRight x value of each direct child shape by one. + * myShapeAsJson.eachChild(function(shape, parentShape){ + * shape.bounds.lowerRight.x = shape.bounds.lowerRight.x + 1; + * return shape; + * }, false, true); + */ + eachChild: function (iterator, deep, modify) { + if (!this.childShapes) return; + + var newChildShapes = []; //needed if modify = true + + this.childShapes.each(function (shape) { + if (!(shape.eachChild instanceof Function)) { + jQuery.extend(shape, ORYX.Core.AbstractShape.JSONHelper); + } + var res = iterator(shape, this); + if (res) newChildShapes.push(res); //if false is returned, and modify = true, current shape is deleted. + + if (deep) shape.eachChild(iterator, deep, modify); + }.bind(this)); + + if (modify) this.childShapes = newChildShapes; + }, + + getShape: function () { + return null; + }, + getChildShapes: function (deep) { + var allShapes = this.childShapes; + + if (deep) { + this.eachChild(function (shape) { + if (!(shape.getChildShapes instanceof Function)) { + jQuery.extend(shape, ORYX.Core.AbstractShape.JSONHelper); + } + allShapes = allShapes.concat(shape.getChildShapes(deep)); + }, true); + } + + return allShapes; + }, + + /** + * @return {String} Serialized JSON object + */ + serialize: function () { + return JSON.stringify(this); + } +} +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespaces + */ +if (!ORYX) { + var ORYX = {}; +} + +/** + @namespace Namespace for the Oryx core elements. + @name ORYX.Core + */ +if (!ORYX.Core) { + ORYX.Core = {}; +} + +/** + * @class Oryx canvas. + * @extends ORYX.Core.AbstractShape + * + */ +ORYX.Core.Canvas = ORYX.Core.AbstractShape.extend({ + /** @lends ORYX.Core.Canvas.prototype */ + + /** + * Defines the current zoom level + */ + zoomLevel: 1, + + /** + * Constructor + */ + construct: function (options, stencil, facade) { + arguments.callee.$.construct.apply(this, arguments); + + if (!(options && options.width && options.height)) { + + ORYX.Log.fatal("Canvas is missing mandatory parameters options.width and options.height."); + return; + } + this.facade = facade; + //TODO: set document resource id + this.resourceId = options.id; + + this.nodes = []; + + this.edges = []; + + // Row highlighting states + this.colHighlightState = 0; + + this.colHighlightEnabled = false; + + //init svg document + this.rootNode = ORYX.Editor.graft("http://www.w3.org/2000/svg", options.parentNode, + ['svg', {id: this.id, width: options.width, height: options.height}, + ['defs', {}] + ]); + + this.rootNode.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink"); + this.rootNode.setAttribute("xmlns:svg", "http://www.w3.org/2000/svg"); + + this._htmlContainer = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", options.parentNode, + ['div', {id: "oryx_canvas_htmlContainer", style: "position:absolute; top:5px"}]); + + // Additional SVG-node BELOW the stencils to allow underlays (if that is even a word) by plugins + this.underlayNode = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.rootNode, + ['svg', {id: "underlay-container"}]); + + // Create 2 svg-elements in the svg-container + this.columnHightlight1 = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.underlayNode, + ['rect', { + x: 0, + width: ORYX.CONFIG.FORM_ROW_WIDTH + 35, + height: "100%", + style: "fill: #fff6d5", + visibility: "hidden" + }]); + + this.columnHightlight2 = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.underlayNode, + ['rect', { + x: ORYX.CONFIG.FORM_ROW_WIDTH + 35, + width: ORYX.CONFIG.FORM_ROW_WIDTH + 25, + height: "100%", + style: "fill: #fff6d5", + visibility: "hidden" + }]); + + this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.rootNode, + ['g', {}, + ['g', {"class": "stencils"}, + ['g', {"class": "me"}], + ['g', {"class": "children"}], + ['g', {"class": "edge"}] + ], + ['g', {"class": "svgcontainer"}] + ]); + + /* + var off = 2 * ORYX.CONFIG.GRID_DISTANCE; + var size = 3; + var d = ""; + for(var i = 0; i <= options.width; i += off) + for(var j = 0; j <= options.height; j += off) + d = d + "M" + (i - size) + " " + j + " l" + (2*size) + " 0 m" + (-size) + " " + (-size) + " l0 " + (2*size) + " m0" + (-size) + " "; + + ORYX.Editor.graft("http://www.w3.org/2000/svg", this.node.firstChild.firstChild, + ['path', {d:d , stroke:'#000000', 'stroke-width':'0.15px'},]); + */ + + //Global definition of default font for shapes + //Definitions in the SVG definition of a stencil will overwrite these settings for + // that stencil. + /*if(navigator.platform.indexOf("Mac") > -1) { + this.node.setAttributeNS(null, 'stroke', 'black'); + this.node.setAttributeNS(null, 'stroke-width', '0.5px'); + this.node.setAttributeNS(null, 'font-family', 'Skia'); + //this.node.setAttributeNS(null, 'letter-spacing', '2px'); + this.node.setAttributeNS(null, 'font-size', ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT); + } else { + this.node.setAttributeNS(null, 'stroke', 'none'); + this.node.setAttributeNS(null, 'font-family', 'Verdana'); + this.node.setAttributeNS(null, 'font-size', ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT); + }*/ + + this.node.setAttributeNS(null, 'stroke', 'none'); + this.node.setAttributeNS(null, 'font-family', 'Verdana, sans-serif'); + this.node.setAttributeNS(null, 'font-size-adjust', 'none'); + this.node.setAttributeNS(null, 'font-style', 'normal'); + this.node.setAttributeNS(null, 'font-variant', 'normal'); + this.node.setAttributeNS(null, 'font-weight', 'normal'); + this.node.setAttributeNS(null, 'line-heigth', 'normal'); + + this.node.setAttributeNS(null, 'font-size', ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT); + + this.bounds.set(0, 0, options.width, options.height); + + this.addEventHandlers(this.rootNode.parentNode); + + //disable context menu + this.rootNode.oncontextmenu = function () { + return false; + }; + }, + + focus: function () { + + try { + // Get a href + if (!this.focusEl) { + this.focusEl = jQuery('body').append(jQuery('')); + this.focusEl.swallowEvent("click", true); + } + + // Focus it + this.focusEl.focus.defer(1, this.focusEl); + this.focusEl.blur.defer(3, this.focusEl); + + } catch (e) { + } + }, + + setHightlightState: function (state) { + if (this.colHighlightEnabled && this.colHighlightState != state) { + if (state == 0) { + this.columnHightlight1.setAttribute("visibility", "hidden"); + this.columnHightlight2.setAttribute("visibility", "hidden"); + } else if (state == 1) { + this.columnHightlight1.setAttribute("visibility", "visible"); + this.columnHightlight2.setAttribute("visibility", "hidden"); + } else if (state == 2) { + this.columnHightlight1.setAttribute("visibility", "hidden"); + this.columnHightlight2.setAttribute("visibility", "visible"); + } else if (state == 3) { + this.columnHightlight1.setAttribute("visibility", "visible"); + this.columnHightlight2.setAttribute("visibility", "visible"); + } + this.colHighlightState = state; + } + }, + + setHightlightStateBasedOnX: function (x) { + if (x > ORYX.CONFIG.FORM_ROW_WIDTH + 30) { + this.setHightlightState(2); + } else { + this.setHightlightState(1); + } + }, + + update: function () { + + this.nodes.each(function (node) { + this._traverseForUpdate(node); + }.bind(this)); + + // call stencil's layout callback + // (needed for row layouting of xforms) + //this.getStencil().layout(this); + + var layoutEvents = this.getStencil().layout(); + + if (layoutEvents) { + layoutEvents.each(function (event) { + + // setup additional attributes + event.shape = this; + event.forceExecution = true; + event.target = this.rootNode; + + // do layouting + + this._delegateEvent(event); + }.bind(this)) + } + + this.nodes.invoke("_update"); + + this.edges.invoke("_update", true); + + /*this.children.each(function(child) { + child._update(); + });*/ + }, + + _traverseForUpdate: function (shape) { + var childRet = shape.isChanged; + shape.getChildNodes(false, function (child) { + if (this._traverseForUpdate(child)) { + childRet = true; + } + }.bind(this)); + + if (childRet) { + shape.layout(); + return true; + } else { + return false; + } + }, + + layout: function () { + + + }, + + /** + * + * @param {Object} deep + * @param {Object} iterator + */ + getChildNodes: function (deep, iterator) { + if (!deep && !iterator) { + return this.nodes.clone(); + } else { + var result = []; + this.nodes.each(function (uiObject) { + if (iterator) { + iterator(uiObject); + } + result.push(uiObject); + + if (deep && uiObject instanceof ORYX.Core.Shape) { + result = result.concat(uiObject.getChildNodes(deep, iterator)); + } + }); + + return result; + } + }, + + /** + * buggy crap! use base class impl instead! + * @param {Object} iterator + */ + /* getChildEdges: function(iterator) { + if(iterator) { + this.edges.each(function(edge) { + iterator(edge); + }); + } + + return this.edges.clone(); + }, +*/ + /** + * Overrides the UIObject.add method. Adds uiObject to the correct sub node. + * @param {UIObject} uiObject + */ + add: function (uiObject, index, silent) { + //if uiObject is child of another UIObject, remove it. + if (uiObject instanceof ORYX.Core.UIObject) { + if (!(this.children.member(uiObject))) { + //if uiObject is child of another parent, remove it from that parent. + if (uiObject.parent) { + uiObject.parent.remove(uiObject, true); + } + + //add uiObject to the Canvas + //add uiObject to this Shape + if (index != undefined) + this.children.splice(index, 0, uiObject); + else + this.children.push(uiObject); + + //set parent reference + uiObject.parent = this; + + //add uiObject.node to this.node depending on the type of uiObject + if (uiObject instanceof ORYX.Core.Shape) { + if (uiObject instanceof ORYX.Core.Edge) { + uiObject.addMarkers(this.rootNode.getElementsByTagNameNS(NAMESPACE_SVG, "defs")[0]); + uiObject.node = this.node.childNodes[0].childNodes[2].appendChild(uiObject.node); + this.edges.push(uiObject); + } else { + uiObject.node = this.node.childNodes[0].childNodes[1].appendChild(uiObject.node); + this.nodes.push(uiObject); + } + } else { //UIObject + uiObject.node = this.node.appendChild(uiObject.node); + } + + uiObject.bounds.registerCallback(this._changedCallback); + + if (this.eventHandlerCallback && silent !== true) + this.eventHandlerCallback({type: ORYX.CONFIG.EVENT_SHAPEADDED, shape: uiObject}) + } else { + + ORYX.Log.warn("add: ORYX.Core.UIObject is already a child of this object."); + } + } else { + + ORYX.Log.fatal("add: Parameter is not of type ORYX.Core.UIObject."); + } + }, + + /** + * Overrides the UIObject.remove method. Removes uiObject. + * @param {UIObject} uiObject + */ + remove: function (uiObject, silent) { + //if uiObject is a child of this object, remove it. + if (this.children.member(uiObject)) { + //remove uiObject from children + var parent = uiObject.parent; + + this.children = this.children.without(uiObject); + + //delete parent reference of uiObject + uiObject.parent = undefined; + + //delete uiObject.node from this.node + if (uiObject instanceof ORYX.Core.Shape) { + if (uiObject instanceof ORYX.Core.Edge) { + uiObject.removeMarkers(); + uiObject.node = this.node.childNodes[0].childNodes[2].removeChild(uiObject.node); + this.edges = this.edges.without(uiObject); + } else { + uiObject.node = this.node.childNodes[0].childNodes[1].removeChild(uiObject.node); + this.nodes = this.nodes.without(uiObject); + } + } else { //UIObject + uiObject.node = this.node.removeChild(uiObject.node); + } + + if (this.eventHandlerCallback && silent !== true) + this.eventHandlerCallback({type: ORYX.CONFIG.EVENT_SHAPEREMOVED, shape: uiObject, parent: parent}); + + uiObject.bounds.unregisterCallback(this._changedCallback); + } else { + + ORYX.Log.warn("remove: ORYX.Core.UIObject is not a child of this object."); + } + }, + + /** + * Creates shapes out of the given collection of shape objects and adds them to the canvas. + * @example + * canvas.addShapeObjects({ + bounds:{ lowerRight:{ y:510, x:633 }, upperLeft:{ y:146, x:210 } }, + resourceId:"oryx_F0715955-50F2-403D-9851-C08CFE70F8BD", + childShapes:[], + properties:{}, + stencil:{ + id:"Subprocess" + }, + outgoing:[{resourceId: 'aShape'}], + target: {resourceId: 'aShape'} + }); + * @param {Object} shapeObjects + * @param {Function} [eventHandler] An event handler passed to each newly created shape (as eventHandlerCallback) + * @return {Array} A collection of ORYX.Core.Shape + * @methodOf ORYX.Core.Canvas.prototype + */ + addShapeObjects: function (shapeObjects, eventHandler) { + if (!shapeObjects) return; + + this.initializingShapes = true; + + /*FIXME This implementation is very evil! At first, all shapes are created on + canvas. In a second step, the attributes are applied. There must be a distinction + between the configuration phase (where the outgoings, for example, are just named), + and the creation phase (where the outgoings are evaluated). This must be reflected + in code to provide a nicer API/ implementation!!! */ + + var addShape = function (shape, parent) { + // Create a new Stencil + var stencil = ORYX.Core.StencilSet.stencil(this.getStencil().namespace() + shape.stencil.id); + + // Create a new Shape + var ShapeClass = (stencil.type() == "node") ? ORYX.Core.Node : ORYX.Core.Edge; + var newShape = new ShapeClass( + {'eventHandlerCallback': eventHandler}, + stencil, this.facade); + + // Set the resource id + newShape.resourceId = shape.resourceId; + newShape.node.id = "svg-" + shape.resourceId; + + // Set parent to json object to be used later + // Due to the nested json structure, normally shape.parent is not set/ must not be set. + // In special cases, it can be easier to set this directly instead of a nested structure. + shape.parent = "#" + ((shape.parent && shape.parent.resourceId) || parent.resourceId); + + // Add the shape to the canvas + this.add(newShape); + + return { + json: shape, + object: newShape + }; + }.bind(this); + + /** Builds up recursively a flatted array of shapes, including a javascript object and json representation + * @param {Object} shape Any object that has Object#childShapes + */ + var addChildShapesRecursively = function (shape) { + var addedShapes = []; + + if (shape.childShapes && shape.childShapes.constructor == String) { + shape.childShapes = JSON.parse(shape.childShapes); + } + + shape.childShapes.each(function (childShape) { + addedShapes.push(addShape(childShape, shape)); + addedShapes = addedShapes.concat(addChildShapesRecursively(childShape)); + }); + + return addedShapes; + }.bind(this); + + var shapes = addChildShapesRecursively({ + childShapes: shapeObjects, + resourceId: this.resourceId + }); + + + // prepare deserialisation parameter + shapes.each( + function (shape) { + var properties = []; + for (field in shape.json.properties) { + properties.push({ + prefix: 'oryx', + name: field, + value: shape.json.properties[field] + }); + } + + // Outgoings + shape.json.outgoing.each(function (out) { + properties.push({ + prefix: 'raziel', + name: 'outgoing', + value: "#" + out.resourceId + }); + }); + + // Target + // (because of a bug, the first outgoing is taken when there is no target, + // can be removed after some time) + if (shape.object instanceof ORYX.Core.Edge) { + var target = shape.json.target || shape.json.outgoing[0]; + if (target) { + properties.push({ + prefix: 'raziel', + name: 'target', + value: "#" + target.resourceId + }); + } + } + + // Bounds + if (shape.json.bounds) { + properties.push({ + prefix: 'oryx', + name: 'bounds', + value: shape.json.bounds.upperLeft.x + "," + shape.json.bounds.upperLeft.y + "," + shape.json.bounds.lowerRight.x + "," + shape.json.bounds.lowerRight.y + }); + } + + //Dockers [{x:40, y:50}, {x:30, y:60}] => "40 50 30 60 #" + if (shape.json.dockers) { + properties.push({ + prefix: 'oryx', + name: 'dockers', + value: shape.json.dockers.inject("", function (dockersStr, docker) { + return dockersStr + docker.x + " " + docker.y + " "; + }) + " #" + }); + } + + //Parent + properties.push({ + prefix: 'raziel', + name: 'parent', + value: shape.json.parent + }); + + shape.__properties = properties; + }.bind(this) + ); + + // Deserialize the properties from the shapes + // This can't be done earlier because Shape#deserialize expects that all referenced nodes are already there + + // first, deserialize all nodes + shapes.each(function (shape) { + if (shape.object instanceof ORYX.Core.Node) { + shape.object.deserialize(shape.__properties, shape.json); + } + }); + + // second, deserialize all edges + shapes.each(function (shape) { + if (shape.object instanceof ORYX.Core.Edge) { + shape.object.deserialize(shape.__properties, shape.json); + shape.object._oldBounds = shape.object.bounds.clone(); + shape.object._update(); + } + }); + + delete this.initializingShapes; + return shapes.pluck("object"); + }, + + /** + * Updates the size of the canvas, regarding to the containg shapes. + */ + updateSize: function () { + // Check the size for the canvas + var maxWidth = 0; + var maxHeight = 0; + var offset = 100; + this.getChildShapes(true, function (shape) { + var b = shape.bounds; + maxWidth = Math.max(maxWidth, b.lowerRight().x + offset) + maxHeight = Math.max(maxHeight, b.lowerRight().y + offset) + }); + + if (this.bounds.width() < maxWidth || this.bounds.height() < maxHeight) { + this.setSize({ + width: Math.max(this.bounds.width(), maxWidth), + height: Math.max(this.bounds.height(), maxHeight) + }) + } + }, + + getRootNode: function () { + return this.rootNode; + }, + + getUnderlayNode: function () { + return this.underlayNode; + }, + + getSvgContainer: function () { + return this.node.childNodes[1]; + }, + + getHTMLContainer: function () { + return this._htmlContainer; + }, + + /** + * Return all elements of the same highest level + * @param {Object} elements + */ + getShapesWithSharedParent: function (elements) { + + // If there is no elements, return [] + if (!elements || elements.length < 1) { + return []; + } + // If there is one element, return this element + if (elements.length == 1) { + return elements; + } + + return elements.findAll(function (value) { + var parentShape = value.parent; + while (parentShape) { + if (elements.member(parentShape)) return false; + parentShape = parentShape.parent; + } + return true; + }); + + }, + + setSize: function (size, dontSetBounds) { + if (!size || !size.width || !size.height) { + return; + } + ; + + if (this.rootNode.parentNode) { + this.rootNode.parentNode.style.width = size.width + 'px'; + this.rootNode.parentNode.style.height = size.height + 'px'; + } + + this.rootNode.setAttributeNS(null, 'width', size.width); + this.rootNode.setAttributeNS(null, 'height', size.height); + + //this._htmlContainer.style.top = "-" + (size.height + 4) + 'px'; + if (!dontSetBounds) { + this.bounds.set({a: {x: 0, y: 0}, b: {x: size.width / this.zoomLevel, y: size.height / this.zoomLevel}}); + } + }, + + /** + * Returns an SVG document of the current process. + * @param {Boolean} escapeText Use true, if you want to parse it with an XmlParser, + * false, if you want to use the SVG document in browser on client side. + */ + getSVGRepresentation: function (escapeText) { + // Get the serialized svg image source + var svgClone = this.getRootNode().cloneNode(true); + + this._removeInvisibleElements(svgClone); + + var x1, y1, x2, y2; + this.getChildShapes(true).each(function (shape) { + var absBounds = shape.absoluteBounds(); + var ul = absBounds.upperLeft(); + var lr = absBounds.lowerRight(); + if (x1 == undefined) { + x1 = ul.x; + y1 = ul.y; + x2 = lr.x; + y2 = lr.y; + } else { + x1 = Math.min(x1, ul.x); + y1 = Math.min(y1, ul.y); + x2 = Math.max(x2, lr.x); + y2 = Math.max(y2, lr.y); + } + }); + + var margin = 50; + var width, height, tx, ty; + if (x1 == undefined) { + width = 0; + height = 0; + tx = 0; + ty = 0; + } else { + width = x2; + height = y2; + tx = -x1 + margin / 2; + ty = -y1 + margin / 2; + } + + // Set the width and height + svgClone.setAttributeNS(null, 'width', width + margin); + svgClone.setAttributeNS(null, 'height', height + margin); + + //remove scale factor + svgClone.childNodes[1].removeAttributeNS(null, 'transform'); + + try { + var svgCont = svgClone.childNodes[1].childNodes[1]; + svgCont.parentNode.removeChild(svgCont); + } catch (e) { + } + + if (escapeText) { + $A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'tspan')).each(function (elem) { + elem.textContent = elem.textContent.escapeHTML(); + }); + + $A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'text')).each(function (elem) { + if (elem.childNodes.length == 0) + elem.textContent = elem.textContent.escapeHTML(); + }); + } + + // generating absolute urls for the pdf-exporter + $A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'image')).each(function (elem) { + var href = elem.getAttributeNS("http://www.w3.org/1999/xlink", "href"); + + if (!href.match("^(http|https)://")) { + href = window.location.protocol + "//" + window.location.host + href; + elem.setAttributeNS("http://www.w3.org/1999/xlink", "href", href); + } + }); + + + // escape all links + $A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'a')).each(function (elem) { + elem.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", (elem.getAttributeNS("http://www.w3.org/1999/xlink", "href") || "").escapeHTML()); + }); + + return svgClone; + }, + + /** + * Removes all nodes (and its children) that has the + * attribute visibility set to "hidden" + */ + _removeInvisibleElements: function (element) { + var index = 0; + while (index < element.childNodes.length) { + var child = element.childNodes[index]; + if (child.getAttributeNS && + child.getAttributeNS(null, "visibility") === "hidden") { + element.removeChild(child); + } else { + this._removeInvisibleElements(child); + index++; + } + } + + }, + + /** + * This method checks all shapes on the canvas and removes all shapes that + * contain invalid bounds values or dockers values(NaN) + */ + /*cleanUp: function(parent) { + if (!parent) { + parent = this; + } + parent.getChildShapes().each(function(shape){ + var a = shape.bounds.a; + var b = shape.bounds.b; + if (isNaN(a.x) || isNaN(a.y) || isNaN(b.x) || isNaN(b.y)) { + parent.remove(shape); + } + else { + shape.getDockers().any(function(docker) { + a = docker.bounds.a; + b = docker.bounds.b; + if (isNaN(a.x) || isNaN(a.y) || isNaN(b.x) || isNaN(b.y)) { + parent.remove(shape); + return true; + } + return false; + }); + shape.getMagnets().any(function(magnet) { + a = magnet.bounds.a; + b = magnet.bounds.b; + if (isNaN(a.x) || isNaN(a.y) || isNaN(b.x) || isNaN(b.y)) { + parent.remove(shape); + return true; + } + return false; + }); + this.cleanUp(shape); + } + }.bind(this)); + },*/ + + _delegateEvent: function (event) { + if (this.eventHandlerCallback && (event.target == this.rootNode || event.target == this.rootNode.parentNode)) { + this.eventHandlerCallback(event, this); + } + }, + + toString: function () { + return "Canvas " + this.id + }, + + /** + * Calls {@link ORYX.Core.AbstractShape#toJSON} and adds some stencil set information. + */ + toJSON: function () { + var json = arguments.callee.$.toJSON.apply(this, arguments); + +// if(ORYX.CONFIG.STENCILSET_HANDLER.length > 0) { +// json.stencilset = { +// url: this.getStencil().stencilSet().namespace() +// }; +// } else { + json.stencilset = { + url: this.getStencil().stencilSet().source(), + namespace: this.getStencil().stencilSet().namespace() + }; +// } + + + return json; + } +});/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +var idCounter = 0; +var ID_PREFIX = "resource"; + +/** + * Main initialization method. To be called when loading + * of the document, including all scripts, is completed. + */ +function init() { + + ORYX.Log.debug("Querying editor instances"); + + // Hack for WebKit to set the SVGElement-Classes + ORYX.Editor.setMissingClasses(); + + // If someone wants to create the editor instance himself + if (window.onOryxResourcesLoaded) { + window.onOryxResourcesLoaded(); + } + // Else fetch the model from server and display editor + else { + var modelId = window.location.search.substring(4); + var modelUrl = "./service/model/" + modelId + "/json"; + + ORYX.Editor.createByUrl(modelUrl); + } +} + +/** + @namespace Global Oryx name space + @name ORYX + */ +if (!ORYX) { + var ORYX = {}; +} + +/** + * The Editor class. + * @class ORYX.Editor + * @extends Clazz + * @param {Object} config An editor object, passed to {@link ORYX.Editor#loadSerialized} + * @param {String} config.id Any ID that can be used inside the editor. If fullscreen=false, any HTML node with this id must be present to render the editor to this node. + * @param {boolean} [config.fullscreen=true] Render editor in fullscreen mode or not. + * @param {String} config.stencilset.url Stencil set URL. + * @param {String} [config.stencil.id] Stencil type used for creating the canvas. + * @param {Object} config.properties Any properties applied to the canvas. + */ +ORYX.Editor = { + /** @lends ORYX.Editor.prototype */ + // Defines the global dom event listener + DOMEventListeners: new Hash(), + + // Defines the selection + selection: [], + + // Defines the current zoom level + zoomLevel: 1.0, + + construct: function (config) { + + // initialization. + this._eventsQueue = []; + this.loadedPlugins = []; + this.pluginsData = []; + + + //meta data about the model for the signavio warehouse + //directory, new, name, description, revision, model (the model data) + + this.modelMetaData = config; + + var model = config; + + this.id = model.modelId; + + if (config.model) { + model = config.model; + } + + if (!this.id) { + this.id = model.id; + if (!this.id) { + this.id = ORYX.Editor.provideId(); + } + } + + // Defines if the editor should be fullscreen or not + this.fullscreen = config.fullscreen !== false; + + // Initialize the eventlistener + this._initEventListener(); + + // Load particular stencilset + if (ORYX.CONFIG.BACKEND_SWITCH) { + var ssUrl = (model.stencilset.namespace || model.stencilset.url).replace("#", "%23"); + ORYX.Core.StencilSet.loadStencilSet(ssUrl, this.modelMetaData, this.id); + } else { + var ssUrl = model.stencilset.url; + ORYX.Core.StencilSet.loadStencilSet(ssUrl, this.modelMetaData, this.id); + } + + // CREATES the canvas + this._createCanvas(model.stencil ? model.stencil.id : null, model.properties); + + // GENERATES the whole EXT.VIEWPORT + this._generateGUI(); + + // Initializing of a callback to check loading ends + var loadPluginFinished = false; + var loadContentFinished = false; + var initFinished = function () { + if (!loadPluginFinished || !loadContentFinished) { + return + } + this._finishedLoading(); + }.bind(this) + + // LOAD the plugins + window.setTimeout(function () { + this.loadPlugins(); + loadPluginFinished = true; + initFinished(); + }.bind(this), 100); + + // LOAD the content of the current editor instance + window.setTimeout(function () { + this.loadSerialized(model, true); // Request the meta data as well + this.getCanvas().update(); + loadContentFinished = true; + initFinished(); + }.bind(this), 200); + }, + + _finishedLoading: function () { + // Raise Loaded Event + this.handleEvents({type: ORYX.CONFIG.EVENT_LOADED}) + }, + + _initEventListener: function () { + + // Register on Events + + document.documentElement.addEventListener(ORYX.CONFIG.EVENT_KEYDOWN, this.catchKeyDownEvents.bind(this), false); + document.documentElement.addEventListener(ORYX.CONFIG.EVENT_KEYUP, this.catchKeyUpEvents.bind(this), false); + + // Enable Key up and down Event + this._keydownEnabled = true; + this._keyupEnabled = true; + + this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEDOWN] = []; + this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEUP] = []; + this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEOVER] = []; + this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEOUT] = []; + this.DOMEventListeners[ORYX.CONFIG.EVENT_SELECTION_CHANGED] = []; + this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEMOVE] = []; + + }, + + /** + * Generate the whole viewport of the + * Editor and initialized the Ext-Framework + * + */ + _generateGUI: function () { + + // Defines the layout height if it's NOT fullscreen + var layoutHeight = ORYX.CONFIG.WINDOW_HEIGHT; + var canvasParent = this.getCanvas().rootNode.parentNode; + + jQuery("#canvasSection").append(canvasParent); + + // Set the editor to the center, and refresh the size + canvasParent.parentNode.setAttributeNS(null, 'align', 'center'); + canvasParent.setAttributeNS(null, 'align', 'left'); + this.getCanvas().setSize({ + width: ORYX.CONFIG.CANVAS_WIDTH, + height: ORYX.CONFIG.CANVAS_HEIGHT + }); + + }, + + getAvailablePlugins: function () { + var curAvailablePlugins = ORYX.availablePlugins.clone(); + curAvailablePlugins.each(function (plugin) { + if (this.loadedPlugins.find(function (loadedPlugin) { + return loadedPlugin.type == this.name; + }.bind(plugin))) { + plugin.engaged = true; + } else { + plugin.engaged = false; + } + }.bind(this)); + return curAvailablePlugins; + }, + + loadScript: function (url, callback) { + var script = document.createElement("script") + script.type = "text/javascript"; + if (script.readyState) { //IE + script.onreadystatechange = function () { + if (script.readyState == "loaded" || script.readyState == "complete") { + script.onreadystatechange = null; + callback(); + } + }; + } else { //Others + script.onload = function () { + callback(); + }; + } + script.src = url; + document.getElementsByTagName("head")[0].appendChild(script); + }, + /** + * activate Plugin + * + * @param {String} name + * @param {Function} callback + * callback(sucess, [errorCode]) + * errorCodes: NOTUSEINSTENCILSET, REQUIRESTENCILSET, NOTFOUND, YETACTIVATED + */ + activatePluginByName: function (name, callback, loadTry) { + + var match = this.getAvailablePlugins().find(function (value) { + return value.name == name + }); + if (match && (!match.engaged || (match.engaged === 'false'))) { + var loadedStencilSetsNamespaces = this.getStencilSets().keys(); + var facade = this._getPluginFacade(); + var newPlugin; + var me = this; + ORYX.Log.debug("Initializing plugin '%0'", match.name); + + if (!match.requires || !match.requires.namespaces || match.requires.namespaces.any(function (req) { + return loadedStencilSetsNamespaces.indexOf(req) >= 0 + })) { + if (!match.notUsesIn || !match.notUsesIn.namespaces || !match.notUsesIn.namespaces.any(function (req) { + return loadedStencilSetsNamespaces.indexOf(req) >= 0 + })) { + + try { + + var className = eval(match.name); + var newPlugin = new className(facade, match); + newPlugin.type = match.name; + + // If there is an GUI-Plugin, they get all Plugins-Offer-Meta-Data + if (newPlugin.registryChanged) + newPlugin.registryChanged(me.pluginsData); + + // If there have an onSelection-Method it will pushed to the Editor Event-Handler + if (newPlugin.onSelectionChanged) + me.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, newPlugin.onSelectionChanged.bind(newPlugin)); + this.loadedPlugins.push(newPlugin); + this.loadedPlugins.each(function (loaded) { + if (loaded.registryChanged) + loaded.registryChanged(this.pluginsData); + }.bind(me)); + callback(true); + + } catch (e) { + ORYX.Log.warn("Plugin %0 is not available", match.name); + if (!!loadTry) { + callback(false, "INITFAILED"); + return; + } + this.loadScript("plugins/scripts/" + match.source, this.activatePluginByName.bind(this, match.name, callback, true)); + } + } else { + callback(false, "NOTUSEINSTENCILSET"); + ORYX.Log.info("Plugin need a stencilset which is not loaded'", match.name); + } + + } else { + callback(false, "REQUIRESTENCILSET"); + ORYX.Log.info("Plugin need a stencilset which is not loaded'", match.name); + } + + + } else { + callback(false, match ? "NOTFOUND" : "YETACTIVATED"); + //TODO error handling + } + }, + + /** + * Laden der Plugins + */ + loadPlugins: function () { + + // if there should be plugins but still are none, try again. + // TODO this should wait for every plugin respectively. + /*if (!ORYX.Plugins && ORYX.availablePlugins.length > 0) { + window.setTimeout(this.loadPlugins.bind(this), 100); + return; + }*/ + + var me = this; + var newPlugins = []; + + + var loadedStencilSetsNamespaces = this.getStencilSets().keys(); + + // Available Plugins will be initalize + var facade = this._getPluginFacade(); + + // If there is an Array where all plugins are described, than only take those + // (that comes from the usage of oryx with a mashup api) + if (ORYX.MashupAPI && ORYX.MashupAPI.loadablePlugins && ORYX.MashupAPI.loadablePlugins instanceof Array) { + + // Get the plugins from the available plugins (those who are in the plugins.xml) + ORYX.availablePlugins = $A(ORYX.availablePlugins).findAll(function (value) { + return ORYX.MashupAPI.loadablePlugins.include(value.name) + }) + + // Add those plugins to the list, which are only in the loadablePlugins list + ORYX.MashupAPI.loadablePlugins.each(function (className) { + if (!(ORYX.availablePlugins.find(function (val) { + return val.name == className + }))) { + ORYX.availablePlugins.push({name: className}); + } + }) + } + + + ORYX.availablePlugins.each(function (value) { + ORYX.Log.debug("Initializing plugin '%0'", value.name); + if ((!value.requires || !value.requires.namespaces || value.requires.namespaces.any(function (req) { + return loadedStencilSetsNamespaces.indexOf(req) >= 0 + })) && + (!value.notUsesIn || !value.notUsesIn.namespaces || !value.notUsesIn.namespaces.any(function (req) { + return loadedStencilSetsNamespaces.indexOf(req) >= 0 + })) && + /*only load activated plugins or undefined */ + (value.engaged || (value.engaged === undefined))) { + + try { + var className = eval(value.name); + if (className) { + var plugin = new className(facade, value); + plugin.type = value.name; + newPlugins.push(plugin); + plugin.engaged = true; + } + } catch (e) { + ORYX.Log.warn("Plugin %0 is not available %1", value.name, e); + } + + } else { + ORYX.Log.info("Plugin need a stencilset which is not loaded'", value.name); + } + + }); + + newPlugins.each(function (value) { + // If there is an GUI-Plugin, they get all Plugins-Offer-Meta-Data + if (value.registryChanged) + value.registryChanged(me.pluginsData); + + // If there have an onSelection-Method it will pushed to the Editor Event-Handler + if (value.onSelectionChanged) + me.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, value.onSelectionChanged.bind(value)); + }); + + this.loadedPlugins = newPlugins; + + this.registerPluginsOnKeyEvents(); + + this.setSelection(); + + }, + + /** + * Creates the Canvas + * @param {String} [stencilType] The stencil type used for creating the canvas. If not given, a stencil with myBeRoot = true from current stencil set is taken. + * @param {Object} [canvasConfig] Any canvas properties (like language). + */ + _createCanvas: function (stencilType, canvasConfig) { + if (stencilType) { + // Add namespace to stencilType + if (stencilType.search(/^http/) === -1) { + stencilType = this.getStencilSets().values()[0].namespace() + stencilType; + } + } else { + // Get any root stencil type + stencilType = this.getStencilSets().values()[0].findRootStencilName(); + } + + // get the stencil associated with the type + var canvasStencil = ORYX.Core.StencilSet.stencil(stencilType); + + if (!canvasStencil) + ORYX.Log.fatal("Initialisation failed, because the stencil with the type %0 is not part of one of the loaded stencil sets.", stencilType); + + // create all dom + // TODO fix border, so the visible canvas has a double border and some spacing to the scrollbars + var div = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", null, ['div']); + // set class for custom styling + div.addClassName("ORYX_Editor"); + + // create the canvas + this._canvas = new ORYX.Core.Canvas({ + width: ORYX.CONFIG.CANVAS_WIDTH, + height: ORYX.CONFIG.CANVAS_HEIGHT, + 'eventHandlerCallback': this.handleEvents.bind(this), + id: this.id, + parentNode: div + }, canvasStencil, this._getPluginFacade()); + + if (canvasConfig) { + // Migrate canvasConfig to an RDF-like structure + //FIXME this isn't nice at all because we don't want rdf any longer + var properties = []; + for (field in canvasConfig) { + properties.push({ + prefix: 'oryx', + name: field, + value: canvasConfig[field] + }); + } + + this._canvas.deserialize(properties); + } + + }, + + /** + * Returns a per-editor singleton plugin facade. + * To be used in plugin initialization. + */ + _getPluginFacade: function () { + + // if there is no pluginfacade already created: + if (!(this._pluginFacade)) + + // create it. + this._pluginFacade = { + + activatePluginByName: this.activatePluginByName.bind(this), + //deactivatePluginByName: this.deactivatePluginByName.bind(this), + getAvailablePlugins: this.getAvailablePlugins.bind(this), + offer: this.offer.bind(this), + getStencilSets: this.getStencilSets.bind(this), + getStencilSetExtensionDefinition: function () { + return Object.clone(this.ss_extensions_def || {}) + }.bind(this), + getRules: this.getRules.bind(this), + loadStencilSet: this.loadStencilSet.bind(this), + createShape: this.createShape.bind(this), + deleteShape: this.deleteShape.bind(this), + getSelection: this.getSelection.bind(this), + setSelection: this.setSelection.bind(this), + updateSelection: this.updateSelection.bind(this), + getCanvas: this.getCanvas.bind(this), + + importJSON: this.importJSON.bind(this), + getJSON: this.getJSON.bind(this), + getSerializedJSON: this.getSerializedJSON.bind(this), + + executeCommands: this.executeCommands.bind(this), + isExecutingCommands: this.isExecutingCommands.bind(this), + + registerOnEvent: this.registerOnEvent.bind(this), + unregisterOnEvent: this.unregisterOnEvent.bind(this), + raiseEvent: this.handleEvents.bind(this), + enableEvent: this.enableEvent.bind(this), + disableEvent: this.disableEvent.bind(this), + + eventCoordinates: this.eventCoordinates.bind(this), + eventCoordinatesXY: this.eventCoordinatesXY.bind(this), + + getModelMetaData: this.getModelMetaData.bind(this) + }; + + // return it. + return this._pluginFacade; + }, + + isExecutingCommands: function () { + return !!this.commandExecuting; + }, + + /** + * Implementes the command pattern + * (The real usage of the command pattern + * is implemented and shown in the Plugins/undo.js) + * + * @param [] Array of commands + */ + executeCommands: function (commands) { + + if (!this.commandStack) { + this.commandStack = []; + } + if (!this.commandStackExecuted) { + this.commandStackExecuted = []; + } + + + this.commandStack = [].concat(this.commandStack) + .concat(commands); + + // Check if already executes + if (this.commandExecuting) { + return; + } + + // Start execution + this.commandExecuting = true; + + // Iterate over all commands + while (this.commandStack.length > 0) { + var command = this.commandStack.shift(); + // and execute it + command.execute(); + this.commandStackExecuted.push(command); + } + + // Raise event for executing commands + this.handleEvents({ + type: ORYX.CONFIG.EVENT_EXECUTE_COMMANDS, + commands: this.commandStackExecuted + }); + + // Remove temporary vars + delete this.commandStack; + delete this.commandStackExecuted; + delete this.commandExecuting; + + + this.updateSelection(); + + }, + + /** + * Returns JSON of underlying canvas (calls ORYX.Canvas#toJSON()). + * @return {Object} Returns JSON representation as JSON object. + */ + getJSON: function () { + delete Array.prototype.toJSON; + var canvasJSON = this.getCanvas().toJSON(); + canvasJSON.ssextensions = this.getStencilSets().values()[0].extensions().keys().findAll(function (sse) { + return !sse.endsWith('/meta#') + }); + return canvasJSON; + }, + + /** + * Serializes a call to toJSON(). + * @return {String} Returns JSON representation as string. + */ + getSerializedJSON: function () { + return JSON.stringify(this.getJSON()); + }, + + /** + * Imports shapes in JSON as expected by {@link ORYX.Editor#loadSerialized} + * @param {Object|String} jsonObject The (serialized) json object to be imported + * @param {boolean } [noSelectionAfterImport=false] Set to true if no shapes should be selected after import + * @throws {SyntaxError} If the serialized json object contains syntax errors + */ + importJSON: function (jsonObject, noSelectionAfterImport) { + + try { + jsonObject = this.renewResourceIds(jsonObject); + } catch (error) { + throw error; + } + //check, if the imported json model can be loaded in this editor + // (stencil set has to fit) + if (jsonObject.stencilset.namespace && jsonObject.stencilset.namespace !== this.getCanvas().getStencil().stencilSet().namespace()) { + alert(String.format(ORYX.I18N.JSONImport.wrongSS, jsonObject.stencilset.namespace, this.getCanvas().getStencil().stencilSet().namespace())); + return null; + } else { + var commandClass = ORYX.Core.Command.extend({ + construct: function (jsonObject, loadSerializedCB, noSelectionAfterImport, facade) { + this.jsonObject = jsonObject; + this.noSelection = noSelectionAfterImport; + this.facade = facade; + this.shapes; + this.connections = []; + this.parents = new Hash(); + this.selection = this.facade.getSelection(); + this.loadSerialized = loadSerializedCB; + }, + execute: function () { + + if (!this.shapes) { + // Import the shapes out of the serialization + this.shapes = this.loadSerialized(this.jsonObject); + + //store all connections + this.shapes.each(function (shape) { + + if (shape.getDockers) { + var dockers = shape.getDockers(); + if (dockers) { + if (dockers.length > 0) { + this.connections.push([dockers.first(), dockers.first().getDockedShape(), dockers.first().referencePoint]); + } + if (dockers.length > 1) { + this.connections.push([dockers.last(), dockers.last().getDockedShape(), dockers.last().referencePoint]); + } + } + } + + //store parents + this.parents[shape.id] = shape.parent; + }.bind(this)); + } else { + this.shapes.each(function (shape) { + this.parents[shape.id].add(shape); + }.bind(this)); + + this.connections.each(function (con) { + con[0].setDockedShape(con[1]); + con[0].setReferencePoint(con[2]); + con[0].update(); + }); + } + + //this.parents.values().uniq().invoke("update"); + this.facade.getCanvas().update(); + + if (!this.noSelection) + this.facade.setSelection(this.shapes); + else + this.facade.updateSelection(); + + // call updateSize again, because during loadSerialized the edges' bounds + // are not yet initialized properly + this.facade.getCanvas().updateSize(); + + }, + rollback: function () { + var selection = this.facade.getSelection(); + + this.shapes.each(function (shape) { + selection = selection.without(shape); + this.facade.deleteShape(shape); + }.bind(this)); + + /*this.parents.values().uniq().each(function(parent) { + if(!this.shapes.member(parent)) + parent.update(); + }.bind(this));*/ + + this.facade.getCanvas().update(); + + this.facade.setSelection(selection); + } + }) + + var command = new commandClass(jsonObject, + this.loadSerialized.bind(this), + noSelectionAfterImport, + this._getPluginFacade()); + + this.executeCommands([command]); + + return command.shapes.clone(); + } + }, + + /** + * This method renew all resource Ids and according references. + * Warning: The implementation performs a substitution on the serialized object for + * easier implementation. This results in a low performance which is acceptable if this + * is only used when importing models. + * @param {Object|String} jsonObject + * @throws {SyntaxError} If the serialized json object contains syntax errors. + * @return {Object} The jsonObject with renewed ids. + * @private + */ + renewResourceIds: function (jsonObject) { + // For renewing resource ids, a serialized and object version is needed + if (Object.prototype.toString.call(jsonObject) === "String") { + try { + var serJsonObject = jsonObject; + jsonObject = JSON.parse(jsonObject); + } catch (error) { + throw new SyntaxError(error.message); + } + } else { + var serJsonObject = JSON.stringify(jsonObject); + } + + // collect all resourceIds recursively + var collectResourceIds = function (shapes) { + if (!shapes) return []; + + return shapes.map(function (shape) { + return collectResourceIds(shape.childShapes).concat(shape.resourceId); + }).flatten(); + } + var resourceIds = collectResourceIds(jsonObject.childShapes); + + // Replace each resource id by a new one + resourceIds.each(function (oldResourceId) { + var newResourceId = ORYX.Editor.provideId(); + serJsonObject = serJsonObject.replace(new RegExp(oldResourceId, 'g'), newResourceId); + }); + + return JSON.parse(serJsonObject); + }, + + /** + * Loads serialized model to the oryx. + * @example + * editor.loadSerialized({ + * resourceId: "mymodel1", + * childShapes: [ + * { + * stencil:{ id:"Subprocess" }, + * outgoing:[{resourceId: 'aShape'}], + * target: {resourceId: 'aShape'}, + * bounds:{ lowerRight:{ y:510, x:633 }, upperLeft:{ y:146, x:210 } }, + * resourceId: "myshape1", + * childShapes:[], + * properties:{}, + * } + * ], + * properties:{ + * language: "English" + * }, + * stencilset:{ + * url:"http://localhost:8080/oryx/stencilsets/bpmn1.1/bpmn1.1.json" + * }, + * stencil:{ + * id:"BPMNDiagram" + * } + * }); + * @param {Object} model Description of the model to load. + * @param {Array} [model.ssextensions] List of stenctil set extensions. + * @param {String} model.stencilset.url + * @param {String} model.stencil.id + * @param {Array} model.childShapes + * @param {Array} [model.properties] + * @param {String} model.resourceId + * @return {ORYX.Core.Shape[]} List of created shapes + * @methodOf ORYX.Editor.prototype + */ + loadSerialized: function (model, requestMeta) { + var canvas = this.getCanvas(); + + // Bugfix (cf. http://code.google.com/p/oryx-editor/issues/detail?id=240) + // Deserialize the canvas' stencil set extensions properties first! + this.loadSSExtensions(model.ssextensions); + + // Load Meta Data Extension if available + // #Signavio + if (requestMeta === true) { + var metaDataExtension = this.getExtensionForMetaData(); + if (metaDataExtension) { + this.loadSSExtension(metaDataExtension); + } + } + + var shapes = this.getCanvas().addShapeObjects(model.childShapes, this.handleEvents.bind(this)); + + if (model.properties) { + for (key in model.properties) { + var value = model.properties[key]; + var prop = this.getCanvas().getStencil().property("oryx-" + key); + if (!(typeof value === "string") && (!prop || !prop.isList())) { + value = JSON.stringify(value); + } + this.getCanvas().setProperty("oryx-" + key, value); + } + } + + + this.getCanvas().updateSize(); + + // Force to update the selection + this.selection = [null]; + this.setSelection([]); + + return shapes; + }, + + /** + * Return the namespace of the extension which + * provided all the self defined meta data + * @return {String} Returns null if no extension is defined, otherwise the namespace + * + */ + getExtensionForMetaData: function () { + if (!this.ss_extensions_def || !(this.ss_extensions_def.extensions instanceof Array)) { + return null; + } + + var stencilsets = this.getStencilSets(); + var extension = this.ss_extensions_def.extensions.find(function (ex) { + return !!stencilsets[ex["extends"]] && ex.namespace.endsWith("/meta#"); + }); + + return extension ? extension.namespace || null : null; + }, + + /** + * Calls ORYX.Editor.prototype.ss_extension_namespace for each element + * @param {Array} ss_extension_namespaces An array of stencil set extension namespaces. + */ + loadSSExtensions: function (ss_extension_namespaces) { + if (!ss_extension_namespaces) return; + + ss_extension_namespaces.each(function (ss_extension_namespace) { + this.loadSSExtension(ss_extension_namespace); + }.bind(this)); + }, + + /** + * Loads a stencil set extension. + * The stencil set extensions definiton file must already + * be loaded when the editor is initialized. + */ + loadSSExtension: function (ss_extension_namespace) { + + if (this.ss_extensions_def) { + var extension = this.ss_extensions_def.extensions.find(function (ex) { + return (ex.namespace == ss_extension_namespace); + }); + + if (!extension) { + return; + } + + var stencilset = this.getStencilSets()[extension["extends"]]; + + if (!stencilset) { + return; + } + + // Check if absolute or relative url + if ((extension["definition"] || "").startsWith("/")) { + stencilset.addExtension(extension["definition"]) + } else { + stencilset.addExtension(ORYX.CONFIG.SS_EXTENSIONS_FOLDER + extension["definition"]) + } + + //stencilset.addExtension("/oryx/build/stencilsets/extensions/" + extension["definition"]) + this.getRules().initializeRules(stencilset); + + this._getPluginFacade().raiseEvent({ + type: ORYX.CONFIG.EVENT_STENCIL_SET_LOADED + }); + } + + }, + + disableEvent: function (eventType) { + if (eventType == ORYX.CONFIG.EVENT_KEYDOWN) { + this._keydownEnabled = false; + } + if (eventType == ORYX.CONFIG.EVENT_KEYUP) { + this._keyupEnabled = false; + } + if (this.DOMEventListeners.keys().member(eventType)) { + var value = this.DOMEventListeners.remove(eventType); + this.DOMEventListeners['disable_' + eventType] = value; + } + }, + + enableEvent: function (eventType) { + if (eventType == ORYX.CONFIG.EVENT_KEYDOWN) { + this._keydownEnabled = true; + } + + if (eventType == ORYX.CONFIG.EVENT_KEYUP) { + this._keyupEnabled = true; + } + + if (this.DOMEventListeners.keys().member("disable_" + eventType)) { + var value = this.DOMEventListeners.remove("disable_" + eventType); + this.DOMEventListeners[eventType] = value; + } + }, + + /** + * Methods for the PluginFacade + */ + registerOnEvent: function (eventType, callback) { + if (!(this.DOMEventListeners.keys().member(eventType))) { + this.DOMEventListeners[eventType] = []; + } + + this.DOMEventListeners[eventType].push(callback); + }, + + unregisterOnEvent: function (eventType, callback) { + if (this.DOMEventListeners.keys().member(eventType)) { + this.DOMEventListeners[eventType] = this.DOMEventListeners[eventType].without(callback); + } else { + // Event is not supported + // TODO: Error Handling + } + }, + + getSelection: function () { + return this.selection || []; + }, + + getStencilSets: function () { + return ORYX.Core.StencilSet.stencilSets(this.id); + }, + + getRules: function () { + return ORYX.Core.StencilSet.rules(this.id); + }, + + loadStencilSet: function (source) { + try { + ORYX.Core.StencilSet.loadStencilSet(source, this.modelMetaData, this.id); + this.handleEvents({type: ORYX.CONFIG.EVENT_STENCIL_SET_LOADED}); + } catch (e) { + ORYX.Log.warn("Requesting stencil set file failed. (" + e + ")"); + } + }, + + offer: function (pluginData) { + if (!this.pluginsData.member(pluginData)) { + this.pluginsData.push(pluginData); + } + }, + + /** + * It creates an new event or adds the callback, if already existing, + * for the key combination that the plugin passes in keyCodes attribute + * of the offer method. + * + * The new key down event fits the schema: + * key.event[.metactrl][.alt][.shift].'thekeyCode' + */ + registerPluginsOnKeyEvents: function () { + this.pluginsData.each(function (pluginData) { + + if (pluginData.keyCodes) { + + pluginData.keyCodes.each(function (keyComb) { + var eventName = "key.event"; + + /* Include key action */ + eventName += '.' + keyComb.keyAction; + + if (keyComb.metaKeys) { + /* Register on ctrl or apple meta key as meta key */ + if (keyComb.metaKeys.indexOf(ORYX.CONFIG.META_KEY_META_CTRL) > -1) { + eventName += "." + ORYX.CONFIG.META_KEY_META_CTRL; + } + + /* Register on alt key as meta key */ + if (keyComb.metaKeys.indexOf(ORYX.CONFIG.META_KEY_ALT) > -1) { + eventName += '.' + ORYX.CONFIG.META_KEY_ALT; + } + + /* Register on shift key as meta key */ + if (keyComb.metaKeys.indexOf(ORYX.CONFIG.META_KEY_SHIFT) > -1) { + eventName += '.' + ORYX.CONFIG.META_KEY_SHIFT; + } + } + + /* Register on the actual key */ + if (keyComb.keyCode) { + eventName += '.' + keyComb.keyCode; + } + + /* Register the event */ + ORYX.Log.debug("Register Plugin on Key Event: %0", eventName); + if (pluginData.toggle === true && pluginData.buttonInstance) { + this.registerOnEvent(eventName, function () { + pluginData.buttonInstance.toggle(!pluginData.buttonInstance.pressed); // Toggle + pluginData.functionality.call(pluginData, pluginData.buttonInstance, pluginData.buttonInstance.pressed); // Call function + }); + } else { + this.registerOnEvent(eventName, pluginData.functionality) + } + + }.bind(this)); + } + }.bind(this)); + }, + + isEqual: function (a, b) { + return a === b || (a.length === b.length && a.all(function (r) { + return b.include(r) + })) + }, + + isDirty: function (a) { + return a.any(function (shape) { + return shape.isPropertyChanged() + }) + }, + + setSelection: function (elements, subSelectionElement, force) { + + if (!elements) { + elements = []; + } + if (!(elements instanceof Array)) { + elements = [elements]; + } + + elements = elements.findAll(function (n) { + return n && n instanceof ORYX.Core.Shape + }); + + if (elements[0] instanceof ORYX.Core.Canvas) { + elements = []; + } + + if (!force && this.isEqual(this.selection, elements) && !this.isDirty(elements)) { + return; + } + + this.selection = elements; + this._subSelection = subSelectionElement; + + this.handleEvents({ + type: ORYX.CONFIG.EVENT_SELECTION_CHANGED, + elements: elements, + subSelection: subSelectionElement, + force: !!force + }) + }, + + updateSelection: function () { + this.setSelection(this.selection, this._subSelection, true); + /*var s = this.selection; + this.setSelection(); + this.setSelection(s);*/ + }, + + getCanvas: function () { + return this._canvas; + }, + + + /** + * option = { + * type: string, + * position: {x:int, y:int}, + * connectingType: uiObj-Class + * connectedShape: uiObj + * draggin: bool + * namespace: url + * parent: ORYX.Core.AbstractShape + * template: a template shape that the newly created inherits properties from. + * } + */ + createShape: function (option) { + + if (option && option.serialize && option.serialize instanceof Array) { + + var type = option.serialize.find(function (obj) { + return (obj.prefix + "-" + obj.name) == "oryx-type" + }); + var stencil = ORYX.Core.StencilSet.stencil(type.value); + + if (stencil.type() == 'node') { + var newShapeObject = new ORYX.Core.Node({'eventHandlerCallback': this.handleEvents.bind(this)}, stencil, this._getPluginFacade()); + } else { + var newShapeObject = new ORYX.Core.Edge({'eventHandlerCallback': this.handleEvents.bind(this)}, stencil, this._getPluginFacade()); + } + + this.getCanvas().add(newShapeObject); + newShapeObject.deserialize(option.serialize); + + return newShapeObject; + } + + // If there is no argument, throw an exception + if (!option || !option.type || !option.namespace) { + throw "To create a new shape you have to give an argument with type and namespace"; + } + + var canvas = this.getCanvas(); + var newShapeObject; + + // Get the shape type + var shapetype = option.type; + + // Get the stencil set + var sset = ORYX.Core.StencilSet.stencilSet(option.namespace); + // Create an New Shape, dependents on an Edge or a Node + if (sset.stencil(shapetype).type() == "node") { + newShapeObject = new ORYX.Core.Node({'eventHandlerCallback': this.handleEvents.bind(this)}, sset.stencil(shapetype), this._getPluginFacade()) + } else { + newShapeObject = new ORYX.Core.Edge({'eventHandlerCallback': this.handleEvents.bind(this)}, sset.stencil(shapetype), this._getPluginFacade()) + } + + // when there is a template, inherit the properties. + if (option.template) { + + newShapeObject._jsonStencil.properties = option.template._jsonStencil.properties; + newShapeObject.postProcessProperties(); + } + + // Add to the canvas + if (option.parent && newShapeObject instanceof ORYX.Core.Node) { + option.parent.add(newShapeObject); + } else { + canvas.add(newShapeObject); + } + + + // Set the position + var point = option.position ? option.position : {x: 100, y: 200}; + + + var con; + // If there is create a shape and in the argument there is given an ConnectingType and is instance of an edge + if (option.connectingType && option.connectedShape && !(newShapeObject instanceof ORYX.Core.Edge)) { + + // there will be create a new Edge + con = new ORYX.Core.Edge({'eventHandlerCallback': this.handleEvents.bind(this)}, sset.stencil(option.connectingType)); + + // And both endings dockers will be referenced to the both shapes + con.dockers.first().setDockedShape(option.connectedShape); + + var magnet = option.connectedShape.getDefaultMagnet() + var cPoint = magnet ? magnet.bounds.center() : option.connectedShape.bounds.midPoint(); + con.dockers.first().setReferencePoint(cPoint); + con.dockers.last().setDockedShape(newShapeObject); + con.dockers.last().setReferencePoint(newShapeObject.getDefaultMagnet().bounds.center()); + + // The Edge will be added to the canvas and be updated + canvas.add(con); + //con.update(); + + } + + // Move the new Shape to the position + if (newShapeObject instanceof ORYX.Core.Edge && option.connectedShape) { + + newShapeObject.dockers.first().setDockedShape(option.connectedShape); + + if (option.connectedShape instanceof ORYX.Core.Node) { + newShapeObject.dockers.first().setReferencePoint(option.connectedShape.getDefaultMagnet().bounds.center()); + newShapeObject.dockers.last().bounds.centerMoveTo(point); + } else { + newShapeObject.dockers.first().setReferencePoint(option.connectedShape.bounds.midPoint()); + } + + var start = newShapeObject.dockers.first(); + var end = newShapeObject.dockers.last(); + + if (start.getDockedShape() && end.getDockedShape()) { + var startPoint = start.getAbsoluteReferencePoint(); + var endPoint = end.getAbsoluteReferencePoint(); + + var docker = newShapeObject.createDocker(); + docker.bounds.centerMoveTo({ + x: startPoint.x + (endPont.x - startPoint.x) / 2, + y: startPoint.y + (endPont.y - startPoint.y) / 2 + }); + } + + } else { + + var b = newShapeObject.bounds + if (newShapeObject instanceof ORYX.Core.Node && newShapeObject.dockers.length == 1) { + b = newShapeObject.dockers.first().bounds + } + + b.centerMoveTo(point); + + var upL = b.upperLeft(); + b.moveBy(-Math.min(upL.x, 0), -Math.min(upL.y, 0)) + + var lwR = b.lowerRight(); + b.moveBy(-Math.max(lwR.x - canvas.bounds.width(), 0), -Math.max(lwR.y - canvas.bounds.height(), 0)) + + } + + // Update the shape + if (newShapeObject instanceof ORYX.Core.Edge) { + newShapeObject._update(false); + } + + // And refresh the selection + if (!(newShapeObject instanceof ORYX.Core.Edge) && !(option.dontUpdateSelection)) { + this.setSelection([newShapeObject]); + } + + if (con && con.alignDockers) { + //con.alignDockers(); + } + if (newShapeObject.alignDockers) { + newShapeObject.alignDockers(); + } + + return newShapeObject; + }, + + deleteShape: function (shape) { + + if (!shape || !shape.parent) { + return + } + + //remove shape from parent + // this also removes it from DOM + shape.parent.remove(shape); + + //delete references to outgoing edges + shape.getOutgoingShapes().each(function (os) { + var docker = os.getDockers().first(); + if (docker && docker.getDockedShape() == shape) { + docker.setDockedShape(undefined); + } + }); + + //delete references to incoming edges + shape.getIncomingShapes().each(function (is) { + var docker = is.getDockers().last(); + if (docker && docker.getDockedShape() == shape) { + docker.setDockedShape(undefined); + } + }); + + //delete references of the shape's dockers + shape.getDockers().each(function (docker) { + docker.setDockedShape(undefined); + }); + }, + + /** + * Returns an object with meta data about the model. + * Like name, description, ... + * + * Empty object with the current backend. + * + * @return {Object} Meta data about the model + */ + getModelMetaData: function () { + return this.modelMetaData; + }, + + /* Event-Handler Methods */ + + /** + * Helper method to execute an event immediately. The event is not + * scheduled in the _eventsQueue. Needed to handle Layout-Callbacks. + */ + _executeEventImmediately: function (eventObj) { + if (this.DOMEventListeners.keys().member(eventObj.event.type)) { + this.DOMEventListeners[eventObj.event.type].each((function (value) { + value(eventObj.event, eventObj.arg); + }).bind(this)); + } + }, + + _executeEvents: function () { + this._queueRunning = true; + while (this._eventsQueue.length > 0) { + var val = this._eventsQueue.shift(); + this._executeEventImmediately(val); + } + this._queueRunning = false; + }, + + /** + * Leitet die Events an die Editor-Spezifischen Event-Methoden weiter + * @param {Object} event Event , welches gefeuert wurde + * @param {Object} uiObj Target-UiObj + */ + handleEvents: function (event, uiObj) { + + ORYX.Log.trace("Dispatching event type %0 on %1", event.type, uiObj); + + switch (event.type) { + case ORYX.CONFIG.EVENT_MOUSEDOWN: + this._handleMouseDown(event, uiObj); + break; + case ORYX.CONFIG.EVENT_MOUSEMOVE: + this._handleMouseMove(event, uiObj); + break; + case ORYX.CONFIG.EVENT_MOUSEUP: + this._handleMouseUp(event, uiObj); + break; + case ORYX.CONFIG.EVENT_MOUSEOVER: + this._handleMouseHover(event, uiObj); + break; + case ORYX.CONFIG.EVENT_MOUSEOUT: + this._handleMouseOut(event, uiObj); + break; + } + /* Force execution if necessary. Used while handle Layout-Callbacks. */ + if (event.forceExecution) { + this._executeEventImmediately({event: event, arg: uiObj}); + } else { + this._eventsQueue.push({event: event, arg: uiObj}); + } + + if (!this._queueRunning) { + this._executeEvents(); + } + + // TODO: Make this return whether no listener returned false. + // So that, when one considers bubbling undesireable, it won't happen. + return false; + }, + + isValidEvent: function (e) { + try { + var isInput = ["INPUT", "TEXTAREA"].include(e.target.tagName.toUpperCase()); + var gridHasFocus = e.target.className.include("x-grid3-focus") && !e.target.className.include("x-grid3-focus-canvas"); + return !isInput && !gridHasFocus; + } catch (e) { + return false; + } + }, + + catchKeyUpEvents: function (event) { + if (!this._keyupEnabled) { + return; + } + /* assure we have the current event. */ + if (!event) + event = window.event; + + // Checks if the event comes from some input field + if (!this.isValidEvent(event)) { + return; + } + + /* Create key up event type */ + var keyUpEvent = this.createKeyCombEvent(event, ORYX.CONFIG.KEY_ACTION_UP); + + ORYX.Log.debug("Key Event to handle: %0", keyUpEvent); + + /* forward to dispatching. */ + this.handleEvents({type: keyUpEvent, event: event}); + }, + + /** + * Catches all key down events and forward the appropriated event to + * dispatching concerning to the pressed keys. + * + * @param {Event} + * The key down event to handle + */ + catchKeyDownEvents: function (event) { + if (!this._keydownEnabled) { + return; + } + /* Assure we have the current event. */ + if (!event) + event = window.event; + + /* Fixed in FF3 */ + // This is a mac-specific fix. The mozilla event object has no knowledge + // of meta key modifier on osx, however, it is needed for certain + // shortcuts. This fix adds the metaKey field to the event object, so + // that all listeners that registered per Oryx plugin facade profit from + // this. The original bug is filed in + // https://bugzilla.mozilla.org/show_bug.cgi?id=418334 + //if (this.__currentKey == ORYX.CONFIG.KEY_CODE_META) { + // event.appleMetaKey = true; + //} + //this.__currentKey = pressedKey; + + // Checks if the event comes from some input field + if (!this.isValidEvent(event)) { + return; + } + + /* Create key up event type */ + var keyDownEvent = this.createKeyCombEvent(event, ORYX.CONFIG.KEY_ACTION_DOWN); + + ORYX.Log.debug("Key Event to handle: %0", keyDownEvent); + + /* Forward to dispatching. */ + this.handleEvents({type: keyDownEvent, event: event}); + }, + + /** + * Creates the event type name concerning to the pressed keys. + * + * @param {Event} keyDownEvent + * The source keyDownEvent to build up the event name + */ + createKeyCombEvent: function (keyEvent, keyAction) { + + /* Get the currently pressed key code. */ + var pressedKey = keyEvent.which || keyEvent.keyCode; + //this.__currentKey = pressedKey; + + /* Event name */ + var eventName = "key.event"; + + /* Key action */ + if (keyAction) { + eventName += "." + keyAction; + } + + /* Ctrl or apple meta key is pressed */ + if (keyEvent.ctrlKey || keyEvent.metaKey) { + eventName += "." + ORYX.CONFIG.META_KEY_META_CTRL; + } + + /* Alt key is pressed */ + if (keyEvent.altKey) { + eventName += "." + ORYX.CONFIG.META_KEY_ALT; + } + + /* Alt key is pressed */ + if (keyEvent.shiftKey) { + eventName += "." + ORYX.CONFIG.META_KEY_SHIFT; + } + + /* Return the composed event name */ + return eventName + "." + pressedKey; + }, + + _handleMouseDown: function (event, uiObj) { + + // get canvas. + var canvas = this.getCanvas(); + // Try to get the focus + canvas.focus() + + // find the shape that is responsible for this element's id. + var element = event.currentTarget; + var elementController = uiObj; + + // gather information on selection. + var currentIsSelectable = (elementController !== null) && + (elementController !== undefined) && (elementController.isSelectable); + var currentIsMovable = (elementController !== null) && + (elementController !== undefined) && (elementController.isMovable); + var modifierKeyPressed = event.shiftKey || event.ctrlKey; + var noObjectsSelected = this.selection.length === 0; + var currentIsSelected = this.selection.member(elementController); + + + // Rule #1: When there is nothing selected, select the clicked object. + if (currentIsSelectable && noObjectsSelected) { + + this.setSelection([elementController]); + + ORYX.Log.trace("Rule #1 applied for mouse down on %0", element.id); + + // Rule #3: When at least one element is selected, and there is no + // control key pressed, and the clicked object is not selected, select + // the clicked object. + } else if (currentIsSelectable && !noObjectsSelected && + !modifierKeyPressed && !currentIsSelected) { + + this.setSelection([elementController]); + + //var objectType = elementController.readAttributes(); + //alert(objectType[0] + ": " + objectType[1]); + + ORYX.Log.trace("Rule #3 applied for mouse down on %0", element.id); + + // Rule #4: When the control key is pressed, and the current object is + // not selected, add it to the selection. + } else if (currentIsSelectable && modifierKeyPressed + && !currentIsSelected) { + + var newSelection = this.selection.clone(); + newSelection.push(elementController) + this.setSelection(newSelection) + + ORYX.Log.trace("Rule #4 applied for mouse down on %0", element.id); + + // Rule #6 + } else if (currentIsSelectable && currentIsSelected && + modifierKeyPressed) { + + var newSelection = this.selection.clone(); + this.setSelection(newSelection.without(elementController)) + + ORYX.Log.trace("Rule #6 applied for mouse down on %0", elementController.id); + + // Rule #5: When there is at least one object selected and no control + // key pressed, we're dragging. + /*} else if(currentIsSelectable && !noObjectsSelected + && !modifierKeyPressed) { + + if(this.log.isTraceEnabled()) + this.log.trace("Rule #5 applied for mouse down on "+element.id); +*/ + // Rule #2: When clicked on something that is neither + // selectable nor movable, clear the selection, and return. + } else if (!currentIsSelectable && !currentIsMovable) { + + this.setSelection([]); + + ORYX.Log.trace("Rule #2 applied for mouse down on %0", element.id); + + return; + + // Rule #7: When the current object is not selectable but movable, + // it is probably a control. Leave the selection unchanged but set + // the movedObject to the current one and enable Drag. Dockers will + // be processed in the dragDocker plugin. + } else if (!currentIsSelectable && currentIsMovable && !(elementController instanceof ORYX.Core.Controls.Docker)) { + + // TODO: If there is any moveable elements, do this in a plugin + //ORYX.Core.UIEnableDrag(event, elementController); + + ORYX.Log.trace("Rule #7 applied for mouse down on %0", element.id); + + // Rule #8: When the element is selectable and is currently selected and no + // modifier key is pressed + } else if (currentIsSelectable && currentIsSelected && + !modifierKeyPressed) { + + this._subSelection = this._subSelection != elementController ? elementController : undefined; + + this.setSelection(this.selection, this._subSelection); + + ORYX.Log.trace("Rule #8 applied for mouse down on %0", element.id); + } + + + // prevent event from bubbling, return. + //Event.stop(event); + return; + }, + + _handleMouseMove: function (event, uiObj) { + return; + }, + + _handleMouseUp: function (event, uiObj) { + // get canvas. + var canvas = this.getCanvas(); + + // find the shape that is responsible for this elemement's id. + var elementController = uiObj; + + //get event position + var evPos = this.eventCoordinates(event); + + //Event.stop(event); + }, + + _handleMouseHover: function (event, uiObj) { + return; + }, + + _handleMouseOut: function (event, uiObj) { + return; + }, + + /** + * Calculates the event coordinates to SVG document coordinates. + * @param {Event} event + * @return {SVGPoint} The event coordinates in the SVG document + */ + eventCoordinates: function (event) { + + var canvas = this.getCanvas(); + + var svgPoint = canvas.node.ownerSVGElement.createSVGPoint(); + svgPoint.x = event.clientX; + svgPoint.y = event.clientY; + + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + var ua = navigator.userAgent; + if (ua.indexOf('MSIE') >= 0) { + //IE 10 and below + var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); + if (zoom !== 100) { + additionalIEZoom = zoom / 100 + } + } + } + + if (additionalIEZoom !== 1) { + svgPoint.x = svgPoint.x * additionalIEZoom; + svgPoint.y = svgPoint.y * additionalIEZoom; + } + + var matrix = canvas.node.getScreenCTM(); + return svgPoint.matrixTransform(matrix.inverse()); + }, + + eventCoordinatesXY: function (x, y) { + + var canvas = this.getCanvas(); + + var svgPoint = canvas.node.ownerSVGElement.createSVGPoint(); + svgPoint.x = x; + svgPoint.y = y; + + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + var ua = navigator.userAgent; + if (ua.indexOf('MSIE') >= 0) { + //IE 10 and below + var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); + if (zoom !== 100) { + additionalIEZoom = zoom / 100 + } + } + } + + if (additionalIEZoom !== 1) { + svgPoint.x = svgPoint.x * additionalIEZoom; + svgPoint.y = svgPoint.y * additionalIEZoom; + } + + var matrix = canvas.node.getScreenCTM(); + return svgPoint.matrixTransform(matrix.inverse()); + } +}; +ORYX.Editor = Clazz.extend(ORYX.Editor); + +/** + * Creates a new ORYX.Editor instance by fetching a model from given url and passing it to the constructur + * @param {String} modelUrl The JSON URL of a model. + * @param {Object} config Editor config passed to the constructur, merged with the response of the request to modelUrl + */ +ORYX.Editor.createByUrl = function (modelUrl) { + new Ajax.Request(modelUrl, { + method: 'GET', + onSuccess: function (transport) { + var editorConfig = JSON.parse(transport.responseText); + new ORYX.Editor(editorConfig); + }.bind(this) + }); +} + +// TODO Implement namespace awareness on attribute level. +/** + * graft() function + * Originally by Sean M. Burke from interglacial.com, altered for usage with + * SVG and namespace (xmlns) support. Be sure you understand xmlns before + * using this funtion, as it creates all grafted elements in the xmlns + * provided by you and all element's attribures in default xmlns. If you + * need to graft elements in a certain xmlns and wish to assign attributes + * in both that and another xmlns, you will need to do stepwise grafting, + * adding non-default attributes yourself or you'll have to enhance this + * function. Latter, I would appreciate: martin???apfelfabrik.de + * @param {Object} namespace The namespace in which + * elements should be grafted. + * @param {Object} parent The element that should contain the grafted + * structure after the function returned. + * @param {Object} t the crafting structure. + * @param {Object} doc the document in which grafting is performed. + */ +ORYX.Editor.graft = function (namespace, parent, t, doc) { + + doc = (doc || (parent && parent.ownerDocument) || document); + var e; + if (t === undefined) { + throw "Can't graft an undefined value"; + } else if (t.constructor == String) { + e = doc.createTextNode(t); + } else { + for (var i = 0; i < t.length; i++) { + if (i === 0 && t[i].constructor == String) { + var snared; + snared = t[i].match(/^([a-z][a-z0-9]*)\.([^\s\.]+)$/i); + if (snared) { + e = doc.createElementNS(namespace, snared[1]); + e.setAttributeNS(null, 'class', snared[2]); + continue; + } + snared = t[i].match(/^([a-z][a-z0-9]*)$/i); + if (snared) { + e = doc.createElementNS(namespace, snared[1]); // but no class + continue; + } + + // Otherwise: + e = doc.createElementNS(namespace, "span"); + e.setAttribute(null, "class", "namelessFromLOL"); + } + + if (t[i] === undefined) { + throw "Can't graft an undefined value in a list!"; + } else if (t[i].constructor == String || t[i].constructor == Array) { + this.graft(namespace, e, t[i], doc); + } else if (t[i].constructor == Number) { + this.graft(namespace, e, t[i].toString(), doc); + } else if (t[i].constructor == Object) { + // hash's properties => element's attributes + for (var k in t[i]) { + e.setAttributeNS(null, k, t[i][k]); + } + } else { + + } + } + } + if (parent && parent.appendChild) { + parent.appendChild(e); + } else { + + } + return e; // return the topmost created node +}; + +ORYX.Editor.provideId = function () { + var res = [], hex = '0123456789ABCDEF'; + + for (var i = 0; i < 36; i++) res[i] = Math.floor(Math.random() * 0x10); + + res[14] = 4; + res[19] = (res[19] & 0x3) | 0x8; + + for (var i = 0; i < 36; i++) res[i] = hex[res[i]]; + + res[8] = res[13] = res[18] = res[23] = '-'; + + return "oryx_" + res.join(''); +}; + +/** + * When working with Ext, conditionally the window needs to be resized. To do + * so, use this class method. Resize is deferred until 100ms, and all subsequent + * resizeBugFix calls are ignored until the initially requested resize is + * performed. + */ +ORYX.Editor.resizeFix = function () { + if (!ORYX.Editor._resizeFixTimeout) { + ORYX.Editor._resizeFixTimeout = window.setTimeout(function () { + window.resizeBy(1, 1); + window.resizeBy(-1, -1); + ORYX.Editor._resizefixTimeout = null; + }, 100); + } +}; + +ORYX.Editor.Cookie = { + + callbacks: [], + + onChange: function (callback, interval) { + + this.callbacks.push(callback); + this.start(interval) + + }, + + start: function (interval) { + + if (this.pe) { + return; + } + + var currentString = document.cookie; + + this.pe = new PeriodicalExecuter(function () { + + if (currentString != document.cookie) { + currentString = document.cookie; + this.callbacks.each(function (callback) { + callback(this.getParams()) + }.bind(this)); + } + + }.bind(this), (interval || 10000) / 1000); + }, + + stop: function () { + + if (this.pe) { + this.pe.stop(); + this.pe = null; + } + }, + + getParams: function () { + var res = {}; + + var p = document.cookie; + p.split("; ").each(function (param) { + res[param.split("=")[0]] = param.split("=")[1]; + }); + + return res; + }, + + toString: function () { + return document.cookie; + } +}; + +/** + * Workaround for SAFARI/Webkit, because + * when trying to check SVGSVGElement of instanceof there is + * raising an error + * + */ +ORYX.Editor.SVGClassElementsAreAvailable = true; +ORYX.Editor.setMissingClasses = function () { + + try { + SVGElement; + } catch (e) { + ORYX.Editor.SVGClassElementsAreAvailable = false; + SVGSVGElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg').toString(); + SVGGElement = document.createElementNS('http://www.w3.org/2000/svg', 'g').toString(); + SVGPathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path').toString(); + SVGTextElement = document.createElementNS('http://www.w3.org/2000/svg', 'text').toString(); + //SVGMarkerElement = document.createElementNS('http://www.w3.org/2000/svg', 'marker').toString(); + SVGRectElement = document.createElementNS('http://www.w3.org/2000/svg', 'rect').toString(); + SVGImageElement = document.createElementNS('http://www.w3.org/2000/svg', 'image').toString(); + SVGCircleElement = document.createElementNS('http://www.w3.org/2000/svg', 'circle').toString(); + SVGEllipseElement = document.createElementNS('http://www.w3.org/2000/svg', 'ellipse').toString(); + SVGLineElement = document.createElementNS('http://www.w3.org/2000/svg', 'line').toString(); + SVGPolylineElement = document.createElementNS('http://www.w3.org/2000/svg', 'polyline').toString(); + SVGPolygonElement = document.createElementNS('http://www.w3.org/2000/svg', 'polygon').toString(); + + } + +} +ORYX.Editor.checkClassType = function (classInst, classType) { + + if (ORYX.Editor.SVGClassElementsAreAvailable) { + return classInst instanceof classType + } else { + return classInst == classType + } +}; +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespaces + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} + + +new function () { + + ORYX.Core.UIEnableDrag = function (event, uiObj, option) { + + this.uiObj = uiObj; + var upL = uiObj.bounds.upperLeft(); + + var a = uiObj.node.getScreenCTM(); + this.faktorXY = {x: a.a, y: a.d}; + + this.scrollNode = uiObj.node.ownerSVGElement.parentNode.parentNode; + + this.offSetPosition = { + x: Event.pointerX(event) - (upL.x * this.faktorXY.x), + y: Event.pointerY(event) - (upL.y * this.faktorXY.y) + }; + + this.offsetScroll = {x: this.scrollNode.scrollLeft, y: this.scrollNode.scrollTop}; + + this.dragCallback = ORYX.Core.UIDragCallback.bind(this); + this.disableCallback = ORYX.Core.UIDisableDrag.bind(this); + + this.movedCallback = option ? option.movedCallback : undefined; + this.upCallback = option ? option.upCallback : undefined; + + document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.disableCallback, true); + document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.dragCallback, false); + + }; + + ORYX.Core.UIDragCallback = function (event) { + + var position = { + x: Event.pointerX(event) - this.offSetPosition.x, + y: Event.pointerY(event) - this.offSetPosition.y + } + + position.x -= this.offsetScroll.x - this.scrollNode.scrollLeft; + position.y -= this.offsetScroll.y - this.scrollNode.scrollTop; + + position.x /= this.faktorXY.x; + position.y /= this.faktorXY.y; + + this.uiObj.bounds.moveTo(position); + //this.uiObj.update(); + + if (this.movedCallback) + this.movedCallback(event); + + //Event.stop(event); + + }; + + ORYX.Core.UIDisableDrag = function (event) { + document.documentElement.removeEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.dragCallback, false); + document.documentElement.removeEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.disableCallback, true); + + if (this.upCallback) + this.upCallback(event); + + this.upCallback = undefined; + this.movedCallback = undefined; + + Event.stop(event); + }; + + + /** + * Implements a command to move docker by an offset. + * + * @class ORYX.Core.MoveDockersCommand + * @param {Object} object An object with the docker id as key and docker and offset as object value + * + */ + ORYX.Core.MoveDockersCommand = ORYX.Core.Command.extend({ + construct: function (dockers) { + this.dockers = $H(dockers); + this.edges = $H({}); + }, + execute: function () { + if (this.changes) { + this.executeAgain(); + return; + } else { + this.changes = $H({}); + } + + this.dockers.values().each(function (docker) { + var edge = docker.docker.parent; + if (!edge) { + return + } + + if (!this.changes[edge.getId()]) { + this.changes[edge.getId()] = { + edge: edge, + oldDockerPositions: edge.dockers.map(function (r) { + return r.bounds.center() + }) + } + } + docker.docker.bounds.moveBy(docker.offset); + this.edges[edge.getId()] = edge; + docker.docker.update(); + }.bind(this)); + this.edges.each(function (edge) { + this.updateEdge(edge.value); + if (this.changes[edge.value.getId()]) + this.changes[edge.value.getId()].dockerPositions = edge.value.dockers.map(function (r) { + return r.bounds.center() + }) + }.bind(this)); + }, + updateEdge: function (edge) { + edge._update(true); + [edge.getOutgoingShapes(), edge.getIncomingShapes()].flatten().invoke("_update", [true]) + }, + executeAgain: function () { + this.changes.values().each(function (change) { + // Reset the dockers + this.removeAllDocker(change.edge); + change.dockerPositions.each(function (pos, i) { + if (i == 0 || i == change.dockerPositions.length - 1) { + return + } + var docker = change.edge.createDocker(undefined, pos); + docker.bounds.centerMoveTo(pos); + docker.update(); + }.bind(this)); + this.updateEdge(change.edge); + }.bind(this)); + }, + rollback: function () { + this.changes.values().each(function (change) { + // Reset the dockers + this.removeAllDocker(change.edge); + change.oldDockerPositions.each(function (pos, i) { + if (i == 0 || i == change.oldDockerPositions.length - 1) { + return + } + var docker = change.edge.createDocker(undefined, pos); + docker.bounds.centerMoveTo(pos); + docker.update(); + }.bind(this)); + this.updateEdge(change.edge); + }.bind(this)); + }, + removeAllDocker: function (edge) { + edge.dockers.slice(1, edge.dockers.length - 1).each(function (docker) { + edge.removeDocker(docker); + }) + } + }); + +}(); +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespaces + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} + +/** + * @classDescription Base class for Shapes. + * @extends ORYX.Core.AbstractShape + */ +ORYX.Core.Shape = { + + /** + * Constructor + */ + construct: function (options, stencil, facade) { + // call base class constructor + arguments.callee.$.construct.apply(this, arguments); + + this.facade = facade; + this.dockers = []; + this.magnets = []; + + this._defaultMagnet; + + this.incoming = []; + this.outgoing = []; + + this.nodes = []; + + this._dockerChangedCallback = this._dockerChanged.bind(this); + + //Hash map for all labels. Labels are not treated as children of shapes. + this._labels = new Hash(); + + // create SVG node + this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", + null, + ['g', {id: "svg-" + this.resourceId}, + ['g', {"class": "stencils"}, + ['g', {"class": "me"}], + ['g', {"class": "children", style: "overflow:hidden"}], + ['g', {"class": "edge"}] + ], + ['g', {"class": "controls"}, + ['g', {"class": "dockers"}], + ['g', {"class": "magnets"}] + ] + ]); + }, + + /** + * If changed flag is set, refresh method is called. + */ + update: function () { + //if(this.isChanged) { + //this.layout(); + //} + }, + + /** + * !!!Not called from any sub class!!! + */ + _update: function () { + + }, + + /** + * Calls the super class refresh method + * and updates the svg elements that are referenced by a property. + */ + refresh: function () { + //call base class refresh method + arguments.callee.$.refresh.apply(this, arguments); + + if (this.node.ownerDocument) { + //adjust SVG to properties' values + var me = this; + this.propertiesChanged.each((function (propChanged) { + if (propChanged.value) { + var prop = this.properties[propChanged.key]; + var property = this.getStencil().property(propChanged.key); + if (property != undefined) { + this.propertiesChanged[propChanged.key] = false; + + //handle choice properties + if (property.type() == ORYX.CONFIG.TYPE_CHOICE) { + //iterate all references to SVG elements + property.refToView().each((function (ref) { + //if property is referencing a label, update the label + if (ref !== "") { + var label = this._labels[this.id + ref]; + if (label && property.item(prop)) { + label.text(property.item(prop).title()); + } + } + }).bind(this)); + + //if the choice's items are referencing SVG elements + // show the selected and hide all other referenced SVG + // elements + var refreshedSvgElements = new Hash(); + property.items().each((function (item) { + item.refToView().each((function (itemRef) { + if (itemRef == "") { + return; + } + + var svgElem = this.node.ownerDocument.getElementById(this.id + itemRef); + + if (!svgElem) { + return; + } + + + /* Do not refresh the same svg element multiple times */ + if (!refreshedSvgElements[svgElem.id] || prop == item.value()) { + svgElem.setAttributeNS(null, 'display', ((prop == item.value()) ? 'inherit' : 'none')); + refreshedSvgElements[svgElem.id] = svgElem; + } + + // Reload the href if there is an image-tag + if (ORYX.Editor.checkClassType(svgElem, SVGImageElement)) { + svgElem.setAttributeNS('http://www.w3.org/1999/xlink', 'href', svgElem.getAttributeNS('http://www.w3.org/1999/xlink', 'href')); + } + }).bind(this)); + }).bind(this)); + + } else { //handle properties that are not of type choice + //iterate all references to SVG elements + property.refToView().each((function (ref) { + //if the property does not reference an SVG element, + // do nothing + + if (ref === "") { + return; + } + + var refId = this.id + ref; + + if (property.type() === ORYX.CONFIG.TYPE_KISBPM_MULTIINSTANCE) { + if (ref === "multiinstance") { + + var svgElemParallel = this.node.ownerDocument.getElementById(this.id + 'parallel'); + if (svgElemParallel) { + if (prop === 'Parallel') { + svgElemParallel.setAttributeNS(null, 'display', 'inherit'); + } else { + svgElemParallel.setAttributeNS(null, 'display', 'none'); + } + } + + var svgElemSequential = this.node.ownerDocument.getElementById(this.id + 'sequential'); + + if (svgElemSequential) { + if (prop === 'Sequential') { + svgElemSequential.setAttributeNS(null, 'display', 'inherit'); + } else { + svgElemSequential.setAttributeNS(null, 'display', 'none'); + } + } + } + return; + + } else if (property.type() === "cancelactivity") { + var svgElemFrame = this.node.ownerDocument.getElementById(this.id + 'frame'); + var svgElemFrame2 = this.node.ownerDocument.getElementById(this.id + 'frame2'); + + if (prop === 'true') { + svgElemFrame.setAttributeNS(null, 'display', 'inherit'); + svgElemFrame2.setAttributeNS(null, 'display', 'inherit'); + } else { + svgElemFrame.setAttributeNS(null, 'display', 'none'); + svgElemFrame2.setAttributeNS(null, 'display', 'none'); + } + } + + //get the SVG element + var svgElem = this.node.ownerDocument.getElementById(refId); + + //if the SVG element can not be found + if (!svgElem || !(svgElem.ownerSVGElement)) { + //if the referenced SVG element is a SVGAElement, it cannot + // be found with getElementById (Firefox bug). + // this is a work around + if (property.type() === ORYX.CONFIG.TYPE_URL || property.type() === ORYX.CONFIG.TYPE_DIAGRAM_LINK) { + var svgElems = this.node.ownerDocument.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'a'); + + svgElem = $A(svgElems).find(function (elem) { + return elem.getAttributeNS(null, 'id') === refId; + }); + + if (!svgElem) { + return; + } + } else { + //this.propertiesChanged[propChanged.key] = true; + return; + } + } + + if (property.complexAttributeToView()) { + var label = this._labels[refId]; + if (label) { + try { + propJson = prop.evalJSON(); + var value = propJson[property.complexAttributeToView()] + label.text(value ? value : prop); + } catch (e) { + label.text(prop); + } + } + + } else { + switch (property.type()) { + case ORYX.CONFIG.TYPE_BOOLEAN: + if (typeof prop == "string") + prop = prop === "true" + + svgElem.setAttributeNS(null, 'display', (!(prop === property.inverseBoolean())) ? 'inherit' : 'none'); + + break; + case ORYX.CONFIG.TYPE_COLOR: + if (property.fill()) { + if (svgElem.tagName.toLowerCase() === "stop") { + if (prop) { + + if (property.lightness() && property.lightness() !== 1) { + prop = ORYX.Utils.adjustLightness(prop, property.lightness()); + } + + svgElem.setAttributeNS(null, "stop-color", prop); + + // Adjust stop color of the others + if (svgElem.parentNode.tagName.toLowerCase() === "radialgradient") { + ORYX.Utils.adjustGradient(svgElem.parentNode, svgElem); + } + } + + // If there is no value, set opaque + if (svgElem.parentNode.tagName.toLowerCase() === "radialgradient") { + $A(svgElem.parentNode.getElementsByTagName('stop')).each(function (stop) { + stop.setAttributeNS(null, "stop-opacity", prop ? stop.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'default-stop-opacity') || 1 : 0); + }.bind(this)) + } + } else { + svgElem.setAttributeNS(null, 'fill', prop); + } + } + if (property.stroke()) { + svgElem.setAttributeNS(null, 'stroke', prop); + } + break; + case ORYX.CONFIG.TYPE_STRING: + var label = this._labels[refId]; + if (label) { + label.text(prop); + } + break; + case ORYX.CONFIG.TYPE_EXPRESSION: + var label = this._labels[refId]; + if (label) { + label.text(prop); + } + break; + case ORYX.CONFIG.TYPE_DATASOURCE: + var label = this._labels[refId]; + if (label) { + label.text(prop); + } + break; + case ORYX.CONFIG.TYPE_INTEGER: + var label = this._labels[refId]; + if (label) { + label.text(prop); + } + break; + case ORYX.CONFIG.TYPE_FLOAT: + if (property.fillOpacity()) { + svgElem.setAttributeNS(null, 'fill-opacity', prop); + } + if (property.strokeOpacity()) { + svgElem.setAttributeNS(null, 'stroke-opacity', prop); + } + if (!property.fillOpacity() && !property.strokeOpacity()) { + var label = this._labels[refId]; + if (label) { + label.text(prop); + } + } + break; + + case ORYX.CONFIG.TYPE_FORM_LINK: + if (ref == "pimg") { + var onclickAttr = svgElem.getAttributeNodeNS('', 'onclick'); + if (onclickAttr) { + if (prop && ("" + prop).length > 0) { + onclickAttr.textContent = "window.location = '../service/editor?id=" + prop + "_form'"; + } else { + newFormFacade = this.facade; + onclickAttr.textContent = "displayNewFormDialog('" + this.resourceId + "');"; + } + } + } else if (ref == "linkIndicator") { + if (prop && prop.length > 0) { + svgElem.setAttributeNS(null, 'display', 'inherit'); + } else { + svgElem.setAttributeNS(null, 'display', 'none'); + } + } + break; + case ORYX.CONFIG.TYPE_URL: + case ORYX.CONFIG.TYPE_DIAGRAM_LINK: + //TODO what is the dafault path? + var hrefAttr = svgElem.getAttributeNodeNS('http://www.w3.org/1999/xlink', 'xlink:href'); + if (hrefAttr) { + hrefAttr.textContent = prop; + } else { + svgElem.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', prop); + } + break; + + } + } + }).bind(this)); + + + } + } + + } + }).bind(this)); + + //update labels + this._labels.values().each(function (label) { + label.update(); + }); + } + }, + + layout: function () { + //this.getStencil().layout(this) + var layoutEvents = this.getStencil().layout() + if (layoutEvents) { + layoutEvents.each(function (event) { + + // setup additional attributes + event.shape = this; + event.forceExecution = true; + + // do layouting + this._delegateEvent(event); + }.bind(this)) + + } + }, + + /** + * Returns an array of Label objects. + */ + getLabels: function () { + return this._labels.values(); + }, + + /** + * Returns the label for a given ref + * @return {ORYX.Core.Label} Returns null if there is no label + */ + getLabel: function (ref) { + if (!ref) { + return null; + } + return (this._labels.find(function (o) { + return o.key.endsWith(ref); + }) || {}).value || null; + }, + + /** + * Hides all related labels + * + */ + hideLabels: function () { + this.getLabels().invoke("hide"); + }, + + /** + * Shows all related labels + * + */ + showLabels: function () { + var labels = this.getLabels(); + labels.invoke("show"); + labels.each(function (label) { + label.update(); + }); + }, + + setOpacity: function (value, animate) { + + value = Math.max(Math.min((typeof value == "number" ? value : 1.0), 1.0), 0.0); + + if (value !== 1.0) { + value = String(value); + this.node.setAttributeNS(null, "fill-opacity", value) + this.node.setAttributeNS(null, "stroke-opacity", value) + } else { + this.node.removeAttributeNS(null, "fill-opacity"); + this.node.removeAttributeNS(null, "stroke-opacity"); + } + }, + + /** + * Returns an array of dockers of this object. + */ + getDockers: function () { + return this.dockers; + }, + + getMagnets: function () { + return this.magnets; + }, + + getDefaultMagnet: function () { + if (this._defaultMagnet) { + return this._defaultMagnet; + } else if (this.magnets.length > 0) { + return this.magnets[0]; + } else { + return undefined; + } + }, + + getParentShape: function () { + return this.parent; + }, + + getIncomingShapes: function (iterator) { + if (iterator) { + this.incoming.each(iterator); + } + return this.incoming; + }, + + getIncomingNodes: function (iterator) { + return this.incoming.select(function (incoming) { + var isNode = (incoming instanceof ORYX.Core.Node); + if (isNode && iterator) iterator(incoming); + return isNode; + }); + }, + + + getOutgoingShapes: function (iterator) { + if (iterator) { + this.outgoing.each(iterator); + } + return this.outgoing; + }, + + getOutgoingNodes: function (iterator) { + return this.outgoing.select(function (out) { + var isNode = (out instanceof ORYX.Core.Node); + if (isNode && iterator) iterator(out); + return isNode; + }); + }, + + getAllDockedShapes: function (iterator) { + var result = this.incoming.concat(this.outgoing); + if (iterator) { + result.each(iterator); + } + return result + }, + + getCanvas: function () { + if (this.parent instanceof ORYX.Core.Canvas) { + return this.parent; + } else if (this.parent instanceof ORYX.Core.Shape) { + return this.parent.getCanvas(); + } else { + return undefined; + } + }, + + /** + * + * @param {Object} deep + * @param {Object} iterator + */ + getChildNodes: function (deep, iterator) { + if (!deep && !iterator) { + return this.nodes.clone(); + } else { + var result = []; + this.nodes.each(function (uiObject) { + if (!uiObject.isVisible) { + return + } + if (iterator) { + iterator(uiObject); + } + result.push(uiObject); + + if (deep && uiObject instanceof ORYX.Core.Shape) { + result = result.concat(uiObject.getChildNodes(deep, iterator)); + } + }); + + return result; + } + }, + + /** + * Overrides the UIObject.add method. Adds uiObject to the correct sub node. + * @param {UIObject} uiObject + * @param {Number} index + */ + add: function (uiObject, index, silent) { + //parameter has to be an UIObject, but + // must not be an Edge. + if (uiObject instanceof ORYX.Core.UIObject + && !(uiObject instanceof ORYX.Core.Edge)) { + + if (!(this.children.member(uiObject))) { + //if uiObject is child of another parent, remove it from that parent. + if (uiObject.parent) { + uiObject.parent.remove(uiObject, true); + } + + //add uiObject to this Shape + if (index != undefined) + this.children.splice(index, 0, uiObject); + else + this.children.push(uiObject); + + //set parent reference + uiObject.parent = this; + + //add uiObject.node to this.node depending on the type of uiObject + var parent; + if (uiObject instanceof ORYX.Core.Node) { + parent = this.node.childNodes[0].childNodes[1]; + this.nodes.push(uiObject); + } else if (uiObject instanceof ORYX.Core.Controls.Control) { + var ctrls = this.node.childNodes[1]; + if (uiObject instanceof ORYX.Core.Controls.Docker) { + parent = ctrls.childNodes[0]; + if (this.dockers.length >= 2) { + this.dockers.splice(index !== undefined ? Math.min(index, this.dockers.length - 1) : this.dockers.length - 1, 0, uiObject); + } else { + this.dockers.push(uiObject); + } + } else if (uiObject instanceof ORYX.Core.Controls.Magnet) { + parent = ctrls.childNodes[1]; + this.magnets.push(uiObject); + } else { + parent = ctrls; + } + } else { //UIObject + parent = this.node; + } + + if (index != undefined && index < parent.childNodes.length) + uiObject.node = parent.insertBefore(uiObject.node, parent.childNodes[index]); + else + uiObject.node = parent.appendChild(uiObject.node); + + this._changed(); + //uiObject.bounds.registerCallback(this._changedCallback); + + + if (this.eventHandlerCallback && silent !== true) + this.eventHandlerCallback({type: ORYX.CONFIG.EVENT_SHAPEADDED, shape: uiObject}) + + } else { + + ORYX.Log.warn("add: ORYX.Core.UIObject is already a child of this object."); + } + } else { + + ORYX.Log.warn("add: Parameter is not of type ORYX.Core.UIObject."); + } + }, + + /** + * Overrides the UIObject.remove method. Removes uiObject. + * @param {UIObject} uiObject + */ + remove: function (uiObject, silent) { + //if uiObject is a child of this object, remove it. + if (this.children.member(uiObject)) { + //remove uiObject from children + var parent = uiObject.parent; + + this.children = this.children.without(uiObject); + + //delete parent reference of uiObject + uiObject.parent = undefined; + + //delete uiObject.node from this.node + if (uiObject instanceof ORYX.Core.Shape) { + if (uiObject instanceof ORYX.Core.Edge) { + uiObject.removeMarkers(); + uiObject.node = this.node.childNodes[0].childNodes[2].removeChild(uiObject.node); + } else { + uiObject.node = this.node.childNodes[0].childNodes[1].removeChild(uiObject.node); + this.nodes = this.nodes.without(uiObject); + } + } else if (uiObject instanceof ORYX.Core.Controls.Control) { + if (uiObject instanceof ORYX.Core.Controls.Docker) { + uiObject.node = this.node.childNodes[1].childNodes[0].removeChild(uiObject.node); + this.dockers = this.dockers.without(uiObject); + } else if (uiObject instanceof ORYX.Core.Controls.Magnet) { + uiObject.node = this.node.childNodes[1].childNodes[1].removeChild(uiObject.node); + this.magnets = this.magnets.without(uiObject); + } else { + uiObject.node = this.node.childNodes[1].removeChild(uiObject.node); + } + } + + if (this.eventHandlerCallback && silent !== true) + this.eventHandlerCallback({type: ORYX.CONFIG.EVENT_SHAPEREMOVED, shape: uiObject, parent: parent}); + + this._changed(); + //uiObject.bounds.unregisterCallback(this._changedCallback); + } else { + + ORYX.Log.warn("remove: ORYX.Core.UIObject is not a child of this object."); + } + }, + + /** + * Calculate the Border Intersection Point between two points + * @param {PointA} + * @param {PointB} + */ + getIntersectionPoint: function () { + + var pointAX, pointAY, pointBX, pointBY; + + // Get the the two Points + switch (arguments.length) { + case 2: + pointAX = arguments[0].x; + pointAY = arguments[0].y; + pointBX = arguments[1].x; + pointBY = arguments[1].y; + break; + case 4: + pointAX = arguments[0]; + pointAY = arguments[1]; + pointBX = arguments[2]; + pointBY = arguments[3]; + break; + default: + throw "getIntersectionPoints needs two or four arguments"; + } + + + // Defined an include and exclude point + var includePointX, includePointY, excludePointX, excludePointY; + + var bounds = this.absoluteBounds(); + + if (this.isPointIncluded(pointAX, pointAY, bounds)) { + includePointX = pointAX; + includePointY = pointAY; + } else { + excludePointX = pointAX; + excludePointY = pointAY; + } + + if (this.isPointIncluded(pointBX, pointBY, bounds)) { + includePointX = pointBX; + includePointY = pointBY; + } else { + excludePointX = pointBX; + excludePointY = pointBY; + } + + // If there is no inclue or exclude Shape, than return + if (!includePointX || !includePointY || !excludePointX || !excludePointY) { + return undefined; + } + + var midPointX = 0; + var midPointY = 0; + + var refPointX, refPointY; + + var minDifferent = 1; + // Get the UpperLeft and LowerRight + //var ul = bounds.upperLeft(); + //var lr = bounds.lowerRight(); + + var i = 0; + + while (true) { + // Calculate the midpoint of the current to points + var midPointX = Math.min(includePointX, excludePointX) + ((Math.max(includePointX, excludePointX) - Math.min(includePointX, excludePointX)) / 2.0); + var midPointY = Math.min(includePointY, excludePointY) + ((Math.max(includePointY, excludePointY) - Math.min(includePointY, excludePointY)) / 2.0); + + + // Set the new midpoint by the means of the include of the bounds + if (this.isPointIncluded(midPointX, midPointY, bounds)) { + includePointX = midPointX; + includePointY = midPointY; + } else { + excludePointX = midPointX; + excludePointY = midPointY; + } + + // Calc the length of the line + var length = Math.sqrt(Math.pow(includePointX - excludePointX, 2) + Math.pow(includePointY - excludePointY, 2)) + // Calc a point one step from the include point + refPointX = includePointX + ((excludePointX - includePointX) / length), + refPointY = includePointY + ((excludePointY - includePointY) / length) + + + // If the reference point not in the bounds, break + if (!this.isPointIncluded(refPointX, refPointY, bounds)) { + break + } + + + } + + // Return the last includepoint + return {x: refPointX, y: refPointY}; + }, + + + /** + * Calculate if the point is inside the Shape + * @param {PointX} + * @param {PointY} + */ + isPointIncluded: function () { + return false + }, + + /** + * Returns TRUE if the given node + * is a child node of the shapes node + * @param {Element} node + * @return {Boolean} + * + */ + containsNode: function (node) { + var me = this.node.firstChild.firstChild; + while (node) { + if (node == me) { + return true; + } + node = node.parentNode; + } + return false + }, + + /** + * Calculate if the point is over an special offset area + * @param {Point} + */ + isPointOverOffset: function () { + return this.isPointIncluded.apply(this, arguments) + }, + + _dockerChanged: function () { + + }, + + /** + * Create a Docker for this Edge + * + */ + createDocker: function (index, position) { + var docker = new ORYX.Core.Controls.Docker({eventHandlerCallback: this.eventHandlerCallback}); + docker.bounds.registerCallback(this._dockerChangedCallback); + if (position) { + docker.bounds.centerMoveTo(position); + } + this.add(docker, index); + + return docker + }, + + /** + * Get the serialized object + * return Array with hash-entrees (prefix, name, value) + * Following values will given: + * Bounds + * Outgoing Shapes + * Parent + */ + serialize: function () { + var serializedObject = arguments.callee.$.serialize.apply(this); + + // Add the bounds + serializedObject.push({name: 'bounds', prefix: 'oryx', value: this.bounds.serializeForERDF(), type: 'literal'}); + + // Add the outgoing shapes + this.getOutgoingShapes().each((function (followingShape) { + serializedObject.push({ + name: 'outgoing', + prefix: 'raziel', + value: '#' + ERDF.__stripHashes(followingShape.resourceId), + type: 'resource' + }); + }).bind(this)); + + // Add the parent shape, if the parent not the canvas + //if(this.parent instanceof ORYX.Core.Shape){ + serializedObject.push({ + name: 'parent', + prefix: 'raziel', + value: '#' + ERDF.__stripHashes(this.parent.resourceId), + type: 'resource' + }); + //} + + return serializedObject; + }, + + + deserialize: function (serialize, json) { + arguments.callee.$.deserialize.apply(this, arguments); + + // Set the Bounds + var bounds = serialize.find(function (ser) { + return 'oryx-bounds' === (ser.prefix + "-" + ser.name) + }); + if (bounds) { + var b = bounds.value.replace(/,/g, " ").split(" ").without(""); + if (this instanceof ORYX.Core.Edge) { + if (!this.dockers.first().isChanged) + this.dockers.first().bounds.centerMoveTo(parseFloat(b[0]), parseFloat(b[1])); + if (!this.dockers.last().isChanged) + this.dockers.last().bounds.centerMoveTo(parseFloat(b[2]), parseFloat(b[3])); + } else { + this.bounds.set(parseFloat(b[0]), parseFloat(b[1]), parseFloat(b[2]), parseFloat(b[3])); + } + } + + if (json && json.labels instanceof Array) { + json.labels.each(function (slabel) { + var label = this.getLabel(slabel.ref); + if (label) { + label.deserialize(slabel, this); + } + }.bind(this)) + } + }, + + toJSON: function () { + var json = arguments.callee.$.toJSON.apply(this, arguments); + + var labels = [], id = this.id; + this._labels.each(function (obj) { + var slabel = obj.value.serialize(); + if (slabel) { + slabel.ref = obj.key.replace(id, ''); + labels.push(slabel); + } + }); + + if (labels.length > 0) { + json.labels = labels; + } + return json; + }, + + + /** + * Private methods. + */ + + /** + * Child classes have to overwrite this method for initializing a loaded + * SVG representation. + * @param {SVGDocument} svgDocument + */ + _init: function (svgDocument) { + //adjust ids + this._adjustIds(svgDocument, 0); + }, + + _adjustIds: function (element, idIndex) { + if (element instanceof Element) { + var eid = element.getAttributeNS(null, 'id'); + if (eid && eid !== "") { + element.setAttributeNS(null, 'id', this.id + eid); + } else { + element.setAttributeNS(null, 'id', this.id + "_" + this.id + "_" + idIndex); + idIndex++; + } + + // Replace URL in fill attribute + var fill = element.getAttributeNS(null, 'fill'); + if (fill && fill.include("url(#")) { + fill = fill.replace(/url\(#/g, 'url(#' + this.id); + element.setAttributeNS(null, 'fill', fill); + } + + if (element.hasChildNodes()) { + for (var i = 0; i < element.childNodes.length; i++) { + idIndex = this._adjustIds(element.childNodes[i], idIndex); + } + } + } + return idIndex; + }, + + toString: function () { + return "ORYX.Core.Shape " + this.getId() + } +}; +ORYX.Core.Shape = ORYX.Core.AbstractShape.extend(ORYX.Core.Shape);/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespaces + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} +if (!ORYX.Core.Controls) { + ORYX.Core.Controls = {}; +} + + +/** + * @classDescription Abstract base class for all Controls. + */ +ORYX.Core.Controls.Control = ORYX.Core.UIObject.extend({ + + toString: function () { + return "Control " + this.id; + } +});/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespaces + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} +if (!ORYX.Core.Controls) { + ORYX.Core.Controls = {}; +} + + +/** + * @classDescription Represents a movable docker that can be bound to a shape. Dockers are used + * for positioning shape objects. + * @extends {Control} + * + * TODO absoluteXY und absoluteCenterXY von einem Docker liefern falsche Werte!!! + */ +ORYX.Core.Controls.Docker = ORYX.Core.Controls.Control.extend({ + /** + * Constructor + */ + construct: function () { + arguments.callee.$.construct.apply(this, arguments); + + this.isMovable = true; // Enables movability + this.bounds.set(0, 0, 16, 16); // Set the bounds + this.referencePoint = undefined; // Refrenzpoint + this._dockedShapeBounds = undefined; + this._dockedShape = undefined; + this._oldRefPoint1 = undefined; + this._oldRefPoint2 = undefined; + + //this.anchors = []; + this.anchorLeft; + this.anchorRight; + this.anchorTop; + this.anchorBottom; + + this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", + null, + ['g']); + + // The DockerNode reprasentation + this._dockerNode = ORYX.Editor.graft("http://www.w3.org/2000/svg", + this.node, + ['g', {"pointer-events": "all"}, + ['circle', {cx: "8", cy: "8", r: "8", stroke: "none", fill: "none"}], + ['circle', {cx: "8", cy: "8", r: "3", stroke: "black", fill: "red", "stroke-width": "1"}] + ]); + + // The ReferenzNode reprasentation + this._referencePointNode = ORYX.Editor.graft("http://www.w3.org/2000/svg", + this.node, + ['g', {"pointer-events": "none"}, + ['circle', { + cx: this.bounds.upperLeft().x, + cy: this.bounds.upperLeft().y, + r: 3, + fill: "red", + "fill-opacity": 0.4 + }]]); + + // Hide the Docker + this.hide(); + + //Add to the EventHandler + this.addEventHandlers(this._dockerNode); + + // Buffer the Update Callback for un-/register on Event-Handler + this._updateCallback = this._changed.bind(this); + }, + + update: function () { + // If there have an DockedShape + if (this._dockedShape) { + if (this._dockedShapeBounds && this._dockedShape instanceof ORYX.Core.Node) { + // Calc the delta of width and height of the lastBounds and the current Bounds + var dswidth = this._dockedShapeBounds.width(); + var dsheight = this._dockedShapeBounds.height(); + if (!dswidth) + dswidth = 1; + if (!dsheight) + dsheight = 1; + var widthDelta = this._dockedShape.bounds.width() / dswidth; + var heightDelta = this._dockedShape.bounds.height() / dsheight; + + // If there is an different + if (widthDelta !== 1.0 || heightDelta !== 1.0) { + // Set the delta + this.referencePoint.x *= widthDelta; + this.referencePoint.y *= heightDelta; + } + + // Clone these bounds + this._dockedShapeBounds = this._dockedShape.bounds.clone(); + } + + // Get the first and the last Docker of the parent Shape + var dockerIndex = this.parent.dockers.indexOf(this) + var dock1 = this; + var dock2 = this.parent.dockers.length > 1 ? + (dockerIndex === 0 ? // If there is the first element + this.parent.dockers[dockerIndex + 1] : // then take the next docker + this.parent.dockers[dockerIndex - 1]) : // if not, then take the docker before + undefined; + + // Calculate the first absolute Refenzpoint + var absoluteReferenzPoint1 = dock1.getDockedShape() ? + dock1.getAbsoluteReferencePoint() : + dock1.bounds.center(); + + // Calculate the last absolute Refenzpoint + var absoluteReferenzPoint2 = dock2 && dock2.getDockedShape() ? + dock2.getAbsoluteReferencePoint() : + dock2 ? + dock2.bounds.center() : + undefined; + + // If there is no last absolute Referenzpoint + if (!absoluteReferenzPoint2) { + // Calculate from the middle of the DockedShape + var center = this._dockedShape.absoluteCenterXY(); + var minDimension = this._dockedShape.bounds.width() * this._dockedShape.bounds.height(); + absoluteReferenzPoint2 = { + x: absoluteReferenzPoint1.x + (center.x - absoluteReferenzPoint1.x) * -minDimension, + y: absoluteReferenzPoint1.y + (center.y - absoluteReferenzPoint1.y) * -minDimension + } + } + + var newPoint = undefined; + + /*if (!this._oldRefPoint1 || !this._oldRefPoint2 || + absoluteReferenzPoint1.x !== this._oldRefPoint1.x || + absoluteReferenzPoint1.y !== this._oldRefPoint1.y || + absoluteReferenzPoint2.x !== this._oldRefPoint2.x || + absoluteReferenzPoint2.y !== this._oldRefPoint2.y) {*/ + + // Get the new point for the Docker, calucalted by the intersection point of the Shape and the two points + newPoint = this._dockedShape.getIntersectionPoint(absoluteReferenzPoint1, absoluteReferenzPoint2); + + // If there is new point, take the referencepoint as the new point + if (!newPoint) { + newPoint = this.getAbsoluteReferencePoint(); + } + + if (this.parent && this.parent.parent) { + var grandParentPos = this.parent.parent.absoluteXY(); + newPoint.x -= grandParentPos.x; + newPoint.y -= grandParentPos.y; + } + + // Set the bounds to the new point + this.bounds.centerMoveTo(newPoint) + + this._oldRefPoint1 = absoluteReferenzPoint1; + this._oldRefPoint2 = absoluteReferenzPoint2; + } + /*else { + newPoint = this.bounds.center(); + }*/ + + + // } + + // Call the super class + arguments.callee.$.update.apply(this, arguments); + }, + + /** + * Calls the super class refresh method and updates the view of the docker. + */ + refresh: function () { + arguments.callee.$.refresh.apply(this, arguments); + + // Refresh the dockers node + var p = this.bounds.upperLeft(); + this._dockerNode.setAttributeNS(null, 'transform', 'translate(' + p.x + ', ' + p.y + ')'); + + // Refresh the referencepoints node + p = Object.clone(this.referencePoint); + + if (p && this._dockedShape) { + var upL + if (this.parent instanceof ORYX.Core.Edge) { + upL = this._dockedShape.absoluteXY(); + } else { + upL = this._dockedShape.bounds.upperLeft(); + } + p.x += upL.x; + p.y += upL.y; + } else { + p = this.bounds.center(); + } + + this._referencePointNode.setAttributeNS(null, 'transform', 'translate(' + p.x + ', ' + p.y + ')'); + }, + + /** + * Set the reference point + * @param {Object} point + */ + setReferencePoint: function (point) { + // Set the referencepoint + if (this.referencePoint !== point && + (!this.referencePoint || + !point || + this.referencePoint.x !== point.x || + this.referencePoint.y !== point.y)) { + + this.referencePoint = point; + this._changed(); + } + + + // Update directly, because the referencepoint has no influence of the bounds + //this.refresh(); + }, + + /** + * Get the absolute referencepoint + */ + getAbsoluteReferencePoint: function () { + if (!this.referencePoint || !this._dockedShape) { + return undefined; + } else { + var absUL = this._dockedShape.absoluteXY(); + return { + x: this.referencePoint.x + absUL.x, + y: this.referencePoint.y + absUL.y + } + } + }, + + /** + * Set the docked Shape from the docker + * @param {Object} shape + */ + setDockedShape: function (shape) { + + // If there is an old docked Shape + if (this._dockedShape) { + this._dockedShape.bounds.unregisterCallback(this._updateCallback) + + // Delete the Shapes from the incoming and outgoing array + // If this Docker the incoming of the Shape + if (this === this.parent.dockers.first()) { + + this.parent.incoming = this.parent.incoming.without(this._dockedShape); + this._dockedShape.outgoing = this._dockedShape.outgoing.without(this.parent); + + // If this Docker the outgoing of the Shape + } else if (this === this.parent.dockers.last()) { + + this.parent.outgoing = this.parent.outgoing.without(this._dockedShape); + this._dockedShape.incoming = this._dockedShape.incoming.without(this.parent); + + } + + } + + + // Set the new Shape + this._dockedShape = shape; + this._dockedShapeBounds = undefined; + var referencePoint = undefined; + + // If there is an Shape, register the updateCallback if there are changes in the shape bounds + if (this._dockedShape) { + + // Add the Shapes to the incoming and outgoing array + // If this Docker the incoming of the Shape + if (this === this.parent.dockers.first()) { + + this.parent.incoming.push(shape); + shape.outgoing.push(this.parent); + + // If this Docker the outgoing of the Shape + } else if (this === this.parent.dockers.last()) { + + this.parent.outgoing.push(shape); + shape.incoming.push(this.parent); + + } + + // Get the bounds and set the new referencepoint + var bounds = this.bounds; + var absUL = shape.absoluteXY(); + + /*if(shape.parent){ + var b = shape.parent.bounds.upperLeft(); + absUL.x -= b.x; + absUL.y -= b.y; + }*/ + + referencePoint = { + x: bounds.center().x - absUL.x, + y: bounds.center().y - absUL.y + } + + this._dockedShapeBounds = this._dockedShape.bounds.clone(); + + this._dockedShape.bounds.registerCallback(this._updateCallback); + + // Set the color of the docker as docked + this.setDockerColor(ORYX.CONFIG.DOCKER_DOCKED_COLOR); + } else { + // Set the color of the docker as undocked + this.setDockerColor(ORYX.CONFIG.DOCKER_UNDOCKED_COLOR); + } + + // Set the referencepoint + this.setReferencePoint(referencePoint); + this._changed(); + //this.update(); + }, + + /** + * Get the docked Shape + */ + getDockedShape: function () { + return this._dockedShape; + }, + + /** + * Returns TRUE if the docker has a docked shape + */ + isDocked: function () { + return !!this._dockedShape; + }, + + /** + * Set the Color of the Docker + * @param {Object} color + */ + setDockerColor: function (color) { + this._dockerNode.lastChild.setAttributeNS(null, "fill", color); + }, + + preventHiding: function (prevent) { + this._preventHiding = Math.max(0, (this._preventHiding || 0) + (prevent ? 1 : -1)); + }, + + /** + * Hides this UIObject and all its children. + */ + hide: function () { + if (this._preventHiding) { + return false; + } + + // Hide docker and reference point + this.node.setAttributeNS(null, 'visibility', 'hidden'); + this._referencePointNode.setAttributeNS(null, 'visibility', 'hidden'); + + this.children.each(function (uiObj) { + uiObj.hide(); + }); + }, + + /** + * Enables visibility of this UIObject and all its children. + */ + show: function () { + // Show docker + this.node.setAttributeNS(null, 'visibility', 'visible'); + + // Hide reference point if the connected shape is an edge + if (this.getDockedShape() instanceof ORYX.Core.Edge) { + this._referencePointNode.setAttributeNS(null, 'visibility', 'hidden'); + } else { + this._referencePointNode.setAttributeNS(null, 'visibility', 'visible'); + } + + this.children.each(function (uiObj) { + uiObj.show(); + }); + }, + + toString: function () { + return "Docker " + this.id + } +});/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespaces + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} +if (!ORYX.Core.Controls) { + ORYX.Core.Controls = {}; +} + + +/** + * @classDescription Represents a magnet that is part of another shape and can + * be attached to dockers. Magnets are used for linking edge objects + * to other Shape objects. + * @extends {Control} + */ +ORYX.Core.Controls.Magnet = ORYX.Core.Controls.Control.extend({ + + /** + * Constructor + */ + construct: function () { + arguments.callee.$.construct.apply(this, arguments); + + //this.anchors = []; + this.anchorLeft; + this.anchorRight; + this.anchorTop; + this.anchorBottom; + + this.bounds.set(0, 0, 16, 16); + + //graft magnet's root node into owner's control group. + this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", + null, + ['g', {"pointer-events": "all"}, + ['circle', {cx: "8", cy: "8", r: "4", stroke: "none", fill: "red", "fill-opacity": "0.3"}], + ]); + + this.hide(); + }, + + update: function () { + arguments.callee.$.update.apply(this, arguments); + + //this.isChanged = true; + }, + + _update: function () { + arguments.callee.$.update.apply(this, arguments); + + //this.isChanged = true; + }, + + refresh: function () { + arguments.callee.$.refresh.apply(this, arguments); + + var p = this.bounds.upperLeft(); + /*if(this.parent) { + var parentPos = this.parent.bounds.upperLeft(); + p.x += parentPos.x; + p.y += parentPos.y; + }*/ + + this.node.setAttributeNS(null, 'transform', 'translate(' + p.x + ', ' + p.y + ')'); + }, + + show: function () { + //this.refresh(); + arguments.callee.$.show.apply(this, arguments); + }, + + toString: function () { + return "Magnet " + this.id; + } +}); +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * Init namespaces + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} + +/** + * @classDescription Abstract base class for all Nodes. + * @extends ORYX.Core.Shape + */ +ORYX.Core.Node = { + + /** + * Constructor + * @param options {Object} A container for arguments. + * @param stencil {Stencil} + */ + construct: function (options, stencil, facade) { + arguments.callee.$.construct.apply(this, arguments); + + this.isSelectable = true; + this.isMovable = true; + this._dockerUpdated = false; + this.facade = facade; + + this._oldBounds = new ORYX.Core.Bounds(); //init bounds with undefined values + this._svgShapes = []; //array of all SVGShape objects of + // SVG representation + + //TODO vielleicht in shape verschieben? + this.minimumSize = undefined; // {width:..., height:...} + this.maximumSize = undefined; + + //TODO vielleicht in shape oder uiobject verschieben? + // vielleicht sogar isResizable ersetzen? + this.isHorizontallyResizable = false; + this.isVerticallyResizable = false; + + this.dataId = undefined; + + this._init(this._stencil.view()); + this.forcedHeight = -1; + }, + + /** + * This method checks whether the shape is resized correctly and calls the + * super class update method. + */ + _update: function () { + + this.dockers.invoke("update"); + if (this.isChanged) { + + var bounds = this.bounds; + var oldBounds = this._oldBounds; + + if (this.isResized) { + + var widthDelta = bounds.width() / oldBounds.width(); + var heightDelta = bounds.height() / oldBounds.height(); + + //iterate over all relevant svg elements and resize them + this._svgShapes.each(function (svgShape) { + //adjust width + if (svgShape.isHorizontallyResizable) { + svgShape.width = svgShape.oldWidth * widthDelta; + } + //adjust height + if (svgShape.isVerticallyResizable) { + svgShape.height = svgShape.oldHeight * heightDelta; + } + + //check, if anchors are set + var anchorOffset; + var leftIncluded = svgShape.anchorLeft; + var rightIncluded = svgShape.anchorRight; + + if (rightIncluded) { + anchorOffset = oldBounds.width() - (svgShape.oldX + svgShape.oldWidth); + if (leftIncluded) { + svgShape.width = bounds.width() - svgShape.x - anchorOffset; + } else { + svgShape.x = bounds.width() - (anchorOffset + svgShape.width); + } + } else if (!leftIncluded) { + svgShape.x = widthDelta * svgShape.oldX; + if (!svgShape.isHorizontallyResizable) { + svgShape.x = svgShape.x + svgShape.width * widthDelta / 2 - svgShape.width / 2; + } + } + + var topIncluded = svgShape.anchorTop; + var bottomIncluded = svgShape.anchorBottom; + + if (bottomIncluded) { + anchorOffset = oldBounds.height() - (svgShape.oldY + svgShape.oldHeight); + if (topIncluded) { + svgShape.height = bounds.height() - svgShape.y - anchorOffset; + } else { + // Hack for choreography task layouting + if (!svgShape._isYLocked) { + svgShape.y = bounds.height() - (anchorOffset + svgShape.height); + } + } + } else if (!topIncluded) { + svgShape.y = heightDelta * svgShape.oldY; + if (!svgShape.isVerticallyResizable) { + svgShape.y = svgShape.y + svgShape.height * heightDelta / 2 - svgShape.height / 2; + } + } + }); + + //check, if the current bounds is unallowed horizontally or vertically resized + var p = { + x: 0, + y: 0 + }; + if (!this.isHorizontallyResizable && bounds.width() !== oldBounds.width()) { + p.x = oldBounds.width() - bounds.width(); + } + if (!this.isVerticallyResizable && bounds.height() !== oldBounds.height()) { + p.y = oldBounds.height() - bounds.height(); + } + if (p.x !== 0 || p.y !== 0) { + bounds.extend(p); + } + + //check, if the current bounds are between maximum and minimum bounds + p = { + x: 0, + y: 0 + }; + var widthDifference, heightDifference; + if (this.minimumSize) { + + ORYX.Log.debug("Shape (%0)'s min size: (%1x%2)", this, this.minimumSize.width, this.minimumSize.height); + widthDifference = this.minimumSize.width - bounds.width(); + if (widthDifference > 0) { + p.x += widthDifference; + } + heightDifference = this.minimumSize.height - bounds.height(); + if (heightDifference > 0) { + p.y += heightDifference; + } + } + if (this.maximumSize) { + + ORYX.Log.debug("Shape (%0)'s max size: (%1x%2)", this, this.maximumSize.width, this.maximumSize.height); + widthDifference = bounds.width() - this.maximumSize.width; + if (widthDifference > 0) { + p.x -= widthDifference; + } + heightDifference = bounds.height() - this.maximumSize.height; + if (heightDifference > 0) { + p.y -= heightDifference; + } + } + if (p.x !== 0 || p.y !== 0) { + bounds.extend(p); + } + + //update magnets + + var widthDelta = bounds.width() / oldBounds.width(); + var heightDelta = bounds.height() / oldBounds.height(); + + var leftIncluded, rightIncluded, topIncluded, bottomIncluded, center, newX, newY; + + this.magnets.each(function (magnet) { + leftIncluded = magnet.anchorLeft; + rightIncluded = magnet.anchorRight; + topIncluded = magnet.anchorTop; + bottomIncluded = magnet.anchorBottom; + + center = magnet.bounds.center(); + + if (leftIncluded) { + newX = center.x; + } else if (rightIncluded) { + newX = bounds.width() - (oldBounds.width() - center.x) + } else { + newX = center.x * widthDelta; + } + + if (topIncluded) { + newY = center.y; + } else if (bottomIncluded) { + newY = bounds.height() - (oldBounds.height() - center.y); + } else { + newY = center.y * heightDelta; + } + + if (center.x !== newX || center.y !== newY) { + magnet.bounds.centerMoveTo(newX, newY); + } + }); + + //set new position of labels + this.getLabels().each(function (label) { + // Set the position dependings on it anchor + if (!label.isAnchorLeft()) { + if (label.isAnchorRight()) { + label.setX(bounds.width() - (oldBounds.width() - label.oldX)) + } else { + label.setX((label.position ? label.position.x : label.x) * widthDelta); + } + } + if (!label.isAnchorTop()) { + if (label.isAnchorBottom()) { + label.setY(bounds.height() - (oldBounds.height() - label.oldY)); + } else { + label.setY((label.position ? label.position.y : label.y) * heightDelta); + } + } + + // If there is an position, + // set the origin position as well + if (label.position) { + if (!label.isOriginAnchorLeft()) { + if (label.isOriginAnchorRight()) { + label.setOriginX(bounds.width() - (oldBounds.width() - label.oldX)) + } else { + label.setOriginX(label.x * widthDelta); + } + } + if (!label.isOriginAnchorTop()) { + if (label.isOriginAnchorBottom()) { + label.setOriginY(bounds.height() - (oldBounds.height() - label.oldY)); + } else { + label.setOriginY(label.y * heightDelta); + } + } + } + }); + + //update docker + var docker = this.dockers[0]; + if (docker) { + docker.bounds.unregisterCallback(this._dockerChangedCallback); + if (!this._dockerUpdated) { + docker.bounds.centerMoveTo(this.bounds.center()); + this._dockerUpdated = false; + } + + docker.update(); + docker.bounds.registerCallback(this._dockerChangedCallback); + } + this.isResized = false; + } + + this.refresh(); + + this.isChanged = false; + + this._oldBounds = this.bounds.clone(); + } + + this.children.each(function (value) { + if (!(value instanceof ORYX.Core.Controls.Docker)) { + value._update(); + } + }); + + if (this.dockers.length > 0 && !this.dockers.first().getDockedShape()) { + this.dockers.each(function (docker) { + docker.bounds.centerMoveTo(this.bounds.center()) + }.bind(this)) + } + + /*this.incoming.each((function(edge) { + if(!(this.dockers[0] && this.dockers[0].getDockedShape() instanceof ORYX.Core.Node)) + edge._update(true); + }).bind(this)); + + this.outgoing.each((function(edge) { + if(!(this.dockers[0] && this.dockers[0].getDockedShape() instanceof ORYX.Core.Node)) + edge._update(true); + }).bind(this)); */ + }, + + /** + * This method repositions and resizes the SVG representation + * of the shape. + */ + refresh: function () { + arguments.callee.$.refresh.apply(this, arguments); + + /** Movement */ + var x = this.bounds.upperLeft().x; + var y = this.bounds.upperLeft().y; + + // Move owner element + this.node.firstChild.setAttributeNS(null, "transform", "translate(" + x + ", " + y + ")"); + // Move magnets + this.node.childNodes[1].childNodes[1].setAttributeNS(null, "transform", "translate(" + x + ", " + y + ")"); + + /** Resize */ + + //iterate over all relevant svg elements and update them + this._svgShapes.each(function (svgShape) { + svgShape.update(); + }); + }, + + _dockerChanged: function () { + var docker = this.dockers[0]; + + //set the bounds of the the association + this.bounds.centerMoveTo(docker.bounds.center()); + + this._dockerUpdated = true; + //this._update(true); + }, + + /** + * This method traverses a tree of SVGElements and returns + * all SVGShape objects. For each basic shape or path element + * a SVGShape object is initialized. + * + * @param svgNode {SVGElement} + * @return {Array} Array of SVGShape objects + */ + _initSVGShapes: function (svgNode) { + var svgShapes = []; + try { + var svgShape = new ORYX.Core.SVG.SVGShape(svgNode); + svgShapes.push(svgShape); + } catch (e) { + //do nothing + } + + if (svgNode.hasChildNodes()) { + for (var i = 0; i < svgNode.childNodes.length; i++) { + svgShapes = svgShapes.concat(this._initSVGShapes(svgNode.childNodes[i])); + } + } + + return svgShapes; + }, + + /** + * Calculate if the point is inside the Shape + * @param {PointX} + * @param {PointY} + * @param {absoluteBounds} optional: for performance + */ + isPointIncluded: function (pointX, pointY, absoluteBounds) { + // If there is an arguments with the absoluteBounds + var absBounds = absoluteBounds && absoluteBounds instanceof ORYX.Core.Bounds ? absoluteBounds : this.absoluteBounds(); + + if (!absBounds.isIncluded(pointX, pointY)) { + return false; + } else { + + } + + + //point = Object.clone(point); + var ul = absBounds.upperLeft(); + var x = pointX - ul.x; + var y = pointY - ul.y; + + var i = 0; + do { + var isPointIncluded = this._svgShapes[i++].isPointIncluded(x, y); + } while (!isPointIncluded && i < this._svgShapes.length) + + return isPointIncluded; + + /*return this._svgShapes.any(function(svgShape){ + return svgShape.isPointIncluded(point); + });*/ + }, + + + /** + * Calculate if the point is over an special offset area + * @param {Point} + */ + isPointOverOffset: function (pointX, pointY) { + var isOverEl = arguments.callee.$.isPointOverOffset.apply(this, arguments); + + if (isOverEl) { + + // If there is an arguments with the absoluteBounds + var absBounds = this.absoluteBounds(); + absBounds.widen(-ORYX.CONFIG.BORDER_OFFSET); + + if (!absBounds.isIncluded(pointX, pointY)) { + return true; + } + } + + return false; + + }, + + serialize: function () { + var result = arguments.callee.$.serialize.apply(this); + + // Add the docker's bounds + // nodes only have at most one docker! + this.dockers.each((function (docker) { + if (docker.getDockedShape()) { + var center = docker.referencePoint; + center = center ? center : docker.bounds.center(); + result.push({ + name: 'docker', + prefix: 'oryx', + value: $H(center).values().join(','), + type: 'literal' + }); + } + }).bind(this)); + + // Get the spezific serialized object from the stencil + try { + //result = this.getStencil().serialize(this, result); + + var serializeEvent = this.getStencil().serialize(); + + /* + * call serialize callback by reference, result should be found + * in serializeEvent.result + */ + if (serializeEvent.type) { + serializeEvent.shape = this; + serializeEvent.data = result; + serializeEvent.result = undefined; + serializeEvent.forceExecution = true; + + this._delegateEvent(serializeEvent); + + if (serializeEvent.result) { + result = serializeEvent.result; + } + } + } catch (e) { + } + return result; + }, + + deserialize: function (data) { + arguments.callee.$.deserialize.apply(this, arguments); + + try { + //data = this.getStencil().deserialize(this, data); + + var deserializeEvent = this.getStencil().deserialize(); + + /* + * call serialize callback by reference, result should be found + * in serializeEventInfo.result + */ + if (deserializeEvent.type) { + deserializeEvent.shape = this; + deserializeEvent.data = data; + deserializeEvent.result = undefined; + deserializeEvent.forceExecution = true; + + this._delegateEvent(deserializeEvent); + if (deserializeEvent.result) { + data = deserializeEvent.result; + } + } + } catch (e) { + } + + // Set the outgoing shapes + var outgoing = data.findAll(function (ser) { + return (ser.prefix + "-" + ser.name) == 'raziel-outgoing' + }); + outgoing.each((function (obj) { + // TODO: Look at Canvas + if (!this.parent) { + return + } + ; + + // Set outgoing Shape + var next = this.getCanvas().getChildShapeByResourceId(obj.value); + + if (next) { + if (next instanceof ORYX.Core.Edge) { + //Set the first docker of the next shape + next.dockers.first().setDockedShape(this); + next.dockers.first().setReferencePoint(next.dockers.first().bounds.center()); + } else if (next.dockers.length > 0) { //next is a node and next has a docker + next.dockers.first().setDockedShape(this); + //next.dockers.first().setReferencePoint({x: this.bounds.width() / 2.0, y: this.bounds.height() / 2.0}); + } + } + + }).bind(this)); + + if (this.dockers.length === 1) { + var dockerPos; + dockerPos = data.find(function (entry) { + return (entry.prefix + "-" + entry.name === "oryx-dockers"); + }); + + if (dockerPos) { + var points = dockerPos.value.replace(/,/g, " ").split(" ").without("").without("#"); + if (points.length === 2 && this.dockers[0].getDockedShape()) { + this.dockers[0].setReferencePoint({ + x: parseFloat(points[0]), + y: parseFloat(points[1]) + }); + } else { + this.dockers[0].bounds.centerMoveTo(parseFloat(points[0]), parseFloat(points[1])); + } + } + } + }, + + /** + * This method excepts the SVGDoucment that is the SVG representation + * of this shape. * The bounds of the shape are calculated, the SVG representation's upper left point * is moved to 0,0 and it the method sets if this shape is resizable. * - * @param {SVGDocument} svgDocument + * @param {SVGDocument} svgDocument + */ + _init: function (svgDocument) { + arguments.callee.$._init.apply(this, arguments); + + var svgNode = svgDocument.getElementsByTagName("g")[0]; //outer most g node + // set all required attributes + var attributeTitle = svgDocument.ownerDocument.createAttribute("title"); + attributeTitle.nodeValue = this.getStencil().title(); + svgNode.setAttributeNode(attributeTitle); + + var attributeId = svgDocument.ownerDocument.createAttribute("id"); + attributeId.nodeValue = this.id; + svgNode.setAttributeNode(attributeId); + + // + var stencilTargetNode = this.node.childNodes[0].childNodes[0]; //" + svgNode = stencilTargetNode.appendChild(svgNode); + + // Add to the EventHandler + this.addEventHandlers(svgNode.parentNode); + + /**set minimum and maximum size*/ + var minSizeAttr = svgNode.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "minimumSize"); + if (minSizeAttr) { + minSizeAttr = minSizeAttr.replace("/,/g", " "); + var minSizeValues = minSizeAttr.split(" "); + minSizeValues = minSizeValues.without(""); + + if (minSizeValues.length > 1) { + this.minimumSize = { + width: parseFloat(minSizeValues[0]), + height: parseFloat(minSizeValues[1]) + }; + } else { + //set minimumSize to (1,1), so that width and height of the stencil can never be (0,0) + this.minimumSize = { + width: 1, + height: 1 + }; + } + } + + var maxSizeAttr = svgNode.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "maximumSize"); + if (maxSizeAttr) { + maxSizeAttr = maxSizeAttr.replace("/,/g", " "); + var maxSizeValues = maxSizeAttr.split(" "); + maxSizeValues = maxSizeValues.without(""); + + if (maxSizeValues.length > 1) { + this.maximumSize = { + width: parseFloat(maxSizeValues[0]), + height: parseFloat(maxSizeValues[1]) + }; + } + } + + if (this.minimumSize && this.maximumSize && + (this.minimumSize.width > this.maximumSize.width || + this.minimumSize.height > this.maximumSize.height)) { + + //TODO wird verschluckt!!! + throw this + ": Minimum Size must be greater than maxiumSize."; + } + + /**get current bounds and adjust it to upperLeft == (0,0)*/ + //initialize all SVGShape objects + this._svgShapes = this._initSVGShapes(svgNode); + + //get upperLeft and lowerRight of stencil + var upperLeft = { + x: undefined, + y: undefined + }; + var lowerRight = { + x: undefined, + y: undefined + }; + var me = this; + this._svgShapes.each(function (svgShape) { + upperLeft.x = (upperLeft.x !== undefined) ? Math.min(upperLeft.x, svgShape.x) : svgShape.x; + upperLeft.y = (upperLeft.y !== undefined) ? Math.min(upperLeft.y, svgShape.y) : svgShape.y; + lowerRight.x = (lowerRight.x !== undefined) ? Math.max(lowerRight.x, svgShape.x + svgShape.width) : svgShape.x + svgShape.width; + lowerRight.y = (lowerRight.y !== undefined) ? Math.max(lowerRight.y, svgShape.y + svgShape.height) : svgShape.y + svgShape.height; + + /** set if resizing is enabled */ + //TODO isResizable durch die beiden anderen booleans ersetzen? + if (svgShape.isHorizontallyResizable) { + me.isHorizontallyResizable = true; + me.isResizable = true; + } + if (svgShape.isVerticallyResizable) { + me.isVerticallyResizable = true; + me.isResizable = true; + } + if (svgShape.anchorTop && svgShape.anchorBottom) { + me.isVerticallyResizable = true; + me.isResizable = true; + } + if (svgShape.anchorLeft && svgShape.anchorRight) { + me.isHorizontallyResizable = true; + me.isResizable = true; + } + }); + + //move all SVGShapes by -upperLeft + this._svgShapes.each(function (svgShape) { + svgShape.x -= upperLeft.x; + svgShape.y -= upperLeft.y; + svgShape.update(); + }); + + //set bounds of shape + //the offsets are also needed for positioning the magnets and the docker + var offsetX = upperLeft.x; + var offsetY = upperLeft.y; + + lowerRight.x -= offsetX; + lowerRight.y -= offsetY; + upperLeft.x = 0; + upperLeft.y = 0; + + //prevent that width or height of initial bounds is 0 + if (lowerRight.x === 0) { + lowerRight.x = 1; + } + if (lowerRight.y === 0) { + lowerRight.y = 1; + } + + this._oldBounds.set(upperLeft, lowerRight); + this.bounds.set(upperLeft, lowerRight); + + /**initialize magnets */ + + var magnets = svgDocument.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_ORYX, "magnets"); + + if (magnets && magnets.length > 0) { + + magnets = $A(magnets[0].getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_ORYX, "magnet")); + + var me = this; + magnets.each(function (magnetElem) { + var magnet = new ORYX.Core.Controls.Magnet({ + eventHandlerCallback: me.eventHandlerCallback + }); + var cx = parseFloat(magnetElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "cx")); + var cy = parseFloat(magnetElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "cy")); + magnet.bounds.centerMoveTo({ + x: cx - offsetX, + y: cy - offsetY + }); + + //get anchors + var anchors = magnetElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "anchors"); + if (anchors) { + anchors = anchors.replace("/,/g", " "); + anchors = anchors.split(" ").without(""); + for (var i = 0; i < anchors.length; i++) { + switch (anchors[i].toLowerCase()) { + case "left": + magnet.anchorLeft = true; + break; + case "right": + magnet.anchorRight = true; + break; + case "top": + magnet.anchorTop = true; + break; + case "bottom": + magnet.anchorBottom = true; + break; + } + } + } + + me.add(magnet); + + //check, if magnet is default magnet + if (!this._defaultMagnet) { + var defaultAttr = magnetElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "default"); + if (defaultAttr && defaultAttr.toLowerCase() === "yes") { + me._defaultMagnet = magnet; + } + } + }); + } else { + // Add a Magnet in the Center of Shape + var magnet = new ORYX.Core.Controls.Magnet(); + magnet.bounds.centerMoveTo(this.bounds.width() / 2, this.bounds.height() / 2); + this.add(magnet); + } + + /**initialize docker */ + var dockerElem = svgDocument.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_ORYX, "docker"); + + if (dockerElem && dockerElem.length > 0) { + dockerElem = dockerElem[0]; + var docker = this.createDocker(); + var cx = parseFloat(dockerElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "cx")); + var cy = parseFloat(dockerElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "cy")); + docker.bounds.centerMoveTo({ + x: cx - offsetX, + y: cy - offsetY + }); + + //get anchors + var anchors = dockerElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "anchors"); + if (anchors) { + anchors = anchors.replace("/,/g", " "); + anchors = anchors.split(" ").without(""); + + for (var i = 0; i < anchors.length; i++) { + switch (anchors[i].toLowerCase()) { + case "left": + docker.anchorLeft = true; + break; + case "right": + docker.anchorRight = true; + break; + case "top": + docker.anchorTop = true; + break; + case "bottom": + docker.anchorBottom = true; + break; + } + } + } + } + + /**initialize labels*/ + var textElems = svgNode.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'text'); + $A(textElems).each((function (textElem) { + var label = new ORYX.Core.SVG.Label({ + textElement: textElem, + shapeId: this.id + }); + label.x -= offsetX; + label.y -= offsetY; + this._labels[label.id] = label; + + label.registerOnChange(this.layout.bind(this)); + + // Only apply fitting on form-components + if (this._stencil.id().indexOf(ORYX.CONFIG.FORM_ELEMENT_ID_PREFIX) == 0) { + label.registerOnChange(this.fitToLabels.bind(this)); + } + + }).bind(this)); + }, + + fitToLabels: function () { + var y = 0; + + this.getLabels().each(function (label) { + var lr = label.getY() + label.getHeight(); + if (lr > y) { + y = lr; + } + }); + + var bounds = this.bounds; + var boundsChanged = false; + + if (this.minimumSize) { + // Check if y-value exceeds the min-value. If not, stick to this value. + var minHeight = this.minimumSize.height; + if (y < minHeight && bounds.height() > minHeight && minHeight > this.forcedHeight) { + bounds.set(bounds.upperLeft().x, bounds.upperLeft().y, bounds.lowerRight().x, bounds.upperLeft().y + minHeight); + boundsChanged = true; + } else if (y > minHeight && bounds.height() != y && y > this.forcedHeight) { + bounds.set(bounds.upperLeft().x, bounds.upperLeft().y, bounds.lowerRight().x, bounds.upperLeft().y + y); + boundsChanged = true; + } else if (bounds.height() > this.forcedHeight && this.forcedHeight > 0) { + bounds.set(bounds.upperLeft().x, bounds.upperLeft().y, bounds.lowerRight().x, bounds.upperLeft().y + this.forcedHeight); + boundsChanged = true; + } + } + + if (boundsChanged) { + // Force facade to re-layout since bounds are changed AFTER layout has been performed + if (this.facade.getCanvas() != null) { + this.facade.getCanvas().update(); + } + + // Re-select if needed to force the select + if (this.facade.getSelection().member(this)) { + var selectedNow = this.facade.getSelection(); + this.facade.setSelection([]); + this.facade.setSelection(selectedNow); + } + } + }, + + /** + * Override the Method, that a docker is not shown + * + */ + createDocker: function () { + var docker = new ORYX.Core.Controls.Docker({eventHandlerCallback: this.eventHandlerCallback}); + docker.bounds.registerCallback(this._dockerChangedCallback); + + this.dockers.push(docker); + docker.parent = this; + docker.bounds.registerCallback(this._changedCallback); + + return docker + }, + + toString: function () { + return this._stencil.title() + " " + this.id + } +}; +ORYX.Core.Node = ORYX.Core.Shape.extend(ORYX.Core.Node); +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +NAMESPACE_SVG = "http://www.w3.org/2000/svg"; +NAMESPACE_ORYX = "http://www.b3mn.org/oryx"; + + +/** + * Init namespaces + */ +if (!ORYX) { + var ORYX = {}; +} +if (!ORYX.Core) { + ORYX.Core = {}; +} + + +/** + * @classDescription Abstract base class for all connections. + * @extends {ORYX.Core.Shape} + * @param options {Object} + * + * TODO da die verschiebung der Edge nicht ueber eine + * translation gemacht wird, die sich auch auf alle kind UIObjects auswirkt, + * muessen die kinder hier beim verschieben speziell betrachtet werden. + * Das sollte ueberarbeitet werden. + * + */ +ORYX.Core.Edge = { + /** + * Constructor + * @param {Object} options + * @param {Stencil} stencil + */ + construct: function (options, stencil, facade) { + arguments.callee.$.construct.apply(this, arguments); + + this.isMovable = true; + this.isSelectable = true; + + this._dockerUpdated = false; + + this._markers = new Hash(); //a hash map of SVGMarker objects where keys are the marker ids + this._paths = []; + this._interactionPaths = []; + this._dockersByPath = new Hash(); + this._markersByPath = new Hash(); + + /* Data structures to store positioning information of attached child nodes */ + this.attachedNodePositionData = new Hash(); + + //TODO was muss hier initial erzeugt werden? + var stencilNode = this.node.childNodes[0].childNodes[0]; + stencilNode = ORYX.Editor.graft("http://www.w3.org/2000/svg", stencilNode, ['g', { + "pointer-events": "painted" + }]); + + //Add to the EventHandler + this.addEventHandlers(stencilNode.parentNode); + + + this._oldBounds = this.bounds.clone(); + + //load stencil + this._init(this._stencil.view()); + + if (stencil instanceof Array) { + this.deserialize(stencil); + } + + }, + + _update: function (force) { + if (this._dockerUpdated || this.isChanged || force) { + + this.dockers.invoke("update"); + + if (false && (this.bounds.width() === 0 || this.bounds.height() === 0)) { + var width = this.bounds.width(); + var height = this.bounds.height(); + this.bounds.extend({ + x: width === 0 ? 2 : 0, + y: height === 0 ? 2 : 0 + }); + this.bounds.moveBy({ + x: width === 0 ? -1 : 0, + y: height === 0 ? -1 : 0 + }); + + } + + // TODO: Bounds muss abhaengig des Eltern-Shapes gesetzt werden + var upL = this.bounds.upperLeft(); + var oldUpL = this._oldBounds.upperLeft(); + var oldWidth = this._oldBounds.width() === 0 ? this.bounds.width() : this._oldBounds.width(); + var oldHeight = this._oldBounds.height() === 0 ? this.bounds.height() : this._oldBounds.height(); + var diffX = upL.x - oldUpL.x; + var diffY = upL.y - oldUpL.y; + var diffWidth = (this.bounds.width() / oldWidth) || 1; + var diffHeight = (this.bounds.height() / oldHeight) || 1; + + this.dockers.each((function (docker) { + // Unregister on BoundsChangedCallback + docker.bounds.unregisterCallback(this._dockerChangedCallback); + + // If there is any changes at the edge and is there is not an DockersUpdate + // set the new bounds to the docker + if (!this._dockerUpdated) { + docker.bounds.moveBy(diffX, diffY); + + if (diffWidth !== 1 || diffHeight !== 1) { + var relX = docker.bounds.upperLeft().x - upL.x; + var relY = docker.bounds.upperLeft().y - upL.y; + + docker.bounds.moveTo(upL.x + relX * diffWidth, upL.y + relY * diffHeight); + } + } + // Do Docker update and register on DockersBoundChange + docker.update(); + docker.bounds.registerCallback(this._dockerChangedCallback); + + }).bind(this)); + + if (this._dockerUpdated) { + var a = this.dockers.first().bounds.center(); + var b = this.dockers.first().bounds.center(); + + this.dockers.each((function (docker) { + var center = docker.bounds.center(); + a.x = Math.min(a.x, center.x); + a.y = Math.min(a.y, center.y); + b.x = Math.max(b.x, center.x); + b.y = Math.max(b.y, center.y); + }).bind(this)); + + //set the bounds of the the association + this.bounds.set(Object.clone(a), Object.clone(b)); + } + + upL = this.bounds.upperLeft(); + oldUpL = this._oldBounds.upperLeft(); + diffWidth = (this.bounds.width() / (oldWidth || this.bounds.width())); + diffHeight = (this.bounds.height() / (oldHeight || this.bounds.height())); + diffX = upL.x - oldUpL.x; + diffY = upL.y - oldUpL.y; + + //reposition labels + this.getLabels().each(function (label) { + + if (label.getReferencePoint()) { + var ref = label.getReferencePoint(); + var from = ref.segment.from, to = ref.segment.to; + if (!from || !from.parent || !to || !to.parent) { + return; + } + + var fromPosition = from.bounds.center(), toPosition = to.bounds.center(); + + if (fromPosition.x === ref.segment.fromPosition.x && fromPosition.y === ref.segment.fromPosition.y && + toPosition.x === ref.segment.toPosition.x && toPosition.y === ref.segment.toPosition.y && !ref.dirty) { + return; + } + + if (!this.parent.initializingShapes) { + var oldDistance = ORYX.Core.Math.getDistanceBetweenTwoPoints(ref.segment.fromPosition, ref.segment.toPosition, ref.intersection); + var newIntersection = ORYX.Core.Math.getPointBetweenTwoPoints(fromPosition, toPosition, isNaN(oldDistance) ? 0.5 : oldDistance); + + /** + * Set position + */ + // Get the orthogonal identity vector of the current segment + var oiv = ORYX.Core.Math.getOrthogonalIdentityVector(fromPosition, toPosition); + var isHor = Math.abs(oiv.y) === 1, isVer = Math.abs(oiv.x) === 1; + oiv.x *= ref.distance; + oiv.y *= ref.distance; // vector * distance + oiv.x += newIntersection.x; + oiv.y += newIntersection.y; // vector + the intersection point + var mx = isHor && ref.orientation && (ref.iorientation || ref.orientation).endsWith("r") ? -label.getWidth() : 0; + var my = isVer && ref.orientation && (ref.iorientation || ref.orientation).startsWith("l") ? -label.getHeight() + 2 : 0; + label.setX(oiv.x + mx); + label.setY(oiv.y + my); + + // Update the reference point + this.updateReferencePointOfLabel(label, newIntersection, from, to); + } else { + var oiv = ORYX.Core.Math.getOrthogonalIdentityVector(fromPosition, toPosition); + oiv.x *= ref.distance; + oiv.y *= ref.distance; // vector * distance + oiv.x += ref.intersection.x; + oiv.y += ref.intersection.y; // vector + the intersection point + label.setX(oiv.x); + label.setY(oiv.y); + ref.segment.fromPosition = fromPosition; + ref.segment.toPosition = toPosition; + } + + return; + } + + // Update label position if no reference point is set + if (label.position && !this.parent.initializingShapes) { + var x = label.position.x + (diffX * (diffWidth || 1)); + if (x > this.bounds.lowerRight().x) { + x += this.bounds.width() - (this.bounds.width() / (diffWidth || 1)); + } + + var y = label.position.y + (diffY * (diffHeight || 1)); + if (y > this.bounds.lowerRight().y) { + y += this.bounds.height() - (this.bounds.height() / (diffHeight || 1)); + } + label.setX(x); + label.setY(y); + return; + } + + switch (label.getEdgePosition()) { + case "starttop": + var angle = this._getAngle(this.dockers[0], this.dockers[1]); + var pos = this.dockers.first().bounds.center(); + + if (angle <= 90 || angle > 270) { + label.horizontalAlign("left"); + label.verticalAlign("bottom"); + label.x = pos.x + label.getOffsetTop(); + label.y = pos.y - label.getOffsetTop(); + label.rotate(360 - angle, pos); + } else { + label.horizontalAlign("right"); + label.verticalAlign("bottom"); + label.x = pos.x - label.getOffsetTop(); + label.y = pos.y - label.getOffsetTop(); + label.rotate(180 - angle, pos); + } + + break; + + case "startmiddle": + var angle = this._getAngle(this.dockers[0], this.dockers[1]); + var pos = this.dockers.first().bounds.center(); + + if (angle <= 90 || angle > 270) { + label.horizontalAlign("left"); + label.verticalAlign("bottom"); + label.x = pos.x + 2; + label.y = pos.y + 4; + label.rotate(360 - angle, pos); + } else { + label.horizontalAlign("right"); + label.verticalAlign("bottom"); + label.x = pos.x + 1; + label.y = pos.y + 4; + label.rotate(180 - angle, pos); + } + + break; + + case "startbottom": + var angle = this._getAngle(this.dockers[0], this.dockers[1]); + var pos = this.dockers.first().bounds.center(); + + if (angle <= 90 || angle > 270) { + label.horizontalAlign("left"); + label.verticalAlign("top"); + label.x = pos.x + label.getOffsetBottom(); + label.y = pos.y + label.getOffsetBottom(); + label.rotate(360 - angle, pos); + } else { + label.horizontalAlign("right"); + label.verticalAlign("top"); + label.x = pos.x - label.getOffsetBottom(); + label.y = pos.y + label.getOffsetBottom(); + label.rotate(180 - angle, pos); + } + + break; + case "midtop": + var numOfDockers = this.dockers.length; + if (numOfDockers % 2 == 0) { + var angle = this._getAngle(this.dockers[numOfDockers / 2 - 1], this.dockers[numOfDockers / 2]) + var pos1 = this.dockers[numOfDockers / 2 - 1].bounds.center(); + var pos2 = this.dockers[numOfDockers / 2].bounds.center(); + var pos = {x: (pos1.x + pos2.x) / 2.0, y: (pos1.y + pos2.y) / 2.0}; + + label.horizontalAlign("center"); + label.verticalAlign("bottom"); + label.x = pos.x; + label.y = pos.y - label.getOffsetTop(); + + if (angle <= 90 || angle > 270) { + label.rotate(360 - angle, pos); + } else { + label.rotate(180 - angle, pos); + } + } else { + var index = parseInt(numOfDockers / 2); + var angle = this._getAngle(this.dockers[index], this.dockers[index + 1]) + var pos = this.dockers[index].bounds.center(); + + if (angle <= 90 || angle > 270) { + label.horizontalAlign("left"); + label.verticalAlign("bottom"); + label.x = pos.x + label.getOffsetTop(); + label.y = pos.y - label.getOffsetTop(); + label.rotate(360 - angle, pos); + } else { + label.horizontalAlign("right"); + label.verticalAlign("bottom"); + label.x = pos.x - label.getOffsetTop(); + label.y = pos.y - label.getOffsetTop(); + label.rotate(180 - angle, pos); + } + } + + break; + case "midbottom": + var numOfDockers = this.dockers.length; + if (numOfDockers % 2 == 0) { + var angle = this._getAngle(this.dockers[numOfDockers / 2 - 1], this.dockers[numOfDockers / 2]) + var pos1 = this.dockers[numOfDockers / 2 - 1].bounds.center(); + var pos2 = this.dockers[numOfDockers / 2].bounds.center(); + var pos = {x: (pos1.x + pos2.x) / 2.0, y: (pos1.y + pos2.y) / 2.0}; + + label.horizontalAlign("center"); + label.verticalAlign("top"); + label.x = pos.x; + label.y = pos.y + label.getOffsetTop(); + + if (angle <= 90 || angle > 270) { + label.rotate(360 - angle, pos); + } else { + label.rotate(180 - angle, pos); + } + } else { + var index = parseInt(numOfDockers / 2); + var angle = this._getAngle(this.dockers[index], this.dockers[index + 1]) + var pos = this.dockers[index].bounds.center(); + + if (angle <= 90 || angle > 270) { + label.horizontalAlign("left"); + label.verticalAlign("top"); + label.x = pos.x + label.getOffsetBottom(); + label.y = pos.y + label.getOffsetBottom(); + label.rotate(360 - angle, pos); + } else { + label.horizontalAlign("right"); + label.verticalAlign("top"); + label.x = pos.x - label.getOffsetBottom(); + label.y = pos.y + label.getOffsetBottom(); + label.rotate(180 - angle, pos); + } + } + + break; + case "endtop": + var length = this.dockers.length; + var angle = this._getAngle(this.dockers[length - 2], this.dockers[length - 1]); + var pos = this.dockers.last().bounds.center(); + + if (angle <= 90 || angle > 270) { + label.horizontalAlign("right"); + label.verticalAlign("bottom"); + label.x = pos.x - label.getOffsetTop(); + label.y = pos.y - label.getOffsetTop(); + label.rotate(360 - angle, pos); + } else { + label.horizontalAlign("left"); + label.verticalAlign("bottom"); + label.x = pos.x + label.getOffsetTop(); + label.y = pos.y - label.getOffsetTop(); + label.rotate(180 - angle, pos); + } + + break; + case "endbottom": + var length = this.dockers.length; + var angle = this._getAngle(this.dockers[length - 2], this.dockers[length - 1]); + var pos = this.dockers.last().bounds.center(); + + if (angle <= 90 || angle > 270) { + label.horizontalAlign("right"); + label.verticalAlign("top"); + label.x = pos.x - label.getOffsetBottom(); + label.y = pos.y + label.getOffsetBottom(); + label.rotate(360 - angle, pos); + } else { + label.horizontalAlign("left"); + label.verticalAlign("top"); + label.x = pos.x + label.getOffsetBottom(); + label.y = pos.y + label.getOffsetBottom(); + label.rotate(180 - angle, pos); + } + + break; + } + }.bind(this)); + + this.children.each(function (value) { + if (value instanceof ORYX.Core.Node) { + this.calculatePositionOfAttachedChildNode.call(this, value); + } + }.bind(this)); + + this.refreshAttachedNodes(); + this.refresh(); + + this.isChanged = false; + this._dockerUpdated = false; + + this._oldBounds = this.bounds.clone(); + } + + + // IE10 specific fix, start and end-markes get left behind when moving path + var userAgent = navigator.userAgent; + if (navigator.appVersion.indexOf("MSIE 10") !== -1 || (userAgent.indexOf('Trident') !== -1 && userAgent.indexOf('rv:11') !== -1)) { + this.node.parentNode.insertBefore(this.node, this.node); + } + }, + + /** + * Moves a point to the upperLeft of a node's bounds. + * + * @param {point} point + * The point to move + * @param {ORYX.Core.Bounds} bounds + * The Bounds of the related noe + */ + movePointToUpperLeftOfNode: function (point, bounds) { + point.x -= bounds.width() / 2; + point.y -= bounds.height() / 2; + }, + + /** + * Refreshes the visual representation of edge's attached nodes. + */ + refreshAttachedNodes: function () { + this.attachedNodePositionData.values().each(function (nodeData) { + var startPoint = nodeData.segment.docker1.bounds.center(); + var endPoint = nodeData.segment.docker2.bounds.center(); + this.relativizePoint(startPoint); + this.relativizePoint(endPoint); + + var newNodePosition = new Object(); + + /* Calculate new x-coordinate */ + newNodePosition.x = startPoint.x + + nodeData.relativDistanceFromDocker1 + * (endPoint.x - startPoint.x); + + /* Calculate new y-coordinate */ + newNodePosition.y = startPoint.y + + nodeData.relativDistanceFromDocker1 + * (endPoint.y - startPoint.y); + + /* Convert new position to the upper left of the node */ + this.movePointToUpperLeftOfNode(newNodePosition, nodeData.node.bounds); + + /* Move node to its new position */ + nodeData.node.bounds.moveTo(newNodePosition); + nodeData.node._update(); + + }.bind(this)); + }, + + /** + * Calculates the position of an edge's child node. The node is placed on + * the path of the edge. + * + * @param {node} + * The node to calculate the new position + * @return {Point} + * The calculated upper left point of the node's shape. + */ + calculatePositionOfAttachedChildNode: function (node) { + /* Initialize position */ + var position = new Object(); + position.x = 0; + position.y = 0; + + /* Case: Node was just added */ + if (!this.attachedNodePositionData[node.getId()]) { + this.attachedNodePositionData[node.getId()] = new Object(); + this.attachedNodePositionData[node.getId()] + .relativDistanceFromDocker1 = 0; + this.attachedNodePositionData[node.getId()].node = node; + this.attachedNodePositionData[node.getId()].segment = new Object(); + this.findEdgeSegmentForNode(node); + } else if (node.isChanged) { + this.findEdgeSegmentForNode(node); + } + + + }, + + /** + * Finds the appropriate edge segement for a node. + * The segment is choosen, which has the smallest distance to the node. + * + * @param {ORYX.Core.Node} node + * The concerning node + */ + findEdgeSegmentForNode: function (node) { + var length = this.dockers.length; + var smallestDistance = undefined; + + for (i = 1; i < length; i++) { + var lineP1 = this.dockers[i - 1].bounds.center(); + var lineP2 = this.dockers[i].bounds.center(); + this.relativizePoint(lineP1); + this.relativizePoint(lineP2); + + var nodeCenterPoint = node.bounds.center(); + var distance = ORYX.Core.Math.distancePointLinie( + lineP1, + lineP2, + nodeCenterPoint, + true); + + if ((distance || distance == 0) && ((!smallestDistance && smallestDistance != 0) + || distance < smallestDistance)) { + + smallestDistance = distance; + + this.attachedNodePositionData[node.getId()].segment.docker1 = + this.dockers[i - 1]; + this.attachedNodePositionData[node.getId()].segment.docker2 = + this.dockers[i]; + + } + + /* Either the distance does not match the segment or the distance + * between docker1 and docker2 is 0 + * + * In this case choose the nearest docker as attaching point. + * + */ + if (!distance && !smallestDistance && smallestDistance != 0) { + (ORYX.Core.Math.getDistancePointToPoint(nodeCenterPoint, lineP1) + < ORYX.Core.Math.getDistancePointToPoint(nodeCenterPoint, lineP2)) ? + this.attachedNodePositionData[node.getId()].relativDistanceFromDocker1 = 0 : + this.attachedNodePositionData[node.getId()].relativDistanceFromDocker1 = 1; + this.attachedNodePositionData[node.getId()].segment.docker1 = + this.dockers[i - 1]; + this.attachedNodePositionData[node.getId()].segment.docker2 = + this.dockers[i]; + } + } + + /* Calculate position on edge segment for the node */ + if (smallestDistance || smallestDistance == 0) { + this.attachedNodePositionData[node.getId()].relativDistanceFromDocker1 = + this.getLineParameterForPosition( + this.attachedNodePositionData[node.getId()].segment.docker1, + this.attachedNodePositionData[node.getId()].segment.docker2, + node); + } + }, + + + /** + * + * @param {ORYX.Core.Node|Object} node or position + * @return {Object} An object with the following attribute: {ORYX.Core.Docker} fromDocker, {ORYX.Core.Docker} toDocker, {X/Y} position, {int} distance + */ + findSegment: function (node) { + + var length = this.dockers.length; + var result; + + var nodeCenterPoint = node instanceof ORYX.Core.UIObject ? node.bounds.center() : node; + + for (i = 1; i < length; i++) { + var lineP1 = this.dockers[i - 1].bounds.center(); + var lineP2 = this.dockers[i].bounds.center(); + + var distance = ORYX.Core.Math.distancePointLinie(lineP1, lineP2, nodeCenterPoint, true); + + if (typeof distance == "number" && (result === undefined || distance < result.distance)) { + result = { + distance: distance, + fromDocker: this.dockers[i - 1], + toDocker: this.dockers[i] + } + + } + } + return result; + }, + + /** + * Returns the value of the scalar to determine the position of the node on + * line defined by docker1 and docker2. + * + * @param {point} docker1 + * The docker that defines the start of the line segment + * @param {point} docker2 + * The docker that defines the end of the line segment + * @param {ORYX.Core.Node} node + * The concerning node + * + * @return {float} positionParameter + * The scalar value to determine the position on the line + */ + getLineParameterForPosition: function (docker1, docker2, node) { + var dockerPoint1 = docker1.bounds.center(); + var dockerPoint2 = docker2.bounds.center(); + this.relativizePoint(dockerPoint1); + this.relativizePoint(dockerPoint2); + + var intersectionPoint = ORYX.Core.Math.getPointOfIntersectionPointLine( + dockerPoint1, + dockerPoint2, + node.bounds.center(), true); + if (!intersectionPoint) { + return 0; + } + + var relativeDistance = + ORYX.Core.Math.getDistancePointToPoint(intersectionPoint, dockerPoint1) / + ORYX.Core.Math.getDistancePointToPoint(dockerPoint1, dockerPoint2); + + return relativeDistance; + }, + /** + * Makes point relative to the upper left of the edge's bound. + * + * @param {point} point + * The point to relativize + */ + relativizePoint: function (point) { + point.x -= this.bounds.upperLeft().x; + point.y -= this.bounds.upperLeft().y; + }, + + /** + * Move the first and last docker and calls the refresh method. + * Attention: This does not calculates intersection point between the + * edge and the bounded nodes. This only works if only the nodes are + * moves. + * + */ + optimizedUpdate: function () { + + var updateDocker = function (docker) { + if (!docker._dockedShape || !docker._dockedShapeBounds) + return; + var off = { + x: docker._dockedShape.bounds.a.x - docker._dockedShapeBounds.a.x, + y: docker._dockedShape.bounds.a.y - docker._dockedShapeBounds.a.y + }; + docker.bounds.moveBy(off); + docker._dockedShapeBounds.moveBy(off); + } + + updateDocker(this.dockers.first()); + updateDocker(this.dockers.last()); + + this.refresh(); + }, + + refresh: function () { + //call base class refresh method + arguments.callee.$.refresh.apply(this, arguments); + + //TODO consider points for marker mids + var lastPoint; + this._paths.each((function (path, index) { + var dockers = this._dockersByPath[path.id]; + var c = undefined; + var d = undefined; + if (lastPoint) { + d = "M" + lastPoint.x + " " + lastPoint.y; + } else { + c = dockers[0].bounds.center(); + lastPoint = c; + + d = "M" + c.x + " " + c.y; + } + + for (var i = 1; i < dockers.length; i++) { + // for each docker, draw a line to the center + c = dockers[i].bounds.center(); + d = d + "L" + c.x + " " + c.y + " "; + lastPoint = c; + } + + path.setAttributeNS(null, "d", d); + this._interactionPaths[index].setAttributeNS(null, "d", d); + + }).bind(this)); + + + /* move child shapes of an edge */ + if (this.getChildNodes().length > 0) { + var x = this.bounds.upperLeft().x; + var y = this.bounds.upperLeft().y; + + this.node.firstChild.childNodes[1].setAttributeNS(null, "transform", "translate(" + x + ", " + y + ")"); + } + + }, + + /** + * Calculate the Border Intersection Point between two points + * @param {PointA} + * @param {PointB} + */ + getIntersectionPoint: function () { + + var length = Math.floor(this.dockers.length / 2) + + return ORYX.Core.Math.midPoint(this.dockers[length - 1].bounds.center(), this.dockers[length].bounds.center()) + }, + + /** + * Returns TRUE if the bounds is over the edge + * @param {Bounds} + * + */ + isBoundsIncluded: function (bounds) { + var dockers = this.dockers, size = dockers.length; + return dockers.any(function (docker, i) { + if (i == size - 1) { + return false; + } + var a = docker.bounds.center(); + var b = dockers[i + 1].bounds.center(); + + return ORYX.Core.Math.isRectOverLine(a.x, a.y, b.x, b.y, bounds.a.x, bounds.a.y, bounds.b.x, bounds.b.y); + }); + }, + + /** + * Calculate if the point is inside the Shape + * @param {PointX} + * @param {PointY} + */ + isPointIncluded: function (pointX, pointY) { + + var isbetweenAB = this.absoluteBounds().isIncluded(pointX, pointY, + ORYX.CONFIG.OFFSET_EDGE_BOUNDS); + + var isPointIncluded = undefined; + + if (isbetweenAB && this.dockers.length > 0) { + + var i = 0; + var point1, point2; + + + do { + + point1 = this.dockers[i].bounds.center(); + point2 = this.dockers[++i].bounds.center(); + + isPointIncluded = ORYX.Core.Math.isPointInLine(pointX, pointY, + point1.x, point1.y, + point2.x, point2.y, + ORYX.CONFIG.OFFSET_EDGE_BOUNDS); + + } while (!isPointIncluded && i < this.dockers.length - 1) + + } + + return isPointIncluded; + + }, + + + /** + * Calculate if the point is over an special offset area + * @param {Point} + */ + isPointOverOffset: function () { + return false + }, + + /** + * Returns TRUE if the given node + * is a child node of the shapes node + * @param {Element} node + * @return {Boolean} + * + */ + containsNode: function (node) { + if (this._paths.include(node) || + this._interactionPaths.include(node)) { + return true; + } + return false; + }, + + /** + * Returns the angle of the line between two dockers + * (0 - 359.99999999) + */ + _getAngle: function (docker1, docker2) { + var p1 = docker1 instanceof ORYX.Core.Controls.Docker ? docker1.absoluteCenterXY() : docker1; + var p2 = docker2 instanceof ORYX.Core.Controls.Docker ? docker2.absoluteCenterXY() : docker2; + + return ORYX.Core.Math.getAngle(p1, p2); + }, + + alignDockers: function () { + this._update(true); + + var firstPoint = this.dockers.first().bounds.center(); + var lastPoint = this.dockers.last().bounds.center(); + + var deltaX = lastPoint.x - firstPoint.x; + var deltaY = lastPoint.y - firstPoint.y; + + var numOfDockers = this.dockers.length - 1; + + this.dockers.each((function (docker, index) { + var part = index / numOfDockers; + docker.bounds.unregisterCallback(this._dockerChangedCallback); + docker.bounds.moveTo(firstPoint.x + part * deltaX, firstPoint.y + part * deltaY); + docker.bounds.registerCallback(this._dockerChangedCallback); + }).bind(this)); + + this._dockerChanged(); + }, + + add: function (shape) { + arguments.callee.$.add.apply(this, arguments); + + // If the new shape is a Docker which is not contained + if (shape instanceof ORYX.Core.Controls.Docker && this.dockers.include(shape)) { + // Add it to the dockers list ordered by paths + var pathArray = this._dockersByPath.values()[0]; + if (pathArray) { + pathArray.splice(this.dockers.indexOf(shape), 0, shape); + } + + /* Perform nessary adjustments on the edge's child shapes */ + this.handleChildShapesAfterAddDocker(shape); + } + }, + + /** + * Performs nessary adjustments on the edge's child shapes. + * + * @param {ORYX.Core.Controls.Docker} docker + * The added docker + */ + handleChildShapesAfterAddDocker: function (docker) { + /* Ensure type of Docker */ + if (!docker instanceof ORYX.Core.Controls.Docker) { + return undefined; + } + + var index = this.dockers.indexOf(docker); + if (!(0 < index && index < this.dockers.length - 1)) { + /* Exception: Expect added docker between first and last node of the edge */ + return undefined; + } + + /* Get child nodes concerning the segment of the new docker */ + var startDocker = this.dockers[index - 1]; + var endDocker = this.dockers[index + 1]; + + /* Adjust the position of edge's child nodes */ + var segmentElements = + this.getAttachedNodePositionDataForSegment(startDocker, endDocker); + + var lengthSegmentPart1 = ORYX.Core.Math.getDistancePointToPoint( + startDocker.bounds.center(), + docker.bounds.center()); + var lengthSegmentPart2 = ORYX.Core.Math.getDistancePointToPoint( + endDocker.bounds.center(), + docker.bounds.center()); + + if (!(lengthSegmentPart1 + lengthSegmentPart2)) { + return; + } + + var relativDockerPosition = lengthSegmentPart1 / (lengthSegmentPart1 + lengthSegmentPart2); + + segmentElements.each(function (nodePositionData) { + /* Assign child node to the new segment */ + if (nodePositionData.value.relativDistanceFromDocker1 < relativDockerPosition) { + /* Case: before added Docker */ + nodePositionData.value.segment.docker2 = docker; + nodePositionData.value.relativDistanceFromDocker1 = + nodePositionData.value.relativDistanceFromDocker1 / relativDockerPosition; + } else { + /* Case: after added Docker */ + nodePositionData.value.segment.docker1 = docker; + var newFullDistance = 1 - relativDockerPosition; + var relativPartOfSegment = + nodePositionData.value.relativDistanceFromDocker1 + - relativDockerPosition; + + nodePositionData.value.relativDistanceFromDocker1 = + relativPartOfSegment / newFullDistance; + + } + }) + + + // Update all labels reference points + this.getLabels().each(function (label) { + + var ref = label.getReferencePoint(); + if (!ref) { + return; + } + var index = this.dockers.indexOf(docker); + if (index >= ref.segment.fromIndex && index <= ref.segment.toIndex) { + + var segment = this.findSegment(ref.intersection); + if (!segment) { + // Choose whether the first of the last segment + segment.fromDocker = ref.segment.fromIndex >= (this.dockers.length / 2) ? this.dockers[0] : this.dockers[this.dockers.length - 2]; + segment.toDocker = this.dockers[this.dockers.indexOf(from) + 1]; // The next one if the to docker + } + + var fromPosition = segment.fromDocker.bounds.center(), toPosition = segment.toDocker.bounds.center(); + + var intersection = ORYX.Core.Math.getPointOfIntersectionPointLine( + fromPosition, // P1 - Center of the first docker + toPosition, // P2 - Center of the second docker + ref.intersection, // P3 - Center of the label + true); + //var oldDistance = ORYX.Core.Math.getDistanceBetweenTwoPoints(ref.segment.fromPosition, ref.segment.toPosition, ref.intersection); + //intersection = ORYX.Core.Math.getPointBetweenTwoPoints(fromPosition, toPosition, isNaN(oldDistance) ? 0.5 : (lengthOld*oldDistance)/lengthNew); + + // Update the reference point + this.updateReferencePointOfLabel(label, intersection, segment.fromDocker, segment.toDocker, true); + } + }.bind(this)); + + /* Update attached nodes visual representation */ + this.refreshAttachedNodes(); + }, + + /** + * Returns elements from {@link attachedNodePositiondata} that match the + * segement defined by startDocker and endDocker. + * + * @param {ORYX.Core.Controls.Docker} startDocker + * The docker defining the begin of the segment. + * @param {ORYX.Core.Controls.Docker} endDocker + * The docker defining the begin of the segment. + * + * @return {Hash} attachedNodePositionData + * Child elements matching the segment + */ + getAttachedNodePositionDataForSegment: function (startDocker, endDocker) { + /* Ensure that the segment is defined correctly */ + if (!((startDocker instanceof ORYX.Core.Controls.Docker) + && (endDocker instanceof ORYX.Core.Controls.Docker))) { + return []; + } + + /* Get elements of the segment */ + var elementsOfSegment = + this.attachedNodePositionData.findAll(function (nodePositionData) { + return nodePositionData.value.segment.docker1 === startDocker && + nodePositionData.value.segment.docker2 === endDocker; + }); + + /* Return a Hash in each case */ + if (!elementsOfSegment) { + return []; + } + + return elementsOfSegment; + }, + + /** + * Removes an edge's child shape + */ + remove: function (shape) { + arguments.callee.$.remove.apply(this, arguments); + + if (this.attachedNodePositionData[shape.getId()]) { + delete this.attachedNodePositionData[shape.getId()]; + } + + /* Adjust child shapes if neccessary */ + if (shape instanceof ORYX.Core.Controls.Docker) { + this.handleChildShapesAfterRemoveDocker(shape); + } + }, + + updateReferencePointOfLabel: function (label, intersection, from, to, dirty) { + if (!label.getReferencePoint() || !label.isVisible) { + return; + } + + var ref = label.getReferencePoint(); + + // + if (ref.orientation && ref.orientation !== "ce") { + var angle = this._getAngle(from, to); + if (ref.distance >= 0) { + if (angle == 0) { + label.horizontalAlign("left");//ref.orientation == "lr" ? "right" : "left"); + label.verticalAlign("bottom"); + } else if (angle > 0 && angle < 90) { + label.horizontalAlign("right"); + label.verticalAlign("bottom"); + } else if (angle == 90) { + label.horizontalAlign("right"); + label.verticalAlign("top");//ref.orientation == "lr" ? "bottom" : "top"); + } else if (angle > 90 && angle < 180) { + label.horizontalAlign("right"); + label.verticalAlign("top"); + } else if (angle == 180) { + label.horizontalAlign("left");//ref.orientation == "ur" ? "right" : "left"); + label.verticalAlign("top"); + } else if (angle > 180 && angle < 270) { + label.horizontalAlign("left"); + label.verticalAlign("top"); + } else if (angle == 270) { + label.horizontalAlign("left"); + label.verticalAlign("top");//ref.orientation == "ll" ? "bottom" : "top"); + } else if (angle > 270 && angle <= 360) { + label.horizontalAlign("left"); + label.verticalAlign("bottom"); + } + } else { + if (angle == 0) { + label.horizontalAlign("left");//ref.orientation == "ur" ? "right" : "left"); + label.verticalAlign("top"); + } else if (angle > 0 && angle < 90) { + label.horizontalAlign("left"); + label.verticalAlign("top"); + } else if (angle == 90) { + label.horizontalAlign("left"); + label.verticalAlign("top");//ref.orientation == "ll" ? "bottom" : "top"); + } else if (angle > 90 && angle < 180) { + label.horizontalAlign("left"); + label.verticalAlign("bottom"); + } else if (angle == 180) { + label.horizontalAlign("left");//ref.orientation == "lr" ? "right" : "left"); + label.verticalAlign("bottom"); + } else if (angle > 180 && angle < 270) { + label.horizontalAlign("right"); + label.verticalAlign("bottom"); + } else if (angle == 270) { + label.horizontalAlign("right"); + label.verticalAlign("top");//ref.orientation == "lr" ? "bottom" : "top"); + } else if (angle > 270 && angle <= 360) { + label.horizontalAlign("right"); + label.verticalAlign("top"); + } + } + ref.iorientation = ref.iorientation || ref.orientation; + ref.orientation = (label.verticalAlign() == "top" ? "u" : "l") + (label.horizontalAlign() == "left" ? "l" : "r"); + } + + label.setReferencePoint(jQuery.extend({}, { + intersection: intersection, + segment: { + from: from, + fromIndex: this.dockers.indexOf(from), + fromPosition: from.bounds.center(), + to: to, + toIndex: this.dockers.indexOf(to), + toPosition: to.bounds.center() + }, + dirty: dirty || false + }, ref)) + }, + /** + * Adjusts the child shapes of an edges after a docker was removed. + * + * @param{ORYX.Core.Controls.Docker} docker + * The removed docker. + */ + handleChildShapesAfterRemoveDocker: function (docker) { + /* Ensure docker type */ + if (!(docker instanceof ORYX.Core.Controls.Docker)) { + return; + } + + this.attachedNodePositionData.each(function (nodePositionData) { + if (nodePositionData.value.segment.docker1 === docker) { + /* The new start of the segment is the predecessor of docker2. */ + var index = this.dockers.indexOf(nodePositionData.value.segment.docker2); + if (index == -1) { + return; + } + nodePositionData.value.segment.docker1 = this.dockers[index - 1]; + } else if (nodePositionData.value.segment.docker2 === docker) { + /* The new end of the segment is the successor of docker1. */ + var index = this.dockers.indexOf(nodePositionData.value.segment.docker1); + if (index == -1) { + return; + } + nodePositionData.value.segment.docker2 = this.dockers[index + 1]; + } + }.bind(this)); + + // Update all labels reference points + this.getLabels().each(function (label) { + + var ref = label.getReferencePoint(); + if (!ref) { + return; + } + var from = ref.segment.from; + var to = ref.segment.to; + + if (from !== docker && to !== docker) { + return; + } + + var segment = this.findSegment(ref.intersection); + if (!segment) { + from = segment.fromDocker; + to = segment.toDocker; + } else { + from = from === docker ? this.dockers[this.dockers.indexOf(to) - 1] : from; + to = this.dockers[this.dockers.indexOf(from) + 1]; + } + + var intersection = ORYX.Core.Math.getPointOfIntersectionPointLine(from.bounds.center(), to.bounds.center(), ref.intersection, true); + // Update the reference point + this.updateReferencePointOfLabel(label, intersection, from, to, true); + }.bind(this)); + + /* Update attached nodes visual representation */ + this.refreshAttachedNodes(); + }, + + /** + *@deprecated Use the .createDocker() Method and set the point via the bounds + */ + addDocker: function (position, exDocker) { + var lastDocker; + var result; + this._dockersByPath.any((function (pair) { + return pair.value.any((function (docker, index) { + if (!lastDocker) { + lastDocker = docker; + return false; + } else { + var point1 = lastDocker.bounds.center(); + var point2 = docker.bounds.center(); + + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + var ua = navigator.userAgent; + if (ua.indexOf('MSIE') >= 0) { + //IE 10 and below + var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); + if (zoom !== 100) { + additionalIEZoom = zoom / 100 + } + } + } + + if (additionalIEZoom !== 1) { + position.x = position.x / additionalIEZoom; + position.y = position.y / additionalIEZoom; + } + + if (ORYX.Core.Math.isPointInLine(position.x, position.y, point1.x, point1.y, point2.x, point2.y, 10)) { + var path = this._paths.find(function (path) { + return path.id === pair.key; + }); + if (path) { + var allowAttr = path.getAttributeNS(NAMESPACE_ORYX, 'allowDockers'); + if (allowAttr && allowAttr.toLowerCase() === "no") { + return true; + } + } + + var newDocker = (exDocker) ? exDocker : this.createDocker(this.dockers.indexOf(lastDocker) + 1, position); + newDocker.bounds.centerMoveTo(position); + if (exDocker) + this.add(newDocker, this.dockers.indexOf(lastDocker) + 1); + result = newDocker; + return true; + } else { + lastDocker = docker; + return false; + } + } + }).bind(this)); + }).bind(this)); + return result; + }, + + removeDocker: function (docker) { + if (this.dockers.length > 2 && !(this.dockers.first() === docker)) { + this._dockersByPath.any((function (pair) { + if (pair.value.member(docker)) { + if (docker === pair.value.last()) { + return true; + } else { + this.remove(docker); + this._dockersByPath[pair.key] = pair.value.without(docker); + this.isChanged = true; + this._dockerChanged(); + return true; + } + } + return false; + }).bind(this)); + } + }, + + /** + * Removes all dockers from the edge which are on + * the line between two dockers + * @return {Object} Removed dockers in an indicied array + * (key is the removed position of the docker, value is docker themselve) + */ + removeUnusedDockers: function () { + var marked = $H({}); + + this.dockers.each(function (docker, i) { + if (i == 0 || i == this.dockers.length - 1) { + return + } + var previous = this.dockers[i - 1]; + + /* Do not consider already removed dockers */ + if (marked.values().indexOf(previous) != -1 && this.dockers[i - 2]) { + previous = this.dockers[i - 2]; + } + var next = this.dockers[i + 1]; + + var cp = previous.getDockedShape() && previous.referencePoint ? previous.getAbsoluteReferencePoint() : previous.bounds.center(); + var cn = next.getDockedShape() && next.referencePoint ? next.getAbsoluteReferencePoint() : next.bounds.center(); + var cd = docker.bounds.center(); + + if (ORYX.Core.Math.isPointInLine(cd.x, cd.y, cp.x, cp.y, cn.x, cn.y, 1)) { + marked[i] = docker; + } + }.bind(this)) + + marked.each(function (docker) { + this.removeDocker(docker.value); + }.bind(this)) + + if (marked.values().length > 0) { + this._update(true); + } + + return marked; + }, + + /** + * Initializes the Edge after loading the SVG representation of the edge. + * @param {SVGDocument} svgDocument + */ + _init: function (svgDocument) { + arguments.callee.$._init.apply(this, arguments); + + var minPointX, minPointY, maxPointX, maxPointY; + + //init markers + var defs = svgDocument.getElementsByTagNameNS(NAMESPACE_SVG, "defs"); + if (defs.length > 0) { + defs = defs[0]; + var markerElements = $A(defs.getElementsByTagNameNS(NAMESPACE_SVG, "marker")); + var marker; + var me = this; + markerElements.each(function (markerElement) { + try { + marker = new ORYX.Core.SVG.SVGMarker(markerElement.cloneNode(true)); + me._markers[marker.id] = marker; + var textElements = $A(marker.element.getElementsByTagNameNS(NAMESPACE_SVG, "text")); + var label; + textElements.each(function (textElement) { + label = new ORYX.Core.SVG.Label({ + textElement: textElement, + shapeId: this.id + }); + me._labels[label.id] = label; + }); + } catch (e) { + } + }); + } + + + var gs = svgDocument.getElementsByTagNameNS(NAMESPACE_SVG, "g"); + if (gs.length <= 0) { + throw "Edge: No g element found."; + } + var g = gs[0]; + + + g.setAttributeNS(null, "id", null); + + var isFirst = true; + + $A(g.childNodes).each((function (path, index) { + if (ORYX.Editor.checkClassType(path, SVGPathElement)) { + path = path.cloneNode(false); + + var pathId = this.id + "_" + index; + path.setAttributeNS(null, "id", pathId); + this._paths.push(path); + + //check, if markers are set and update the id + var markersByThisPath = []; + var markerUrl = path.getAttributeNS(null, "marker-start"); + + if (markerUrl && markerUrl !== "") { + markerUrl = markerUrl.strip(); + markerUrl = markerUrl.replace(/^url\(#/, ''); + + var markerStartId = this.getValidMarkerId(markerUrl); + path.setAttributeNS(null, "marker-start", "url(#" + markerStartId + ")"); + + markersByThisPath.push(this._markers[markerStartId]); + } + + markerUrl = path.getAttributeNS(null, "marker-mid"); + + if (markerUrl && markerUrl !== "") { + markerUrl = markerUrl.strip(); + markerUrl = markerUrl.replace(/^url\(#/, ''); + var markerMidId = this.getValidMarkerId(markerUrl); + path.setAttributeNS(null, "marker-mid", "url(#" + markerMidId + ")"); + + markersByThisPath.push(this._markers[markerMidId]); + } + + markerUrl = path.getAttributeNS(null, "marker-end"); + + if (markerUrl && markerUrl !== "") { + markerUrl = markerUrl.strip(); + + var markerEndId = this.getValidMarkerId(markerUrl); + path.setAttributeNS(null, "marker-end", "url(#" + markerEndId + ")"); + + markersByThisPath.push(this._markers[markerEndId]); + } + + this._markersByPath[pathId] = markersByThisPath; + + //init dockers + var parser = new PathParser(); + var handler = new ORYX.Core.SVG.PointsPathHandler(); + parser.setHandler(handler); + parser.parsePath(path); + + if (handler.points.length < 4) { + throw "Edge: Path has to have two or more points specified."; + } + + this._dockersByPath[pathId] = []; + + for (var i = 0; i < handler.points.length; i += 2) { + //handler.points.each((function(point, pIndex){ + var x = handler.points[i]; + var y = handler.points[i + 1]; + if (isFirst || i > 0) { + var docker = new ORYX.Core.Controls.Docker({ + eventHandlerCallback: this.eventHandlerCallback + }); + docker.bounds.centerMoveTo(x, y); + docker.bounds.registerCallback(this._dockerChangedCallback); + this.add(docker, this.dockers.length); + + //this._dockersByPath[pathId].push(docker); + + //calculate minPoint and maxPoint + if (minPointX) { + minPointX = Math.min(x, minPointX); + minPointY = Math.min(y, minPointY); + } else { + minPointX = x; + minPointY = y; + } + + if (maxPointX) { + maxPointX = Math.max(x, maxPointX); + maxPointY = Math.max(y, maxPointY); + } else { + maxPointX = x; + maxPointY = y; + } + } + //}).bind(this)); + } + isFirst = false; + } + }).bind(this)); + + this.bounds.set(minPointX, minPointY, maxPointX, maxPointY); + + if (false && (this.bounds.width() === 0 || this.bounds.height() === 0)) { + var width = this.bounds.width(); + var height = this.bounds.height(); + + this.bounds.extend({ + x: width === 0 ? 2 : 0, + y: height === 0 ? 2 : 0 + }); + + this.bounds.moveBy({ + x: width === 0 ? -1 : 0, + y: height === 0 ? -1 : 0 + }); + + } + + this._oldBounds = this.bounds.clone(); + + //add paths to this.node + this._paths.reverse(); + var paths = []; + this._paths.each((function (path) { + paths.push(this.node.childNodes[0].childNodes[0].childNodes[0].appendChild(path)); + }).bind(this)); + + this._paths = paths; + + //init interaction path + this._paths.each((function (path) { + var iPath = path.cloneNode(false); + iPath.setAttributeNS(null, "id", undefined); + iPath.setAttributeNS(null, "stroke-width", 10); + iPath.setAttributeNS(null, "visibility", "hidden"); + iPath.setAttributeNS(null, "stroke-dasharray", null); + iPath.setAttributeNS(null, "stroke", "black"); + iPath.setAttributeNS(null, "fill", "none"); + iPath.setAttributeNS(null, "title", this.getStencil().title()); + this._interactionPaths.push(this.node.childNodes[0].childNodes[0].childNodes[0].appendChild(iPath)); + }).bind(this)); + + this._paths.reverse(); + this._interactionPaths.reverse(); + + /**initialize labels*/ + var textElems = svgDocument.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'text'); + + $A(textElems).each((function (textElem) { + var label = new ORYX.Core.SVG.Label({ + textElement: textElem, + shapeId: this.id + }); + this.node.childNodes[0].childNodes[0].appendChild(label.node); + this._labels[label.id] = label; + + label.registerOnChange(this.layout.bind(this)); + }).bind(this)); + + + this.propertiesChanged.each(function (pair) { + pair.value = true; + }); + + + //if(this.dockers.length == 2) { + + + // } + + //this._update(true); + }, + + getValidMarkerId: function (markerUrl) { + if (markerUrl.indexOf("url(\"#") >= 0) { + // Fix for IE9, additional quotes are added to the 0) { + defs = defs[0]; + this._markers.each(function (marker) { + var foundMarker = defs.ownerDocument.getElementById(marker.value.id); + if (foundMarker) { + marker.value.element = defs.removeChild(marker.value.element); + } + }); + } + } + }, + + /** + * Calls when a docker has changed + */ + _dockerChanged: function () { + + //this._update(true); + this._dockerUpdated = true; + + }, + + serialize: function () { + var result = arguments.callee.$.serialize.apply(this); + + //add dockers triple + var value = ""; + this._dockersByPath.each((function (pair) { + pair.value.each(function (docker) { + var position = docker.getDockedShape() && docker.referencePoint ? docker.referencePoint : docker.bounds.center(); + value = value.concat(position.x + " " + position.y + " "); + }); + + value += " # "; + }).bind(this)); + result.push({ + name: 'dockers', + prefix: 'oryx', + value: value, + type: 'literal' + }); + + //add parent triple dependant on the dockedShapes + //TODO change this when canvas becomes a resource + /* var source = this.dockers.first().getDockedShape(); + var target = this.dockers.last().getDockedShape(); + var sharedParent; + if (source && target) { + //get shared parent + while (source.parent) { + source = source.parent; + if (source instanceof ORYX.Core.Canvas) { + sharedParent = source; + break; + } + else { + var targetParent = target.parent; + var found; + while (targetParent) { + if (source === targetParent) { + sharedParent = source; + found = true; + break; + } + else { + targetParent = targetParent.parent; + } + } + if (found) { + break; + } + } + } + } + else + if (source) { + sharedParent = source.parent; + } + else + if (target) { + sharedParent = target.parent; + } +*/ + //if (sharedParent) { + /* result.push({ + name: 'parent', + prefix: 'raziel', + //value: '#' + ERDF.__stripHashes(sharedParent.resourceId), + value: '#' + ERDF.__stripHashes(this.getCanvas().resourceId), + type: 'resource' + });*/ + //} + + //serialize target and source + var lastDocker = this.dockers.last(); + + var target = lastDocker.getDockedShape(); + + if (target) { + result.push({ + name: 'target', + prefix: 'raziel', + value: '#' + ERDF.__stripHashes(target.resourceId), + type: 'resource' + }); + } + + try { + //result = this.getStencil().serialize(this, result); + var serializeEvent = this.getStencil().serialize(); + + /* + * call serialize callback by reference, result should be found + * in serializeEvent.result + */ + if (serializeEvent.type) { + serializeEvent.shape = this; + serializeEvent.data = result; + serializeEvent.result = undefined; + serializeEvent.forceExecution = true; + + this._delegateEvent(serializeEvent); + + if (serializeEvent.result) { + result = serializeEvent.result; + } + } + } catch (e) { + } + return result; + }, + + deserialize: function (data) { + try { + //data = this.getStencil().deserialize(this, data); + + var deserializeEvent = this.getStencil().deserialize(); + + /* + * call serialize callback by reference, result should be found + * in serializeEventInfo.result + */ + if (deserializeEvent.type) { + deserializeEvent.shape = this; + deserializeEvent.data = data; + deserializeEvent.result = undefined; + deserializeEvent.forceExecution = true; + + this._delegateEvent(deserializeEvent); + if (deserializeEvent.result) { + data = deserializeEvent.result; + } + } + } catch (e) { + } + + // Set the outgoing shapes + var target = data.find(function (ser) { + return (ser.prefix + "-" + ser.name) == 'raziel-target' + }); + var targetShape; + if (target) { + targetShape = this.getCanvas().getChildShapeByResourceId(target.value); + } + + var outgoing = data.findAll(function (ser) { + return (ser.prefix + "-" + ser.name) == 'raziel-outgoing' + }); + outgoing.each((function (obj) { + // TODO: Look at Canvas + if (!this.parent) { + return + } + ; + + // Set outgoing Shape + var next = this.getCanvas().getChildShapeByResourceId(obj.value); + + if (next) { + if (next == targetShape) { + // If this is an edge, set the last docker to the next shape + this.dockers.last().setDockedShape(next); + this.dockers.last().setReferencePoint({ + x: next.bounds.width() / 2.0, + y: next.bounds.height() / 2.0 + }); + } else if (next instanceof ORYX.Core.Edge) { + //Set the first docker of the next shape + next.dockers.first().setDockedShape(this); + //next.dockers.first().setReferencePoint({x: this.bounds.width() / 2.0, y: this.bounds.height() / 2.0}); + } /*else if(next.dockers.length > 0) { //next is a node and next has a docker + next.dockers.first().setDockedShape(this); + next.dockers.first().setReferencePoint({x: this.bounds.width() / 2.0, y: this.bounds.height() / 2.0}); + }*/ + } + + }).bind(this)); + + + var oryxDockers = data.find(function (obj) { + return (obj.prefix === "oryx" && + obj.name === "dockers"); + }); + + if (oryxDockers) { + var dataByPath = oryxDockers.value.split("#").without("").without(" "); + + dataByPath.each((function (data, index) { + var values = data.replace(/,/g, " ").split(" ").without(""); + + //for each docker two values must be defined + if (values.length % 2 === 0) { + var path = this._paths[index]; + + if (path) { + if (index === 0) { + while (this._dockersByPath[path.id].length > 2) { + this.removeDocker(this._dockersByPath[path.id][1]); + } + } else { + while (this._dockersByPath[path.id].length > 1) { + this.removeDocker(this._dockersByPath[path.id][0]); + } + } + + var dockersByPath = this._dockersByPath[path.id]; + + if (index === 0) { + //set position of first docker + var x = parseFloat(values.shift()); + var y = parseFloat(values.shift()); + + if (dockersByPath.first().getDockedShape()) { + dockersByPath.first().setReferencePoint({ + x: x, + y: y + }); + } else { + dockersByPath.first().bounds.centerMoveTo(x, y); + } + } + + //set position of last docker + y = parseFloat(values.pop()); + x = parseFloat(values.pop()); + + if (dockersByPath.last().getDockedShape()) { + dockersByPath.last().setReferencePoint({ + x: x, + y: y + }); + } else { + dockersByPath.last().bounds.centerMoveTo(x, y); + } + + //add additional dockers + for (var i = 0; i < values.length; i++) { + x = parseFloat(values[i]); + y = parseFloat(values[++i]); + + var newDocker = this.createDocker(); + newDocker.bounds.centerMoveTo(x, y); + + //this.dockers = this.dockers.without(newDocker); + //this.dockers.splice(this.dockers.indexOf(dockersByPath.last()), 0, newDocker); + //dockersByPath.splice(this.dockers.indexOf(dockersByPath.last()), 0, newDocker); + } + } + } + }).bind(this)); + } else { + this.alignDockers(); + } + + arguments.callee.$.deserialize.apply(this, arguments); + + this._changed(); + }, + + toString: function () { + return this.getStencil().title() + " " + this.id; + }, + + /** + * @return {ORYX.Core.Shape} Returns last docked shape or null. + */ + getTarget: function () { + return this.dockers.last() ? this.dockers.last().getDockedShape() : null; + }, + + /** + * @return {ORYX.Core.Shape} Returns the first docked shape or null + */ + getSource: function () { + return this.dockers.first() ? this.dockers.first().getDockedShape() : null; + }, + + /** + * Checks whether the edge is at least docked to one shape. + * + * @return {boolean} True if edge is docked + */ + isDocked: function () { + var isDocked = false; + this.dockers.each(function (docker) { + if (docker.isDocked()) { + isDocked = true; + throw $break; + } + }); + return isDocked; + }, + + /** + * Calls {@link ORYX.Core.AbstractShape#toJSON} and add a some stencil set information. + */ + toJSON: function () { + var json = arguments.callee.$.toJSON.apply(this, arguments); + + if (this.getTarget()) { + json.target = { + resourceId: this.getTarget().resourceId + }; + } + + return json; + } +}; +ORYX.Core.Edge = ORYX.Core.Shape.extend(ORYX.Core.Edge); +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +if (!ORYX) { + var ORYX = {} +} +if (!ORYX.Plugins) { + ORYX.Plugins = {} +} + +/** + This abstract plugin class can be used to build plugins on. + It provides some more basic functionality like registering events (on*-handlers)... + @example + ORYX.Plugins.MyPlugin = ORYX.Plugins.AbstractPlugin.extend({ + construct: function() { + // Call super class constructor + arguments.callee.$.construct.apply(this, arguments); + + [...] + }, + [...] + }); + + @class ORYX.Plugins.AbstractPlugin + @constructor Creates a new instance + @author Willi Tscheschner + */ +ORYX.Plugins.AbstractPlugin = Clazz.extend({ + /** + * The facade which offer editor-specific functionality + * @type Facade + * @memberOf ORYX.Plugins.AbstractPlugin.prototype + */ + facade: null, + + construct: function (facade) { + this.facade = facade; + + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADED, this.onLoaded.bind(this)); + }, + + /** + Overwrite to handle load event. TODO: Document params!!! + @methodOf ORYX.Plugins.AbstractPlugin.prototype + */ + onLoaded: function () { + }, + + /** + Overwrite to handle selection changed event. TODO: Document params!!! + @methodOf ORYX.Plugins.AbstractPlugin.prototype + */ + onSelectionChanged: function () { + }, + + /** + Show overlay on given shape. + @methodOf ORYX.Plugins.AbstractPlugin.prototype + @example + showOverlay( + myShape, + { stroke: "green" }, + ORYX.Editor.graft("http://www.w3.org/2000/svg", null, ['path', { + "title": "Click the element to execute it!", + "stroke-width": 2.0, + "stroke": "black", + "d": "M0,-5 L5,0 L0,5 Z", + "line-captions": "round" + }]) + ) + @param {Oryx.XXX.Shape[]} shapes One shape or array of shapes the overlay should be put on + @param {Oryx.XXX.Attributes} attributes some attributes... + @param {Oryx.svg.node} svgNode The svg node which should be used as overlay + @param {String} [svgNode="NW"] The svg node position where the overlay should be placed + */ + showOverlay: function (shapes, attributes, svgNode, svgNodePosition) { + + if (!(shapes instanceof Array)) { + shapes = [shapes] + } + + // Define Shapes + shapes = shapes.map(function (shape) { + var el = shape; + if (typeof shape == "string") { + el = this.facade.getCanvas().getChildShapeByResourceId(shape); + el = el || this.facade.getCanvas().getChildById(shape, true); + } + return el; + }.bind(this)).compact(); + + // Define unified id + if (!this.overlayID) { + this.overlayID = this.type + ORYX.Editor.provideId(); + } + + this.facade.raiseEvent({ + type: ORYX.CONFIG.EVENT_OVERLAY_SHOW, + id: this.overlayID, + shapes: shapes, + attributes: attributes, + node: svgNode, + nodePosition: svgNodePosition || "NW" + }); + + }, + + /** + Hide current overlay. + @methodOf ORYX.Plugins.AbstractPlugin.prototype + */ + hideOverlay: function () { + this.facade.raiseEvent({ + type: ORYX.CONFIG.EVENT_OVERLAY_HIDE, + id: this.overlayID + }); + }, + + /** + Does a transformation with the given xslt stylesheet. + @methodOf ORYX.Plugins.AbstractPlugin.prototype + @param {String} data The data (e.g. eRDF) which should be transformed + @param {String} stylesheet URL of a stylesheet which should be used for transforming data. + */ + doTransform: function (data, stylesheet) { + + if (!stylesheet || !data) { + return "" + } + + var parser = new DOMParser(); + var parsedData = parser.parseFromString(data, "text/xml"); + source = stylesheet; + new Ajax.Request(source, { + asynchronous: false, + method: 'get', + onSuccess: function (transport) { + xsl = transport.responseText + }.bind(this), + onFailure: (function (transport) { + ORYX.Log.error("XSL load failed" + transport); + }).bind(this) + }); + var xsltProcessor = new XSLTProcessor(); + var domParser = new DOMParser(); + var xslObject = domParser.parseFromString(xsl, "text/xml"); + xsltProcessor.importStylesheet(xslObject); + + try { + + var newData = xsltProcessor.transformToFragment(parsedData, document); + var serializedData = (new XMLSerializer()).serializeToString(newData); + + /* Firefox 2 to 3 problem?! */ + serializedData = !serializedData.startsWith("" + serializedData : serializedData; + + return serializedData; + + } catch (error) { + return -1; + } + + }, + + /** + * Opens a new window that shows the given XML content. + * @methodOf ORYX.Plugins.AbstractPlugin.prototype + * @param {Object} content The XML content to be shown. + * @example + * openDownloadWindow( "my.xml", "" ); + */ + openXMLWindow: function (content) { + var win = window.open( + 'data:application/xml,' + encodeURIComponent( + content + ), + '_blank', "resizable=yes,width=600,height=600,toolbar=0,scrollbars=yes" + ); + }, + + /** + * Opens a download window for downloading the given content. + * @methodOf ORYX.Plugins.AbstractPlugin.prototype + * @param {String} filename The content's file name + * @param {String} content The content to download + */ + openDownloadWindow: function (filename, content) { + var win = window.open(""); + if (win != null) { + win.document.open(); + win.document.write(""); + var submitForm = win.document.createElement("form"); + win.document.body.appendChild(submitForm); + + var createHiddenElement = function (name, value) { + var newElement = document.createElement("input"); + newElement.name = name; + newElement.type = "hidden"; + newElement.value = value; + return newElement + } + + submitForm.appendChild(createHiddenElement("download", content)); + submitForm.appendChild(createHiddenElement("file", filename)); + + + submitForm.method = "POST"; + win.document.write(""); + win.document.close(); + submitForm.action = ORYX.PATH + "/download"; + submitForm.submit(); + } + }, + + /** + * Serializes DOM. + * @methodOf ORYX.Plugins.AbstractPlugin.prototype + * @type {String} Serialized DOM + */ + getSerializedDOM: function () { + // Force to set all resource IDs + var serializedDOM = DataManager.serializeDOM(this.facade); + + //add namespaces + serializedDOM = '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + serializedDOM + + ''; + + return serializedDOM; + }, + + /** + * Sets the editor in read only mode: Edges/ dockers cannot be moved anymore, + * shapes cannot be selected anymore. + * @methodOf ORYX.Plugins.AbstractPlugin.prototype + */ + enableReadOnlyMode: function () { + //Edges cannot be moved anymore + this.facade.disableEvent(ORYX.CONFIG.EVENT_MOUSEDOWN); + + // Stop the user from editing the diagram while the plugin is active + this._stopSelectionChange = function () { + if (this.facade.getSelection().length > 0) { + this.facade.setSelection([]); + } + }; + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, this._stopSelectionChange.bind(this)); + }, + /** + * Disables read only mode, see @see + * @methodOf ORYX.Plugins.AbstractPlugin.prototype + * @see ORYX.Plugins.AbstractPlugin.prototype.enableReadOnlyMode + */ + disableReadOnlyMode: function () { + // Edges can be moved now again + this.facade.enableEvent(ORYX.CONFIG.EVENT_MOUSEDOWN); + + if (this._stopSelectionChange) { + this.facade.unregisterOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, this._stopSelectionChange.bind(this)); + this._stopSelectionChange = undefined; + } + }, + + /** + * Extracts RDF from DOM. + * @methodOf ORYX.Plugins.AbstractPlugin.prototype + * @type {String} Extracted RFD. Null if there are transformation errors. + */ + getRDFFromDOM: function () { + //convert to RDF + try { + var xsl = ""; + source = ORYX.PATH + "lib/extract-rdf.xsl"; + new Ajax.Request(source, { + asynchronous: false, + method: 'get', + onSuccess: function (transport) { + xsl = transport.responseText + }.bind(this), + onFailure: (function (transport) { + ORYX.Log.error("XSL load failed" + transport); + }).bind(this) + }); + + var domParser = new DOMParser(); + var xmlObject = domParser.parseFromString(this.getSerializedDOM(), "text/xml"); + var xslObject = domParser.parseFromString(xsl, "text/xml"); + var xsltProcessor = new XSLTProcessor(); + xsltProcessor.importStylesheet(xslObject); + var result = xsltProcessor.transformToFragment(xmlObject, document); + + var serializer = new XMLSerializer(); + + return serializer.serializeToString(result); + } catch (e) { + return ""; + } + + + }, + + /** + * Checks if a certain stencil set is loaded right now. + * + */ + isStencilSetExtensionLoaded: function (stencilSetExtensionNamespace) { + return this.facade.getStencilSets().values().any( + function (ss) { + return ss.extensions().keys().any( + function (extensionKey) { + return extensionKey == stencilSetExtensionNamespace; + }.bind(this) + ); + }.bind(this) + ); + }, + + /** + * Raises an event so that registered layouters does + * have the posiblility to layout the given shapes + * For further reading, have a look into the AbstractLayouter + * class + * @param {Object} shapes + */ + doLayout: function (shapes) { + // Raises a do layout event + if (this.facade.raiseEvent) { + this.facade.raiseEvent({ + type: ORYX.CONFIG.EVENT_LAYOUT, + shapes: shapes + }); + } else { + this.facade.handleEvents({ + type: ORYX.CONFIG.EVENT_LAYOUT, + shapes: shapes + }); + } + }, + + + /** + * Does a primitive layouting with the incoming/outgoing + * edges (set the dockers to the right position) and if + * necessary, it will be called the real layouting + * @param {ORYX.Core.Node} node + * @param {Array} edges + */ + layoutEdges: function (node, allEdges, offset) { + + if (!this.facade.isExecutingCommands()) { + return + } + + var Command = ORYX.Core.Command.extend({ + construct: function (edges, node, offset, plugin) { + this.edges = edges; + this.node = node; + this.plugin = plugin; + this.offset = offset; + + // Get the new absolute center + var center = node.absoluteXY(); + this.ulo = {x: center.x - offset.x, y: center.y - offset.y}; + + + }, + execute: function () { + + if (this.changes) { + this.executeAgain(); + return; + } else { + this.changes = []; + this.edges.each(function (edge) { + this.changes.push({ + edge: edge, + oldDockerPositions: edge.dockers.map(function (r) { + return r.bounds.center() + }) + }) + }.bind(this)); + } + + // Find all edges, which are related to the node and + // have more than two dockers + this.edges + // Find all edges with more than two dockers + .findAll(function (r) { + return r.dockers.length > 2 + }.bind(this)) + // For every edge, check second and one before last docker + // if there are horizontal/vertical on the same level + // and if so, align the the bounds + .each(function (edge) { + if (edge.dockers.first().getDockedShape() === this.node) { + var second = edge.dockers[1]; + if (this.align(second.bounds, edge.dockers.first())) { + second.update(); + } + } else if (edge.dockers.last().getDockedShape() === this.node) { + var beforeLast = edge.dockers[edge.dockers.length - 2]; + if (this.align(beforeLast.bounds, edge.dockers.last())) { + beforeLast.update(); + } + } + edge._update(true); + edge.removeUnusedDockers(); + if (this.isBendPointIncluded(edge)) { + this.plugin.doLayout(edge); + return; + } + }.bind(this)); + + + // Find all edges, which have only to dockers + // and is located horizontal/vertical. + // Do layout with those edges + this.edges + // Find all edges with exactly two dockers + .each(function (edge) { + if (edge.dockers.length == 2) { + var p1 = edge.dockers.first().getAbsoluteReferencePoint() || edge.dockers.first().bounds.center(); + var p2 = edge.dockers.last().getAbsoluteReferencePoint() || edge.dockers.first().bounds.center(); + // Find all horizontal/vertical edges + if (Math.abs(-Math.abs(p1.x - p2.x) + Math.abs(this.offset.x)) < 2 || Math.abs(-Math.abs(p1.y - p2.y) + Math.abs(this.offset.y)) < 2) { + this.plugin.doLayout(edge); + } + } + }.bind(this)); + + this.edges.each(function (edge, i) { + this.changes[i].dockerPositions = edge.dockers.map(function (r) { + return r.bounds.center() + }); + }.bind(this)); + + }, + /** + * Align the bounds if the center is + * the same than the old center + * @params {Object} bounds + * @params {Object} bounds2 + */ + align: function (bounds, refDocker) { + + var abRef = refDocker.getAbsoluteReferencePoint() || refDocker.bounds.center(); + + var xdif = bounds.center().x - abRef.x; + var ydif = bounds.center().y - abRef.y; + if (Math.abs(-Math.abs(xdif) + Math.abs(this.offset.x)) < 3 && this.offset.xs === undefined) { + bounds.moveBy({x: -xdif, y: 0}) + } + if (Math.abs(-Math.abs(ydif) + Math.abs(this.offset.y)) < 3 && this.offset.ys === undefined) { + bounds.moveBy({y: -ydif, x: 0}) + } + + if (this.offset.xs !== undefined || this.offset.ys !== undefined) { + var absPXY = refDocker.getDockedShape().absoluteXY(); + xdif = bounds.center().x - (absPXY.x + ((abRef.x - absPXY.x) / this.offset.xs)); + ydif = bounds.center().y - (absPXY.y + ((abRef.y - absPXY.y) / this.offset.ys)); + + if (Math.abs(-Math.abs(xdif) + Math.abs(this.offset.x)) < 3) { + bounds.moveBy({x: -(bounds.center().x - abRef.x), y: 0}) + } + + if (Math.abs(-Math.abs(ydif) + Math.abs(this.offset.y)) < 3) { + bounds.moveBy({y: -(bounds.center().y - abRef.y), x: 0}) + } + } + }, + + /** + * Returns a TRUE if there are bend point which overlay the shape + */ + isBendPointIncluded: function (edge) { + // Get absolute bounds + var ab = edge.dockers.first().getDockedShape(); + var bb = edge.dockers.last().getDockedShape(); + + if (ab) { + ab = ab.absoluteBounds(); + ab.widen(5); + } + + if (bb) { + bb = bb.absoluteBounds(); + bb.widen(20); // Wide with 20 because of the arrow from the edge + } + + return edge.dockers + .any(function (docker, i) { + var c = docker.bounds.center(); + // Dont count first and last + return i != 0 && i != edge.dockers.length - 1 && + // Check if the point is included to the absolute bounds + ((ab && ab.isIncluded(c)) || (bb && bb.isIncluded(c))) + }) + }, + + removeAllDocker: function (edge) { + edge.dockers.slice(1, edge.dockers.length - 1).each(function (docker) { + edge.removeDocker(docker); + }) + }, + executeAgain: function () { + this.changes.each(function (change) { + // Reset the dockers + this.removeAllDocker(change.edge); + change.dockerPositions.each(function (pos, i) { + if (i == 0 || i == change.dockerPositions.length - 1) { + return + } + var docker = change.edge.createDocker(undefined, pos); + docker.bounds.centerMoveTo(pos); + docker.update(); + }.bind(this)); + change.edge._update(true); + }.bind(this)); + }, + rollback: function () { + this.changes.each(function (change) { + // Reset the dockers + this.removeAllDocker(change.edge); + change.oldDockerPositions.each(function (pos, i) { + if (i == 0 || i == change.oldDockerPositions.length - 1) { + return + } + var docker = change.edge.createDocker(undefined, pos); + docker.bounds.centerMoveTo(pos); + docker.update(); + }.bind(this)); + change.edge._update(true); + }.bind(this)); + } + }); + + this.facade.executeCommands([new Command(allEdges, node, offset, this)]); + + } +});/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +if (!ORYX) { + var ORYX = {} +} +if (!ORYX.Plugins) { + ORYX.Plugins = {} +} + +/** + This abstract plugin implements the core behaviour of layout + + @class ORYX.Plugins.AbstractLayouter + @constructor Creates a new instance + @author Willi Tscheschner + */ +ORYX.Plugins.AbstractLayouter = ORYX.Plugins.AbstractPlugin.extend({ + + /** + * 'layouted' defined all types of shapes which will be layouted. + * It can be one value or an array of values. The value + * can be a Stencil ID (as String) or an class type of either + * a ORYX.Core.Node or ORYX.Core.Edge + * @type Array|String|Object + * @memberOf ORYX.Plugins.AbstractLayouter.prototype + */ + layouted: [], + + /** + * Constructor + * @param {Object} facade + * @memberOf ORYX.Plugins.AbstractLayouter.prototype + */ + construct: function (facade) { + arguments.callee.$.construct.apply(this, arguments); + + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LAYOUT, this._initLayout.bind(this)); + }, + + /** + * Proofs if this shape should be layouted or not + * @param {Object} shape + * @memberOf ORYX.Plugins.AbstractLayouter.prototype + */ + isIncludedInLayout: function (shape) { + if (!(this.layouted instanceof Array)) { + this.layouted = [this.layouted].compact(); + } + + // If there are no elements + if (this.layouted.length <= 0) { + // Return TRUE + return true; + } + + // Return TRUE if there is any correlation between + // the 'layouted' attribute and the shape themselve. + return this.layouted.any(function (s) { + if (typeof s == "string") { + return shape.getStencil().id().include(s); + } else { + return shape instanceof s; + } + }) + }, + + /** + * Callback to start the layouting + * @param {Object} event Layout event + * @param {Object} shapes Given shapes + * @memberOf ORYX.Plugins.AbstractLayouter.prototype + */ + _initLayout: function (event) { + + // Get the shapes + var shapes = [event.shapes].flatten().compact(); + + // Find all shapes which should be layouted + var toLayout = shapes.findAll(function (shape) { + return this.isIncludedInLayout(shape) + }.bind(this)) + + // If there are shapes left + if (toLayout.length > 0) { + // Do layout + this.layout(toLayout); + } + }, + + /** + * Implementation of layouting a set on shapes + * @param {Object} shapes Given shapes + * @memberOf ORYX.Plugins.AbstractLayouter.prototype + */ + layout: function (shapes) { + throw new Error("Layouter has to implement the layout function.") + } +});/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +if (!ORYX.Plugins) + ORYX.Plugins = new Object(); + +ORYX.Plugins.Edit = Clazz.extend({ + + construct: function (facade) { + + this.facade = facade; + this.clipboard = new ORYX.Plugins.Edit.ClipBoard(); + + //this.facade.registerOnEvent(ORYX.CONFIG.EVENT_KEYDOWN, this.keyHandler.bind(this)); + + this.facade.offer({ + name: ORYX.I18N.Edit.cut, + description: ORYX.I18N.Edit.cutDesc, + icon: ORYX.PATH + "images/cut.png", + keyCodes: [{ + metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL], + keyCode: 88, + keyAction: ORYX.CONFIG.KEY_ACTION_DOWN + } + ], + functionality: this.callEdit.bind(this, this.editCut), + group: ORYX.I18N.Edit.group, + index: 1, + minShape: 1 + }); + + this.facade.offer({ + name: ORYX.I18N.Edit.copy, + description: ORYX.I18N.Edit.copyDesc, + icon: ORYX.PATH + "images/page_copy.png", + keyCodes: [{ + metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL], + keyCode: 67, + keyAction: ORYX.CONFIG.KEY_ACTION_DOWN + } + ], + functionality: this.callEdit.bind(this, this.editCopy, [true, false]), + group: ORYX.I18N.Edit.group, + index: 2, + minShape: 1 + }); + + this.facade.offer({ + name: ORYX.I18N.Edit.paste, + description: ORYX.I18N.Edit.pasteDesc, + icon: ORYX.PATH + "images/page_paste.png", + keyCodes: [{ + metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL], + keyCode: 86, + keyAction: ORYX.CONFIG.KEY_ACTION_DOWN + } + ], + functionality: this.callEdit.bind(this, this.editPaste), + isEnabled: this.clipboard.isOccupied.bind(this.clipboard), + group: ORYX.I18N.Edit.group, + index: 3, + minShape: 0, + maxShape: 0 + }); + + this.facade.offer({ + name: ORYX.I18N.Edit.del, + description: ORYX.I18N.Edit.delDesc, + icon: ORYX.PATH + "images/cross.png", + keyCodes: [{ + metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL], + keyCode: 8, + keyAction: ORYX.CONFIG.KEY_ACTION_DOWN + }, + { + keyCode: 46, + keyAction: ORYX.CONFIG.KEY_ACTION_DOWN + } + ], + functionality: this.callEdit.bind(this, this.editDelete), + group: ORYX.I18N.Edit.group, + index: 4, + minShape: 1 + }); + }, + + callEdit: function (fn, args) { + window.setTimeout(function () { + fn.apply(this, (args instanceof Array ? args : [])); + }.bind(this), 1); + }, + + /** + * Handles the mouse down event and starts the copy-move-paste action, if + * control or meta key is pressed. + */ + handleMouseDown: function (event) { + if (this._controlPressed) { + this._controlPressed = false; + this.editCopy(); +// console.log("copiedEle: %0",this.clipboard.shapesAsJson) +// console.log("mousevent: %o",event) + this.editPaste(); + event.forceExecution = true; + this.facade.raiseEvent(event, this.clipboard.shapesAsJson); + + } + }, + + /** + * The key handler for this plugin. Every action from the set of cut, copy, + * paste and delete should be accessible trough simple keyboard shortcuts. + * This method checks whether any event triggers one of those actions. + * + * @param {Object} event The keyboard event that should be analysed for + * triggering of this plugin. + */ +// keyHandler: function(event){ +// //TODO document what event.which is. +// +// ORYX.Log.debug("edit.js handles a keyEvent."); +// +// // assure we have the current event. +// if (!event) +// event = window.event; +// +// +// // get the currently pressed key and state of control key. +// var pressedKey = event.which || event.keyCode; +// var ctrlPressed = event.ctrlKey; +// +// // if the object is to be deleted, do so, and return immediately. +// if ((pressedKey == ORYX.CONFIG.KEY_CODE_DELETE) || +// ((pressedKey == ORYX.CONFIG.KEY_CODE_BACKSPACE) && +// (event.metaKey || event.appleMetaKey))) { +// +// ORYX.Log.debug("edit.js deletes the shape."); +// this.editDelete(); +// return; +// } +// +// // if control key is not pressed, we're not interested anymore. +// if (!ctrlPressed) +// return; +// +// // when ctrl is pressed, switch trough the possibilities. +// switch (pressedKey) { +// +// // cut. +// case ORYX.CONFIG.KEY_CODE_X: +// this.editCut(); +// break; +// +// // copy. +// case ORYX.CONFIG.KEY_CODE_C: +// this.editCopy(); +// break; +// +// // paste. +// case ORYX.CONFIG.KEY_CODE_V: +// this.editPaste(); +// break; +// } +// }, + + /** + * Returns a list of shapes which should be considered while copying. + * Besides the shapes of given ones, edges and attached nodes are added to the result set. + * If one of the given shape is a child of another given shape, it is not put into the result. + */ + getAllShapesToConsider: function (shapes) { + var shapesToConsider = []; // only top-level shapes + var childShapesToConsider = []; // all child shapes of top-level shapes + + shapes.each(function (shape) { + //Throw away these shapes which have a parent in given shapes + isChildShapeOfAnother = shapes.any(function (s2) { + return s2.hasChildShape(shape); + }); + if (isChildShapeOfAnother) return; + + // This shape should be considered + shapesToConsider.push(shape); + // Consider attached nodes (e.g. intermediate events) + if (shape instanceof ORYX.Core.Node) { + var attached = shape.getOutgoingNodes(); + attached = attached.findAll(function (a) { + return !shapes.include(a) + }); + shapesToConsider = shapesToConsider.concat(attached); + } + + childShapesToConsider = childShapesToConsider.concat(shape.getChildShapes(true)); + }.bind(this)); + + // All edges between considered child shapes should be considered + // Look for these edges having incoming and outgoing in childShapesToConsider + var edgesToConsider = this.facade.getCanvas().getChildEdges().select(function (edge) { + // Ignore if already added + if (shapesToConsider.include(edge)) return false; + // Ignore if there are no docked shapes + if (edge.getAllDockedShapes().size() === 0) return false; + // True if all docked shapes are in considered child shapes + return edge.getAllDockedShapes().all(function (shape) { + // Remember: Edges can have other edges on outgoing, that is why edges must not be included in childShapesToConsider + return shape instanceof ORYX.Core.Edge || childShapesToConsider.include(shape); + }); + }); + shapesToConsider = shapesToConsider.concat(edgesToConsider); + + return shapesToConsider; + }, + + /** + * Performs the cut operation by first copy-ing and then deleting the + * current selection. + */ + editCut: function () { + //TODO document why this returns false. + //TODO document what the magic boolean parameters are supposed to do. + + this.editCopy(false, true); + this.editDelete(true); + return false; + }, + + /** + * Performs the copy operation. + * @param {Object} will_not_update ?? + */ + editCopy: function (will_update, useNoOffset) { + var selection = this.facade.getSelection(); + + //if the selection is empty, do not remove the previously copied elements + if (selection.length == 0) return; + + this.clipboard.refresh(selection, this.getAllShapesToConsider(selection), this.facade.getCanvas().getStencil().stencilSet().namespace(), useNoOffset); + + if (will_update) this.facade.updateSelection(); + }, + + /** + * Performs the paste operation. + */ + editPaste: function () { + // Create a new canvas with childShapes + //and stencilset namespace to be JSON Import conform + var canvas = { + childShapes: this.clipboard.shapesAsJson, + stencilset: { + namespace: this.clipboard.SSnamespace + } + }; + // Apply json helper to iterate over json object + jQuery.extend(canvas, ORYX.Core.AbstractShape.JSONHelper); + + var childShapeResourceIds = canvas.getChildShapes(true).pluck("resourceId"); + var outgoings = {}; + // Iterate over all shapes + canvas.eachChild(function (shape, parent) { + // Throw away these references where referenced shape isn't copied + shape.outgoing = shape.outgoing.select(function (out) { + return childShapeResourceIds.include(out.resourceId); + }); + shape.outgoing.each(function (out) { + if (!outgoings[out.resourceId]) { + outgoings[out.resourceId] = []; + } + outgoings[out.resourceId].push(shape); + }); + + return shape; + }.bind(this), true, true); + + + // Iterate over all shapes + canvas.eachChild(function (shape, parent) { + + // Check if there has a valid target + if (shape.target && !(childShapeResourceIds.include(shape.target.resourceId))) { + shape.target = undefined; + shape.targetRemoved = true; + } + + // Check if the first docker is removed + if (shape.dockers && + shape.dockers.length >= 1 && + shape.dockers[0].getDocker && + ((shape.dockers[0].getDocker().getDockedShape() && + !childShapeResourceIds.include(shape.dockers[0].getDocker().getDockedShape().resourceId)) || + !shape.getShape().dockers[0].getDockedShape() && !outgoings[shape.resourceId])) { + + shape.sourceRemoved = true; + } + + return shape; + }.bind(this), true, true); + + + // Iterate over top-level shapes + canvas.eachChild(function (shape, parent) { + // All top-level shapes should get an offset in their bounds + // Move the shape occording to COPY_MOVE_OFFSET + if (this.clipboard.useOffset) { + shape.bounds = { + lowerRight: { + x: shape.bounds.lowerRight.x + ORYX.CONFIG.COPY_MOVE_OFFSET, + y: shape.bounds.lowerRight.y + ORYX.CONFIG.COPY_MOVE_OFFSET + }, + upperLeft: { + x: shape.bounds.upperLeft.x + ORYX.CONFIG.COPY_MOVE_OFFSET, + y: shape.bounds.upperLeft.y + ORYX.CONFIG.COPY_MOVE_OFFSET + } + }; + } + // Only apply offset to shapes with a target + if (shape.dockers) { + shape.dockers = shape.dockers.map(function (docker, i) { + // If shape had a target but the copied does not have anyone anymore, + // migrate the relative dockers to absolute ones. + if ((shape.targetRemoved === true && i == shape.dockers.length - 1 && docker.getDocker) || + (shape.sourceRemoved === true && i == 0 && docker.getDocker)) { + + docker = docker.getDocker().bounds.center(); + } + + // If it is the first docker and it has a docked shape, + // just return the coordinates + if ((i == 0 && docker.getDocker instanceof Function && + shape.sourceRemoved !== true && (docker.getDocker().getDockedShape() || ((outgoings[shape.resourceId] || []).length > 0 && (!(shape.getShape() instanceof ORYX.Core.Node) || outgoings[shape.resourceId][0].getShape() instanceof ORYX.Core.Node)))) || + (i == shape.dockers.length - 1 && docker.getDocker instanceof Function && + shape.targetRemoved !== true && (docker.getDocker().getDockedShape() || shape.target))) { + + return { + x: docker.x, + y: docker.y, + getDocker: docker.getDocker + } + } else if (this.clipboard.useOffset) { + return { + x: docker.x + ORYX.CONFIG.COPY_MOVE_OFFSET, + y: docker.y + ORYX.CONFIG.COPY_MOVE_OFFSET, + getDocker: docker.getDocker + }; + } else { + return { + x: docker.x, + y: docker.y, + getDocker: docker.getDocker + }; + } + }.bind(this)); + + } else if (shape.getShape() instanceof ORYX.Core.Node && shape.dockers && shape.dockers.length > 0 && (!shape.dockers.first().getDocker || shape.sourceRemoved === true || !(shape.dockers.first().getDocker().getDockedShape() || outgoings[shape.resourceId]))) { + + shape.dockers = shape.dockers.map(function (docker, i) { + + if ((shape.sourceRemoved === true && i == 0 && docker.getDocker)) { + docker = docker.getDocker().bounds.center(); + } + + if (this.clipboard.useOffset) { + return { + x: docker.x + ORYX.CONFIG.COPY_MOVE_OFFSET, + y: docker.y + ORYX.CONFIG.COPY_MOVE_OFFSET, + getDocker: docker.getDocker + }; + } else { + return { + x: docker.x, + y: docker.y, + getDocker: docker.getDocker + }; + } + }.bind(this)); + } + + return shape; + }.bind(this), false, true); + + this.clipboard.useOffset = true; + this.facade.importJSON(canvas); + }, + + /** + * Performs the delete operation. No more asking. + */ + editDelete: function () { + var selection = this.facade.getSelection(); + + var clipboard = new ORYX.Plugins.Edit.ClipBoard(); + clipboard.refresh(selection, this.getAllShapesToConsider(selection)); + + var command = new ORYX.Plugins.Edit.DeleteCommand(clipboard, this.facade); + + this.facade.executeCommands([command]); + } +}); + +ORYX.Plugins.Edit.ClipBoard = Clazz.extend({ + construct: function () { + this.shapesAsJson = []; + this.selection = []; + this.SSnamespace = ""; + this.useOffset = true; + }, + isOccupied: function () { + return this.shapesAsJson.length > 0; + }, + refresh: function (selection, shapes, namespace, useNoOffset) { + this.selection = selection; + this.SSnamespace = namespace; + // Store outgoings, targets and parents to restore them later on + this.outgoings = {}; + this.parents = {}; + this.targets = {}; + this.useOffset = useNoOffset !== true; + + this.shapesAsJson = shapes.map(function (shape) { + var s = shape.toJSON(); + s.parent = {resourceId: shape.getParentShape().resourceId}; + s.parentIndex = shape.getParentShape().getChildShapes().indexOf(shape) + return s; + }); + } +}); + +ORYX.Plugins.Edit.DeleteCommand = ORYX.Core.Command.extend({ + construct: function (clipboard, facade) { + this.clipboard = clipboard; + this.shapesAsJson = clipboard.shapesAsJson; + this.facade = facade; + + // Store dockers of deleted shapes to restore connections + this.dockers = this.shapesAsJson.map(function (shapeAsJson) { + var shape = shapeAsJson.getShape(); + var incomingDockers = shape.getIncomingShapes().map(function (s) { + return s.getDockers().last(); + }); + var outgoingDockers = shape.getOutgoingShapes().map(function (s) { + return s.getDockers().first(); + }); + var dockers = shape.getDockers().concat(incomingDockers, outgoingDockers).compact().map(function (docker) { + return { + object: docker, + referencePoint: docker.referencePoint, + dockedShape: docker.getDockedShape() + }; + }); + return dockers; + }).flatten(); + }, + execute: function () { + this.shapesAsJson.each(function (shapeAsJson) { + // Delete shape + this.facade.deleteShape(shapeAsJson.getShape()); + }.bind(this)); + + this.facade.setSelection([]); + this.facade.getCanvas().update(); + this.facade.updateSelection(); + + }, + rollback: function () { + this.shapesAsJson.each(function (shapeAsJson) { + var shape = shapeAsJson.getShape(); + var parent = this.facade.getCanvas().getChildShapeByResourceId(shapeAsJson.parent.resourceId) || this.facade.getCanvas(); + parent.add(shape, shape.parentIndex); + }.bind(this)); + + //reconnect shapes + this.dockers.each(function (d) { + d.object.setDockedShape(d.dockedShape); + d.object.setReferencePoint(d.referencePoint); + }.bind(this)); + + this.facade.setSelection(this.selectedShapes); + this.facade.getCanvas().update(); + this.facade.updateSelection(); + + } +});/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * @namespace Oryx name space for plugins + * @name ORYX.Plugins + */ +if (!ORYX.Plugins) + ORYX.Plugins = new Object(); + +/** + * The view plugin offers all of zooming functionality accessible over the + * tool bar. This are zoom in, zoom out, zoom to standard, zoom fit to model. + * + * @class ORYX.Plugins.View + * @extends Clazz + * @param {Object} facade The editor facade for plugins. + */ +ORYX.Plugins.View = { + /** @lends ORYX.Plugins.View.prototype */ + facade: undefined, + + construct: function (facade, ownPluginData) { + this.facade = facade; + //Standard Values + this.zoomLevel = 1.0; + this.maxFitToScreenLevel = 1.5; + this.minZoomLevel = 0.1; + this.maxZoomLevel = 2.5; + this.diff = 5; //difference between canvas and view port, s.th. like toolbar?? + + //Read properties + if (ownPluginData !== undefined && ownPluginData !== null) { + ownPluginData.properties.each(function (property) { + if (property.zoomLevel) { + this.zoomLevel = Number(1.0); + } + if (property.maxFitToScreenLevel) { + this.maxFitToScreenLevel = Number(property.maxFitToScreenLevel); + } + if (property.minZoomLevel) { + this.minZoomLevel = Number(property.minZoomLevel); + } + if (property.maxZoomLevel) { + this.maxZoomLevel = Number(property.maxZoomLevel); + } + }.bind(this)); + } + + + /* Register zoom in */ + this.facade.offer({ + 'name': ORYX.I18N.View.zoomIn, + 'functionality': this.zoom.bind(this, [1.0 + ORYX.CONFIG.ZOOM_OFFSET]), + 'group': ORYX.I18N.View.group, + 'icon': ORYX.PATH + "images/magnifier_zoom_in.png", + 'description': ORYX.I18N.View.zoomInDesc, + 'index': 1, + 'minShape': 0, + 'maxShape': 0, + 'isEnabled': function () { + return this.zoomLevel < this.maxZoomLevel + }.bind(this) + }); + + /* Register zoom out */ + this.facade.offer({ + 'name': ORYX.I18N.View.zoomOut, + 'functionality': this.zoom.bind(this, [1.0 - ORYX.CONFIG.ZOOM_OFFSET]), + 'group': ORYX.I18N.View.group, + 'icon': ORYX.PATH + "images/magnifier_zoom_out.png", + 'description': ORYX.I18N.View.zoomOutDesc, + 'index': 2, + 'minShape': 0, + 'maxShape': 0, + 'isEnabled': function () { + return this._checkSize() + }.bind(this) + }); + + /* Register zoom standard */ + this.facade.offer({ + 'name': ORYX.I18N.View.zoomStandard, + 'functionality': this.setAFixZoomLevel.bind(this, 1), + 'group': ORYX.I18N.View.group, + 'icon': ORYX.PATH + "images/zoom_standard.png", + 'cls': 'icon-large', + 'description': ORYX.I18N.View.zoomStandardDesc, + 'index': 3, + 'minShape': 0, + 'maxShape': 0, + 'isEnabled': function () { + return this.zoomLevel != 1 + }.bind(this) + }); + + /* Register zoom fit to model */ + this.facade.offer({ + 'name': ORYX.I18N.View.zoomFitToModel, + 'functionality': this.zoomFitToModel.bind(this), + 'group': ORYX.I18N.View.group, + 'icon': ORYX.PATH + "images/image.png", + 'description': ORYX.I18N.View.zoomFitToModelDesc, + 'index': 4, + 'minShape': 0, + 'maxShape': 0 + }); + }, + + /** + * It sets the zoom level to a fix value and call the zooming function. + * + * @param {Number} zoomLevel + * the zoom level + */ + setAFixZoomLevel: function (zoomLevel) { + this.zoomLevel = zoomLevel; + this._checkZoomLevelRange(); + this.zoom(1); + }, + + /** + * It does the actual zooming. It changes the viewable size of the canvas + * and all to its child elements. + * + * @param {Number} factor + * the factor to adjust the zoom level + */ + zoom: function (factor) { + // TODO: Zoomen auf allen Objekten im SVG-DOM + + this.zoomLevel *= factor; + var scrollNode = this.facade.getCanvas().getHTMLContainer().parentNode.parentNode; + var canvas = this.facade.getCanvas(); + var newWidth = canvas.bounds.width() * this.zoomLevel; + var newHeight = canvas.bounds.height() * this.zoomLevel; + + /* Set new top offset */ + var offsetTop = (canvas.node.parentNode.parentNode.parentNode.offsetHeight - newHeight) / 2.0; + offsetTop = offsetTop > 20 ? offsetTop - 20 : 0; + canvas.node.parentNode.parentNode.style.marginTop = offsetTop + "px"; + offsetTop += 5; + canvas.getHTMLContainer().style.top = offsetTop + "px"; + + /*readjust scrollbar*/ + var newScrollTop = scrollNode.scrollTop - Math.round((canvas.getHTMLContainer().parentNode.getHeight() - newHeight) / 2) + this.diff; + var newScrollLeft = scrollNode.scrollLeft - Math.round((canvas.getHTMLContainer().parentNode.getWidth() - newWidth) / 2) + this.diff; + + /* Set new Zoom-Level */ + canvas.setSize({width: newWidth, height: newHeight}, true); + + /* Set Scale-Factor */ + canvas.node.setAttributeNS(null, "transform", "scale(" + this.zoomLevel + ")"); + + /* Refresh the Selection */ + this.facade.updateSelection(); + scrollNode.scrollTop = newScrollTop; + scrollNode.scrollLeft = newScrollLeft; + + /* Update the zoom-level*/ + canvas.zoomLevel = this.zoomLevel; + }, + + + /** + * It calculates the zoom level to fit whole model into the visible area + * of the canvas. Than the model gets zoomed and the position of the + * scroll bars are adjusted. + * + */ + zoomFitToModel: function () { + + /* Get the size of the visible area of the canvas */ + var scrollNode = this.facade.getCanvas().getHTMLContainer().parentNode.parentNode; + var visibleHeight = scrollNode.getHeight() - 30; + var visibleWidth = scrollNode.getWidth() - 30; + + var nodes = this.facade.getCanvas().getChildShapes(); + + if (!nodes || nodes.length < 1) { + return false; + } + + /* Calculate size of canvas to fit the model */ + var bounds = nodes[0].absoluteBounds().clone(); + nodes.each(function (node) { + bounds.include(node.absoluteBounds().clone()); + }); + + + /* Set new Zoom Level */ + var scaleFactorWidth = visibleWidth / bounds.width(); + var scaleFactorHeight = visibleHeight / bounds.height(); + + /* Choose the smaller zoom level to fit the whole model */ + var zoomFactor = scaleFactorHeight < scaleFactorWidth ? scaleFactorHeight : scaleFactorWidth; + + /*Test if maximum zoom is reached*/ + if (zoomFactor > this.maxFitToScreenLevel) { + zoomFactor = this.maxFitToScreenLevel + } + /* Do zooming */ + this.setAFixZoomLevel(zoomFactor); + + /* Set scroll bar position */ + scrollNode.scrollTop = Math.round(bounds.upperLeft().y * this.zoomLevel) - 5; + scrollNode.scrollLeft = Math.round(bounds.upperLeft().x * this.zoomLevel) - 5; + + }, + + /** + * It checks if the zoom level is less or equal to the level, which is required + * to schow the whole canvas. + * + * @private + */ + _checkSize: function () { + var canvasParent = this.facade.getCanvas().getHTMLContainer().parentNode; + var minForCanvas = Math.min((canvasParent.parentNode.getWidth() / canvasParent.getWidth()), (canvasParent.parentNode.getHeight() / canvasParent.getHeight())); + return 1.05 > minForCanvas; + + }, + /** + * It checks if the zoom level is included in the definined zoom + * level range. + * + * @private + */ + _checkZoomLevelRange: function () { + /*var canvasParent=this.facade.getCanvas().getHTMLContainer().parentNode; + var maxForCanvas= Math.max((canvasParent.parentNode.getWidth()/canvasParent.getWidth()),(canvasParent.parentNode.getHeight()/canvasParent.getHeight())); + if(this.zoomLevel > maxForCanvas) { + this.zoomLevel = maxForCanvas; + }*/ + if (this.zoomLevel < this.minZoomLevel) { + this.zoomLevel = this.minZoomLevel; + } + + if (this.zoomLevel > this.maxZoomLevel) { + this.zoomLevel = this.maxZoomLevel; + } + } +}; + +ORYX.Plugins.View = Clazz.extend(ORYX.Plugins.View); +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +if (!Signavio) { + var Signavio = {} +} +; +if (!Signavio.Core) { + Signavio.Core = {} +} +; +Signavio.Core.Version = "1.0"; +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +if (!Signavio) { + var Signavio = new Object(); +} + +if (!Signavio.Plugins) { + Signavio.Plugins = new Object(); +} + +if (!Signavio.Plugins.Utils) { + Signavio.Plugins.Utils = new Object(); +} + +if (!Signavio.Helper) { + Signavio.Helper = new Object(); +} + + +new function () { + + /** + * Provides an uniq id + * @overwrite + * @return {String} + * + */ + ORYX.Editor.provideId = function () { + var res = [], hex = '0123456789ABCDEF'; + + for (var i = 0; i < 36; i++) res[i] = Math.floor(Math.random() * 0x10); + + res[14] = 4; + res[19] = (res[19] & 0x3) | 0x8; + + for (var i = 0; i < 36; i++) res[i] = hex[res[i]]; + + res[8] = res[13] = res[18] = res[23] = '-'; + + return "sid-" + res.join(''); + }; + + +}(); + +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +if (!ORYX.Plugins) { + ORYX.Plugins = new Object(); +} + +/** + * This plugin is responsible for displaying loading indicators and to prevent + * the user from accidently unloading the page by, e.g., pressing the backspace + * button and returning to the previous site in history. + * @param {Object} facade The editor plugin facade to register enhancements with. + */ +ORYX.Plugins.Loading = { + + construct: function (facade) { + + this.facade = facade; + + // The parent Node + this.node = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", this.facade.getCanvas().getHTMLContainer().parentNode, ['div', { + 'class': 'LoadingIndicator' + }, '']); + + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADING_ENABLE, this.enableLoading.bind(this)); + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADING_DISABLE, this.disableLoading.bind(this)); + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADING_STATUS, this.showStatus.bind(this)); + + this.disableLoading(); + }, + + enableLoading: function (options) { + if (options.text) + this.node.innerHTML = options.text + "..."; + else + this.node.innerHTML = ORYX.I18N.Loading.waiting; + this.node.removeClassName('StatusIndicator'); + this.node.addClassName('LoadingIndicator'); + this.node.style.display = "block"; + + var pos = this.facade.getCanvas().rootNode.parentNode.parentNode.parentNode.parentNode; + + this.node.style.top = pos.offsetTop + 'px'; + this.node.style.left = pos.offsetLeft + 'px'; + + }, + + disableLoading: function () { + this.node.style.display = "none"; + }, + + showStatus: function (options) { + if (options.text) { + this.node.innerHTML = options.text; + this.node.addClassName('StatusIndicator'); + this.node.removeClassName('LoadingIndicator'); + this.node.style.display = 'block'; + + var pos = this.facade.getCanvas().rootNode.parentNode.parentNode.parentNode.parentNode; + + this.node.style.top = pos.offsetTop + 'px'; + this.node.style.left = pos.offsetLeft + 'px'; + + var tout = options.timeout ? options.timeout : 2000; + + window.setTimeout((function () { + + this.disableLoading(); + + }).bind(this), tout); + } + + } +} + +ORYX.Plugins.Loading = Clazz.extend(ORYX.Plugins.Loading); +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +if (!ORYX.Plugins) { + ORYX.Plugins = new Object(); +} + +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +/** + * This plugin is responsible for resizing the canvas. + * @param {Object} facade The editor plugin facade to register enhancements with. + */ +ORYX.Plugins.CanvasResize = Clazz.extend({ + + construct: function (facade) { + + this.facade = facade; + new ORYX.Plugins.CanvasResizeButton(this.facade.getCanvas(), "N", this.resize.bind(this)); + new ORYX.Plugins.CanvasResizeButton(this.facade.getCanvas(), "W", this.resize.bind(this)); + new ORYX.Plugins.CanvasResizeButton(this.facade.getCanvas(), "E", this.resize.bind(this)); + new ORYX.Plugins.CanvasResizeButton(this.facade.getCanvas(), "S", this.resize.bind(this)); + + window.setTimeout(function () { + jQuery(window).trigger('resize'); + }); + + }, + + resize: function (position, shrink) { + + resizeCanvas = function (position, extentionSize, facade) { + var canvas = facade.getCanvas(); + var b = canvas.bounds; + var scrollNode = facade.getCanvas().getHTMLContainer().parentNode.parentNode; + + if (position == "E" || position == "W") { + canvas.setSize({ + width: (b.width() + extentionSize) * canvas.zoomLevel, + height: (b.height()) * canvas.zoomLevel + }) + + } else if (position == "S" || position == "N") { + canvas.setSize({ + width: (b.width()) * canvas.zoomLevel, + height: (b.height() + extentionSize) * canvas.zoomLevel + }) + } + + if (position == "N" || position == "W") { + + var move = position == "N" ? {x: 0, y: extentionSize} : {x: extentionSize, y: 0}; + + // Move all children + canvas.getChildNodes(false, function (shape) { + shape.bounds.moveBy(move) + }) + // Move all dockers, when the edge has at least one docked shape + var edges = canvas.getChildEdges().findAll(function (edge) { + return edge.getAllDockedShapes().length > 0 + }) + var dockers = edges.collect(function (edge) { + return edge.dockers.findAll(function (docker) { + return !docker.getDockedShape() + }) + }).flatten(); + dockers.each(function (docker) { + docker.bounds.moveBy(move) + }) + } else if (position == "S") { + scrollNode.scrollTop += extentionSize; + } else if (position == "E") { + scrollNode.scrollLeft += extentionSize; + } + + jQuery(window).trigger('resize'); + + canvas.update(); + facade.updateSelection(); + } + + var commandClass = ORYX.Core.Command.extend({ + construct: function (position, extentionSize, facade) { + this.position = position; + this.extentionSize = extentionSize; + this.facade = facade; + }, + execute: function () { + resizeCanvas(this.position, this.extentionSize, this.facade); + }, + rollback: function () { + resizeCanvas(this.position, -this.extentionSize, this.facade); + }, + update: function () { + } + }); + + var extentionSize = ORYX.CONFIG.CANVAS_RESIZE_INTERVAL; + if (shrink) extentionSize = -extentionSize; + var command = new commandClass(position, extentionSize, this.facade); + + this.facade.executeCommands([command]); + + } + +}); + + +ORYX.Plugins.CanvasResizeButton = Clazz.extend({ + + construct: function (canvas, position, callback) { + this.canvas = canvas; + var parentNode = canvas.getHTMLContainer().parentNode; + + window.myParent = parentNode; + + var actualScrollNode = jQuery('#canvasSection')[0]; + var scrollNode = actualScrollNode; + var canvasNode = jQuery('#canvasSection').find(".ORYX_Editor")[0]; + var svgRootNode = canvasNode.children[0]; + + var iconClass = 'glyphicon glyphicon-chevron-'; + var iconClassShrink = 'glyphicon glyphicon-chevron-'; + if (position == 'N') { + iconClass += 'up'; + iconClassShrink += 'down'; + } else if (position == 'S') { + iconClass += 'down'; + iconClassShrink += 'up'; + } else if (position == 'E') { + iconClass += 'right'; + iconClassShrink += 'left'; + } else if (position == 'W') { + iconClass += 'left'; + iconClassShrink += 'right'; + } + + // The buttons + var idGrow = 'canvas-shrink-' + position; + var idShrink = 'canvas-grow-' + position; + + var buttonGrow = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", parentNode, ['div', { + 'class': 'canvas_resize_indicator canvas_resize_indicator_grow' + ' ' + position, + 'id': idGrow, + 'title': ORYX.I18N.RESIZE.tipGrow + ORYX.I18N.RESIZE[position] + }, + ['i', {'class': iconClass}] + ]); + var buttonShrink = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", parentNode, ['div', { + 'class': 'canvas_resize_indicator canvas_resize_indicator_shrink' + ' ' + position, + 'id': idShrink, + 'title': ORYX.I18N.RESIZE.tipGrow + ORYX.I18N.RESIZE[position] + }, + ['i', {'class': iconClassShrink}] + ]); + // Defines a callback which gives back + // a boolean if the current mouse event + // is over the particular button area + var offSetWidth = 60; + var isOverOffset = function (event) { + + var isOverButton = event.target.id.indexOf("canvas-shrink") != -1 + || event.target.id.indexOf("canvas-grow") != -1 + || event.target.parentNode.id.indexOf("canvas-shrink") != -1 + || event.target.parentNode.id.indexOf("canvas-grow") != -1; + if (isOverButton) { + if (event.target.id == idGrow || event.target.id == idShrink || + event.target.parentNode.id == idGrow || event.target.parentNode.id == idShrink) { + return true; + } else { + return false; + } + } + + if (event.target != parentNode && event.target != scrollNode && event.target != scrollNode.firstChild && event.target != svgRootNode && event.target != scrollNode) { + return false; + } + + //if(inCanvas){offSetWidth=30} else {offSetWidth=30*2} + //Safari work around + var X = event.offsetX !== undefined ? event.offsetX : event.layerX; + var Y = event.offsetY !== undefined ? event.offsetY : event.layerY; + + var canvasOffset = 0; + if (canvasNode.clientWidth < actualScrollNode.clientWidth) { + var widthDiff = actualScrollNode.clientWidth - canvasNode.clientWidth; + canvasOffset = widthDiff / 2; + } + + // Adjust to relative location to the actual viewport + Y = Y - actualScrollNode.scrollTop; + X = X - actualScrollNode.scrollLeft; + + + if (position == "N") { + return Y < offSetWidth; + } else if (position == "W") { + return X < offSetWidth + canvasOffset; + } else if (position == "E") { + return actualScrollNode.clientWidth - X < offSetWidth + canvasOffset; + } else if (position == "S") { + return actualScrollNode.clientHeight - Y < offSetWidth; + } + + return false; + }; + + var showButtons = (function () { + buttonGrow.show(); + + var w = canvas.bounds.width(); + var h = canvas.bounds.height(); + + if (position == "N" && (h - ORYX.CONFIG.CANVAS_RESIZE_INTERVAL > ORYX.CONFIG.CANVAS_MIN_HEIGHT)) buttonShrink.show(); + else if (position == "E" && (w - ORYX.CONFIG.CANVAS_RESIZE_INTERVAL > ORYX.CONFIG.CANVAS_MIN_WIDTH)) buttonShrink.show(); + else if (position == "S" && (h - ORYX.CONFIG.CANVAS_RESIZE_INTERVAL > ORYX.CONFIG.CANVAS_MIN_HEIGHT)) buttonShrink.show(); + else if (position == "W" && (w - ORYX.CONFIG.CANVAS_RESIZE_INTERVAL > ORYX.CONFIG.CANVAS_MIN_WIDTH)) buttonShrink.show(); + else buttonShrink.hide(); + + + }).bind(this); + + var hideButtons = function () { + buttonGrow.hide(); + buttonShrink.hide(); + }; + + // If the mouse move is over the button area, show the button + parentNode.parentNode.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, function (event) { + if (isOverOffset(event)) { + showButtons(); + } else { + hideButtons() + } + }, false); + // If the mouse is over the button, show them + buttonGrow.addEventListener(ORYX.CONFIG.EVENT_MOUSEOVER, function (event) { + showButtons(); + }, true); + buttonShrink.addEventListener(ORYX.CONFIG.EVENT_MOUSEOVER, function (event) { + showButtons(); + }, true); + // If the mouse is out, hide the button + //scrollNode.addEventListener( ORYX.CONFIG.EVENT_MOUSEOUT, function(event){button.hide()}, true ) + parentNode.parentNode.addEventListener(ORYX.CONFIG.EVENT_MOUSEOUT, function (event) { + hideButtons() + }, true); + //svgRootNode.addEventListener( ORYX.CONFIG.EVENT_MOUSEOUT, function(event){ inCanvas = false } , true ); + + // Hide the button initialy + hideButtons(); + + // Add the callbacks + buttonGrow.addEventListener('click', function () { + callback(position); + showButtons(); + }, true); + buttonShrink.addEventListener('click', function () { + callback(position, true); + showButtons(); + }, true); + + } + + +}); + +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +if (!ORYX.Plugins) + ORYX.Plugins = new Object(); + +ORYX.Plugins.RenameShapes = Clazz.extend({ + + facade: undefined, + + construct: function (facade) { + + this.facade = facade; + + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_CANVAS_SCROLL, this.hideField.bind(this)); + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DBLCLICK, this.actOnDBLClick.bind(this)); + this.facade.offer({ + keyCodes: [{ + keyCode: 113, // F2-Key + keyAction: ORYX.CONFIG.KEY_ACTION_DOWN + } + ], + functionality: this.renamePerF2.bind(this) + }); + + + document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEDOWN, this.hide.bind(this), true); + }, + + /** + * This method handles the "F2" key down event. The selected shape are looked + * up and the editing of title/name of it gets started. */ - _init: function(svgDocument){ - arguments.callee.$._init.apply(this, arguments); - - var svgNode = svgDocument.getElementsByTagName("g")[0]; //outer most g node - // set all required attributes - var attributeTitle = svgDocument.ownerDocument.createAttribute("title"); - attributeTitle.nodeValue = this.getStencil().title(); - svgNode.setAttributeNode(attributeTitle); - - var attributeId = svgDocument.ownerDocument.createAttribute("id"); - attributeId.nodeValue = this.id; - svgNode.setAttributeNode(attributeId); - - // - var stencilTargetNode = this.node.childNodes[0].childNodes[0]; //" - svgNode = stencilTargetNode.appendChild(svgNode); - - // Add to the EventHandler - this.addEventHandlers(svgNode.parentNode); - - /**set minimum and maximum size*/ - var minSizeAttr = svgNode.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "minimumSize"); - if (minSizeAttr) { - minSizeAttr = minSizeAttr.replace("/,/g", " "); - var minSizeValues = minSizeAttr.split(" "); - minSizeValues = minSizeValues.without(""); - - if (minSizeValues.length > 1) { - this.minimumSize = { - width: parseFloat(minSizeValues[0]), - height: parseFloat(minSizeValues[1]) - }; + renamePerF2: function () { + var selectedShapes = this.facade.getSelection(); + this.actOnDBLClick(undefined, selectedShapes.first()); + }, + + actOnDBLClick: function (evt, shape) { + + if (!(shape instanceof ORYX.Core.Shape)) { + return; + } + + // Destroys the old input, if there is one + this.destroy(); + + // Get all properties which where at least one ref to view is set + var props = shape.getStencil().properties().findAll(function (item) { + return (item.refToView() + && item.refToView().length > 0 + && item.directlyEditable()); + }); + // from these, get all properties where write access are and the type is String or Expression + props = props.findAll(function (item) { + return !item.readonly() && (item.type() == ORYX.CONFIG.TYPE_STRING || item.type() == ORYX.CONFIG.TYPE_EXPRESSION || item.type() == ORYX.CONFIG.TYPE_DATASOURCE); + }); + + // Get all ref ids + var allRefToViews = props.collect(function (prop) { + return prop.refToView(); + }).flatten().compact(); + // Get all labels from the shape with the ref ids + var labels = shape.getLabels().findAll(function (label) { + return allRefToViews.any(function (toView) { + return label.id.endsWith(toView); + }); + }); + + // If there are no referenced labels --> return + if (labels.length == 0) { + return; + } + + // Define the nearest label + var nearestLabel = labels.length <= 1 ? labels[0] : null; + if (!nearestLabel) { + nearestLabel = labels.find(function (label) { + return label.node == evt.target || label.node == evt.target.parentNode; + }); + if (!nearestLabel) { + + var evtCoord = this.facade.eventCoordinates(evt); + + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + var ua = navigator.userAgent; + if (ua.indexOf('MSIE') >= 0) { + //IE 10 and below + var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); + if (zoom !== 100) { + additionalIEZoom = zoom / 100 + } + } + } + + if (additionalIEZoom !== 1) { + evtCoord.x = evtCoord.x / additionalIEZoom; + evtCoord.y = evtCoord.y / additionalIEZoom; + } + + evtCoord.y += $("editor-header").clientHeight - $("canvasSection").scrollTop - 5; + if (KISBPM.HEADER_CONFIG.showAppTitle == false) { + evtCoord.y += 61; + } + + evtCoord.x -= $("canvasSection").scrollLeft; + + var trans = this.facade.getCanvas().rootNode.lastChild.getScreenCTM(); + evtCoord.x *= trans.a; + evtCoord.y *= trans.d; + + var diff = labels.collect(function (label) { + var center = this.getCenterPosition(label.node); + var len = Math.sqrt(Math.pow(center.x - evtCoord.x, 2) + Math.pow(center.y - evtCoord.y, 2)); + return {diff: len, label: label}; + }.bind(this)); + + diff.sort(function (a, b) { + return a.diff > b.diff; + }); + + nearestLabel = diff[0].label; + } - else { - //set minimumSize to (1,1), so that width and height of the stencil can never be (0,0) - this.minimumSize = { - width: 1, - height: 1 - }; + } + // Get the particular property for the label + var prop = props.find(function (item) { + return item.refToView().any(function (toView) { + return nearestLabel.id == shape.id + toView; + }); + }); + + // Get the center position from the nearest label + var width = Math.min(Math.max(100, shape.bounds.width()), 200); + var center = this.getCenterPosition(nearestLabel.node, shape); + center.x -= (width / 2); + var propId = prop.prefix() + "-" + prop.id(); + var textInput = document.createElement("textarea"); + textInput.id = 'shapeTextInput'; + textInput.style.position = 'absolute'; + textInput.style.width = width + 'px'; + textInput.style.left = (center.x < 10) ? 10 : center.x + 'px'; + textInput.style.top = (center.y - 15) + 'px'; + textInput.className = 'x-form-textarea x-form-field x_form_text_set_absolute'; + textInput.value = shape.properties[propId]; + this.oldValueText = shape.properties[propId]; + document.getElementById('canvasSection').appendChild(textInput); + this.shownTextField = textInput; + + + // Value change listener needs to be defined now since we reference it in the text field + this.updateValueFunction = function (newValue, oldValue) { + var currentEl = shape; + var facade = this.facade; + + if (oldValue != newValue) { + // Implement the specific command for property change + var commandClass = ORYX.Core.Command.extend({ + construct: function () { + this.el = currentEl; + this.propId = propId; + this.oldValue = oldValue; + this.newValue = newValue; + this.facade = facade; + }, + execute: function () { + this.el.setProperty(this.propId, this.newValue); + //this.el.update(); + this.facade.setSelection([this.el]); + this.facade.getCanvas().update(); + this.facade.updateSelection(); + }, + rollback: function () { + this.el.setProperty(this.propId, this.oldValue); + //this.el.update(); + this.facade.setSelection([this.el]); + this.facade.getCanvas().update(); + this.facade.updateSelection(); + } + }); + // Instantiated the class + var command = new commandClass(); + + // Execute the command + this.facade.executeCommands([command]); + } + }.bind(this); + + jQuery("#shapeTextInput").focus(); + + jQuery("#shapeTextInput").autogrow(); + + // Disable the keydown in the editor (that when hitting the delete button, the shapes not get deleted) + this.facade.disableEvent(ORYX.CONFIG.EVENT_KEYDOWN); + + }, + + getCenterPosition: function (svgNode, shape) { + + if (!svgNode) { + return {x: 0, y: 0}; + } + + var scale = this.facade.getCanvas().node.getScreenCTM(); + var absoluteXY = shape.bounds.upperLeft(); + + var hasParent = true; + var searchShape = shape; + while (hasParent) { + if (searchShape.getParentShape().getStencil().idWithoutNs() === 'BPMNDiagram') { + hasParent = false; + } else { + var parentXY = searchShape.getParentShape().bounds.upperLeft(); + absoluteXY.x += parentXY.x; + absoluteXY.y += parentXY.y; + searchShape = searchShape.getParentShape(); + } + } + + var center = shape.bounds.midPoint(); + center.x += absoluteXY.x + scale.e; + center.y += absoluteXY.y + scale.f; + + center.x *= scale.a; + center.y *= scale.d; + + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + var ua = navigator.userAgent; + if (ua.indexOf('MSIE') >= 0) { + //IE 10 and below + var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); + if (zoom !== 100) { + additionalIEZoom = zoom / 100 + } + } + } + + if (additionalIEZoom === 1) { + center.y = center.y - jQuery("#canvasSection").offset().top + 5; + center.x -= jQuery("#canvasSection").offset().left; + + } else { + var canvasOffsetLeft = jQuery("#canvasSection").offset().left; + var canvasScrollLeft = jQuery("#canvasSection").scrollLeft(); + var canvasScrollTop = jQuery("#canvasSection").scrollTop(); + + var offset = scale.e - (canvasOffsetLeft * additionalIEZoom); + var additionaloffset = 0; + if (offset > 10) { + additionaloffset = (offset / additionalIEZoom) - offset; + } + center.y = center.y - (jQuery("#canvasSection").offset().top * additionalIEZoom) + 5 + ((canvasScrollTop * additionalIEZoom) - canvasScrollTop); + center.x = center.x - (canvasOffsetLeft * additionalIEZoom) + additionaloffset + ((canvasScrollLeft * additionalIEZoom) - canvasScrollLeft); + } + + + return center; + }, + + hide: function (e) { + if (this.shownTextField && (!e || e.target !== this.shownTextField)) { + var newValue = this.shownTextField.value; + if (newValue !== this.oldValueText) { + this.updateValueFunction(newValue, this.oldValueText); } + this.destroy(); + } + }, + + hideField: function (e) { + if (this.shownTextField) { + this.destroy(); + } + }, + + destroy: function (e) { + var textInputComp = jQuery("#shapeTextInput"); + if (textInputComp) { + textInputComp.remove(); + delete this.shownTextField; + + this.facade.enableEvent(ORYX.CONFIG.EVENT_KEYDOWN); + } + } +}); +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +if (!ORYX.Plugins) + ORYX.Plugins = new Object(); + +/** + * Supports EPCs by offering a syntax check and export and import ability.. + * + * + */ +ORYX.Plugins.ProcessLink = Clazz.extend({ + + facade: undefined, + + /** + * Offers the plugin functionality: + * + */ + construct: function (facade) { + + this.facade = facade; + + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_PROPERTY_CHANGED, this.propertyChanged.bind(this)); + + }, + + + /** + * + * @param {Object} option + */ + propertyChanged: function (option, node) { + + if (option.name !== "oryx-refuri" || !node instanceof ORYX.Core.Node) { + return + } + + + if (option.value && option.value.length > 0 && option.value != "undefined") { + + this.show(node, option.value); + + } else { + + this.hide(node); + + } + + }, + + /** + * Shows the Link for a particular shape with a specific url + * + * @param {Object} shape + * @param {Object} url + */ + show: function (shape, url) { + + + // Generate the svg-representation of a link + var link = ORYX.Editor.graft("http://www.w3.org/2000/svg", null, + ['a', + {'target': '_blank'}, + ['path', + { + "stroke-width": 1.0, + "stroke": "#00DD00", + "fill": "#00AA00", + "d": "M3,3 l0,-2.5 l7.5,0 l0,-2.5 l7.5,4.5 l-7.5,3.5 l0,-2.5 l-8,0", + "line-captions": "round" + } + ] + ]); + + var link = ORYX.Editor.graft("http://www.w3.org/2000/svg", null, + ['a', + {'target': '_blank'}, + ['path', { + "style": "fill:#92BFFC;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.72", + "d": "M0 1.44 L0 15.05 L11.91 15.05 L11.91 5.98 L7.37 1.44 L0 1.44 Z" + }], + ['path', { + "style": "stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.72;fill:none;", + "transform": "translate(7.5, -8.5)", + "d": "M0 10.51 L0 15.05 L4.54 15.05" + }], + ['path', { + "style": "fill:#f28226;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.72", + "transform": "translate(-3, -1)", + "d": "M0 8.81 L0 13.06 L5.95 13.06 L5.95 15.05 A50.2313 50.2313 -175.57 0 0 10.77 11.08 A49.9128 49.9128 -1.28 0 0 5.95 6.54 L5.95 8.81 L0 8.81 Z" + }], + ]); + + /* + * + * [ 'a', + {'target': '_blank'}, + ['path', { "style": "fill:none;stroke-width:0.5px; stroke:#000000", "d": "M7,4 l0,2"}], + ['path', { "style": "fill:none;stroke-width:0.5px; stroke:#000000", "d": "M4,8 l-2,0 l0,6"}], + ['path', { "style": "fill:none;stroke-width:0.5px; stroke:#000000", "d": "M10,8 l2,0 l0,6"}], + ['rect', { "style": "fill:#96ff96;stroke:#000000;stroke-width:1", "width": 6, "height": 4, "x": 4, "y": 0}], + ['rect', { "style": "fill:#ffafff;stroke:#000000;stroke-width:1", "width": 6, "height": 4, "x": 4, "y": 6}], + ['rect', { "style": "fill:#96ff96;stroke:#000000;stroke-width:1", "width": 6, "height": 4, "x": 0, "y": 12}], + ['rect', { "style": "fill:#96ff96;stroke:#000000;stroke-width:1", "width": 6, "height": 4, "x": 8, "y": 12}], + ['rect', { "style": "fill:none;stroke:none;pointer-events:all", "width": 14, "height": 16, "x": 0, "y": 0}] + ]); + */ + + // Set the link with the special namespace + link.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", url); + + + // Shows the link in the overlay + this.facade.raiseEvent({ + type: ORYX.CONFIG.EVENT_OVERLAY_SHOW, + id: "arissupport.urlref_" + shape.id, + shapes: [shape], + node: link, + nodePosition: "SE" + }); + + }, + + /** + * Hides the Link for a particular shape + * + * @param {Object} shape + */ + hide: function (shape) { + + this.facade.raiseEvent({ + type: ORYX.CONFIG.EVENT_OVERLAY_HIDE, + id: "arissupport.urlref_" + shape.id + }); + + } +});/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +Array.prototype.insertFrom = function (from, to) { + to = Math.max(0, to); + from = Math.min(Math.max(0, from), this.length - 1); + + var el = this[from]; + var old = this.without(el); + var newA = old.slice(0, to); + newA.push(el); + if (old.length > to) { + newA = newA.concat(old.slice(to)) + } + ; + return newA; +} + +if (!ORYX.Plugins) + ORYX.Plugins = new Object(); + +ORYX.Plugins.Arrangement = ORYX.Plugins.AbstractPlugin.extend({ + + facade: undefined, + + construct: function (facade) { + this.facade = facade; + + // Z-Ordering + /** Hide for SIGNAVIO + + this.facade.offer({ + 'name':ORYX.I18N.Arrangement.btf, + 'functionality': this.setZLevel.bind(this, this.setToTop), + 'group': ORYX.I18N.Arrangement.groupZ, + 'icon': ORYX.PATH + "images/shape_move_front.png", + 'description': ORYX.I18N.Arrangement.btfDesc, + 'index': 1, + 'minShape': 1}); + + this.facade.offer({ + 'name':ORYX.I18N.Arrangement.btb, + 'functionality': this.setZLevel.bind(this, this.setToBack), + 'group': ORYX.I18N.Arrangement.groupZ, + 'icon': ORYX.PATH + "images/shape_move_back.png", + 'description': ORYX.I18N.Arrangement.btbDesc, + 'index': 2, + 'minShape': 1}); + + this.facade.offer({ + 'name':ORYX.I18N.Arrangement.bf, + 'functionality': this.setZLevel.bind(this, this.setForward), + 'group': ORYX.I18N.Arrangement.groupZ, + 'icon': ORYX.PATH + "images/shape_move_forwards.png", + 'description': ORYX.I18N.Arrangement.bfDesc, + 'index': 3, + 'minShape': 1}); + + this.facade.offer({ + 'name':ORYX.I18N.Arrangement.bb, + 'functionality': this.setZLevel.bind(this, this.setBackward), + 'group': ORYX.I18N.Arrangement.groupZ, + 'icon': ORYX.PATH + "images/shape_move_backwards.png", + 'description': ORYX.I18N.Arrangement.bbDesc, + 'index': 4, + 'minShape': 1}); + + // Aligment + this.facade.offer({ + 'name':ORYX.I18N.Arrangement.ab, + 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_BOTTOM]), + 'group': ORYX.I18N.Arrangement.groupA, + 'icon': ORYX.PATH + "images/shape_align_bottom.png", + 'description': ORYX.I18N.Arrangement.abDesc, + 'index': 1, + 'minShape': 2}); + + + + this.facade.offer({ + 'name':ORYX.I18N.Arrangement.at, + 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_TOP]), + 'group': ORYX.I18N.Arrangement.groupA, + 'icon': ORYX.PATH + "images/shape_align_top.png", + 'description': ORYX.I18N.Arrangement.atDesc, + 'index': 3, + 'minShape': 2}); + + this.facade.offer({ + 'name':ORYX.I18N.Arrangement.al, + 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_LEFT]), + 'group': ORYX.I18N.Arrangement.groupA, + 'icon': ORYX.PATH + "images/shape_align_left.png", + 'description': ORYX.I18N.Arrangement.alDesc, + 'index': 4, + 'minShape': 2}); + + this.facade.offer({ + 'name':ORYX.I18N.Arrangement.ar, + 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_RIGHT]), + 'group': ORYX.I18N.Arrangement.groupA, + 'icon': ORYX.PATH + "images/shape_align_right.png", + 'description': ORYX.I18N.Arrangement.arDesc, + 'index': 6, + 'minShape': 2}); + + **/ + + this.facade.offer({ + 'name': ORYX.I18N.Arrangement.am, + 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_MIDDLE]), + 'group': ORYX.I18N.Arrangement.groupA, + 'icon': ORYX.PATH + "images/shape_align_middle.png", + 'description': ORYX.I18N.Arrangement.amDesc, + 'index': 1, + 'minShape': 2 + }); + + this.facade.offer({ + 'name': ORYX.I18N.Arrangement.ac, + 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_CENTER]), + 'group': ORYX.I18N.Arrangement.groupA, + 'icon': ORYX.PATH + "images/shape_align_center.png", + 'description': ORYX.I18N.Arrangement.acDesc, + 'index': 2, + 'minShape': 2 + }); + + + this.facade.offer({ + 'name': ORYX.I18N.Arrangement.as, + 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_SIZE]), + 'group': ORYX.I18N.Arrangement.groupA, + 'icon': ORYX.PATH + "images/shape_align_size.png", + 'description': ORYX.I18N.Arrangement.asDesc, + 'index': 3, + 'minShape': 2 + }); + + + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_ARRANGEMENT_TOP, this.setZLevel.bind(this, this.setToTop)); + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_ARRANGEMENT_BACK, this.setZLevel.bind(this, this.setToBack)); + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_ARRANGEMENT_FORWARD, this.setZLevel.bind(this, this.setForward)); + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_ARRANGEMENT_BACKWARD, this.setZLevel.bind(this, this.setBackward)); + + + }, + + onSelectionChanged: function (elemnt) { + var selection = this.facade.getSelection(); + if (selection.length === 1 && selection[0] instanceof ORYX.Core.Edge) { + this.setToTop(selection); } - - var maxSizeAttr = svgNode.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "maximumSize"); - if (maxSizeAttr) { - maxSizeAttr = maxSizeAttr.replace("/,/g", " "); - var maxSizeValues = maxSizeAttr.split(" "); - maxSizeValues = maxSizeValues.without(""); - - if (maxSizeValues.length > 1) { - this.maximumSize = { - width: parseFloat(maxSizeValues[0]), - height: parseFloat(maxSizeValues[1]) - }; + }, + + setZLevel: function (callback, event) { + + //Command-Pattern for dragging one docker + var zLevelCommand = ORYX.Core.Command.extend({ + construct: function (callback, elements, facade) { + this.callback = callback; + this.elements = elements; + // For redo, the previous elements get stored + this.elAndIndex = elements.map(function (el) { + return {el: el, previous: el.parent.children[el.parent.children.indexOf(el) - 1]} + }) + this.facade = facade; + }, + execute: function () { + + // Call the defined z-order callback with the elements + this.callback(this.elements) + this.facade.setSelection(this.elements) + }, + rollback: function () { + + // Sort all elements on the index of there containment + var sortedEl = this.elAndIndex.sortBy(function (el) { + var value = el.el; + var t = $A(value.node.parentNode.childNodes); + return t.indexOf(value.node); + }); + + // Every element get setted back bevor the old previous element + for (var i = 0; i < sortedEl.length; i++) { + var el = sortedEl[i].el; + var p = el.parent; + var oldIndex = p.children.indexOf(el); + var newIndex = p.children.indexOf(sortedEl[i].previous); + newIndex = newIndex || 0 + p.children = p.children.insertFrom(oldIndex, newIndex) + el.node.parentNode.insertBefore(el.node, el.node.parentNode.childNodes[newIndex + 1]); + } + + // Reset the selection + this.facade.setSelection(this.elements) } + }); + + // Instanziate the dockCommand + var command = new zLevelCommand(callback, this.facade.getSelection(), this.facade); + if (event.excludeCommand) { + command.execute(); + } else { + this.facade.executeCommands([command]); } - - if (this.minimumSize && this.maximumSize && - (this.minimumSize.width > this.maximumSize.width || - this.minimumSize.height > this.maximumSize.height)) { - - //TODO wird verschluckt!!! - throw this + ": Minimum Size must be greater than maxiumSize."; - } - - /**get current bounds and adjust it to upperLeft == (0,0)*/ - //initialize all SVGShape objects - this._svgShapes = this._initSVGShapes(svgNode); - - //get upperLeft and lowerRight of stencil - var upperLeft = { - x: undefined, - y: undefined - }; - var lowerRight = { - x: undefined, - y: undefined - }; - var me = this; - this._svgShapes.each(function(svgShape){ - upperLeft.x = (upperLeft.x !== undefined) ? Math.min(upperLeft.x, svgShape.x) : svgShape.x; - upperLeft.y = (upperLeft.y !== undefined) ? Math.min(upperLeft.y, svgShape.y) : svgShape.y; - lowerRight.x = (lowerRight.x !== undefined) ? Math.max(lowerRight.x, svgShape.x + svgShape.width) : svgShape.x + svgShape.width; - lowerRight.y = (lowerRight.y !== undefined) ? Math.max(lowerRight.y, svgShape.y + svgShape.height) : svgShape.y + svgShape.height; - - /** set if resizing is enabled */ - //TODO isResizable durch die beiden anderen booleans ersetzen? - if (svgShape.isHorizontallyResizable) { - me.isHorizontallyResizable = true; - me.isResizable = true; - } - if (svgShape.isVerticallyResizable) { - me.isVerticallyResizable = true; - me.isResizable = true; + + }, + + setToTop: function (elements) { + + // Sortieren des Arrays nach dem Index des SVGKnotens im Bezug auf dem Elternknoten. + var tmpElem = elements.sortBy(function (value, index) { + var t = $A(value.node.parentNode.childNodes); + return t.indexOf(value.node); + }); + // Sortiertes Array wird nach oben verschoben. + tmpElem.each(function (value) { + var p = value.parent; + if (p.children.last() === value) { + return; } - if (svgShape.anchorTop && svgShape.anchorBottom) { - me.isVerticallyResizable = true; - me.isResizable = true; + p.children = p.children.without(value) + p.children.push(value); + value.node.parentNode.appendChild(value.node); + }); + }, + + setToBack: function (elements) { + // Sortieren des Arrays nach dem Index des SVGKnotens im Bezug auf dem Elternknoten. + var tmpElem = elements.sortBy(function (value, index) { + var t = $A(value.node.parentNode.childNodes); + return t.indexOf(value.node); + }); + + tmpElem = tmpElem.reverse(); + + // Sortiertes Array wird nach unten verschoben. + tmpElem.each(function (value) { + var p = value.parent + p.children = p.children.without(value) + p.children.unshift(value); + value.node.parentNode.insertBefore(value.node, value.node.parentNode.firstChild); + }); + + + }, + + setBackward: function (elements) { + // Sortieren des Arrays nach dem Index des SVGKnotens im Bezug auf dem Elternknoten. + var tmpElem = elements.sortBy(function (value, index) { + var t = $A(value.node.parentNode.childNodes); + return t.indexOf(value.node); + }); + + // Reverse the elements + tmpElem = tmpElem.reverse(); + + // Delete all Nodes who are the next Node in the nodes-Array + var compactElem = tmpElem.findAll(function (el) { + return !tmpElem.some(function (checkedEl) { + return checkedEl.node == el.node.previousSibling + }) + }); + + // Sortiertes Array wird nach eine Ebene nach oben verschoben. + compactElem.each(function (el) { + if (el.node.previousSibling === null) { + return; } - if (svgShape.anchorLeft && svgShape.anchorRight) { - me.isHorizontallyResizable = true; - me.isResizable = true; + var p = el.parent; + var index = p.children.indexOf(el); + p.children = p.children.insertFrom(index, index - 1) + el.node.parentNode.insertBefore(el.node, el.node.previousSibling); + }); + + + }, + + setForward: function (elements) { + // Sortieren des Arrays nach dem Index des SVGKnotens im Bezug auf dem Elternknoten. + var tmpElem = elements.sortBy(function (value, index) { + var t = $A(value.node.parentNode.childNodes); + return t.indexOf(value.node); + }); + + + // Delete all Nodes who are the next Node in the nodes-Array + var compactElem = tmpElem.findAll(function (el) { + return !tmpElem.some(function (checkedEl) { + return checkedEl.node == el.node.nextSibling + }) + }); + + + // Sortiertes Array wird eine Ebene nach unten verschoben. + compactElem.each(function (el) { + var nextNode = el.node.nextSibling + if (nextNode === null) { + return; } + var index = el.parent.children.indexOf(el); + var p = el.parent; + p.children = p.children.insertFrom(index, index + 1) + el.node.parentNode.insertBefore(nextNode, el.node); }); - - //move all SVGShapes by -upperLeft - this._svgShapes.each(function(svgShape){ - svgShape.x -= upperLeft.x; - svgShape.y -= upperLeft.y; - svgShape.update(); + }, + + + alignShapes: function (way) { + + var elements = this.facade.getSelection(); + + // Set the elements to all Top-Level elements + elements = this.facade.getCanvas().getShapesWithSharedParent(elements); + // Get only nodes + elements = elements.findAll(function (value) { + return (value instanceof ORYX.Core.Node) }); - - //set bounds of shape - //the offsets are also needed for positioning the magnets and the docker - var offsetX = upperLeft.x; - var offsetY = upperLeft.y; - - lowerRight.x -= offsetX; - lowerRight.y -= offsetY; - upperLeft.x = 0; - upperLeft.y = 0; - - //prevent that width or height of initial bounds is 0 - if (lowerRight.x === 0) { - lowerRight.x = 1; - } - if (lowerRight.y === 0) { - lowerRight.y = 1; + // Delete all attached intermediate events from the array + elements = elements.findAll(function (value) { + var d = value.getIncomingShapes() + return d.length == 0 || !elements.include(d[0]) + }); + if (elements.length < 2) { + return; } - - this._oldBounds.set(upperLeft, lowerRight); - this.bounds.set(upperLeft, lowerRight); - - /**initialize magnets */ - - var magnets = svgDocument.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_ORYX, "magnets"); - - if (magnets && magnets.length > 0) { - - magnets = $A(magnets[0].getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_ORYX, "magnet")); - - var me = this; - magnets.each(function(magnetElem){ - var magnet = new ORYX.Core.Controls.Magnet({ - eventHandlerCallback: me.eventHandlerCallback - }); - var cx = parseFloat(magnetElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "cx")); - var cy = parseFloat(magnetElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "cy")); - magnet.bounds.centerMoveTo({ - x: cx - offsetX, - y: cy - offsetY - }); - - //get anchors - var anchors = magnetElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "anchors"); - if (anchors) { - anchors = anchors.replace("/,/g", " "); - anchors = anchors.split(" ").without(""); - for(var i = 0; i < anchors.length; i++) { - switch(anchors[i].toLowerCase()) { - case "left": - magnet.anchorLeft = true; - break; - case "right": - magnet.anchorRight = true; - break; - case "top": - magnet.anchorTop = true; - break; - case "bottom": - magnet.anchorBottom = true; - break; - } - } + + // get bounds of all shapes. + var bounds = elements[0].absoluteBounds().clone(); + elements.each(function (shape) { + bounds.include(shape.absoluteBounds().clone()); + }); + + // get biggest width and heigth + var maxWidth = 0; + var maxHeight = 0; + elements.each(function (shape) { + maxWidth = Math.max(shape.bounds.width(), maxWidth); + maxHeight = Math.max(shape.bounds.height(), maxHeight); + }); + + var commandClass = ORYX.Core.Command.extend({ + construct: function (elements, bounds, maxHeight, maxWidth, way, plugin) { + this.elements = elements; + this.bounds = bounds; + this.maxHeight = maxHeight; + this.maxWidth = maxWidth; + this.way = way; + this.facade = plugin.facade; + this.plugin = plugin; + this.orgPos = []; + }, + setBounds: function (shape, maxSize) { + if (!maxSize) + maxSize = {width: ORYX.CONFIG.MAXIMUM_SIZE, height: ORYX.CONFIG.MAXIMUM_SIZE}; + + if (!shape.bounds) { + throw "Bounds not definined." } - - me.add(magnet); - - //check, if magnet is default magnet - if (!this._defaultMagnet) { - var defaultAttr = magnetElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "default"); - if (defaultAttr && defaultAttr.toLowerCase() === "yes") { - me._defaultMagnet = magnet; + + var newBounds = { + a: { + x: shape.bounds.upperLeft().x - (this.maxWidth - shape.bounds.width()) / 2, + y: shape.bounds.upperLeft().y - (this.maxHeight - shape.bounds.height()) / 2 + }, + b: { + x: shape.bounds.lowerRight().x + (this.maxWidth - shape.bounds.width()) / 2, + y: shape.bounds.lowerRight().y + (this.maxHeight - shape.bounds.height()) / 2 + } + } + + /* If the new width of shape exceeds the maximum width, set width value to maximum. */ + if (this.maxWidth > maxSize.width) { + newBounds.a.x = shape.bounds.upperLeft().x - + (maxSize.width - shape.bounds.width()) / 2; + + newBounds.b.x = shape.bounds.lowerRight().x + (maxSize.width - shape.bounds.width()) / 2 + } + + /* If the new height of shape exceeds the maximum height, set height value to maximum. */ + if (this.maxHeight > maxSize.height) { + newBounds.a.y = shape.bounds.upperLeft().y - + (maxSize.height - shape.bounds.height()) / 2; + + newBounds.b.y = shape.bounds.lowerRight().y + (maxSize.height - shape.bounds.height()) / 2 + } + + /* set bounds of shape */ + shape.bounds.set(newBounds); + + }, + execute: function () { + // align each shape according to the way that was specified. + this.elements.each(function (shape, index) { + this.orgPos[index] = shape.bounds.upperLeft(); + + var relBounds = this.bounds.clone(); + var newCoordinates; + if (shape.parent && !(shape.parent instanceof ORYX.Core.Canvas)) { + var upL = shape.parent.absoluteBounds().upperLeft(); + relBounds.moveBy(-upL.x, -upL.y); + } + + switch (this.way) { + // align the shapes in the requested way. + case ORYX.CONFIG.EDITOR_ALIGN_BOTTOM: + newCoordinates = { + x: shape.bounds.upperLeft().x, + y: relBounds.b.y - shape.bounds.height() + }; + break; + + case ORYX.CONFIG.EDITOR_ALIGN_MIDDLE: + newCoordinates = { + x: shape.bounds.upperLeft().x, + y: (relBounds.a.y + relBounds.b.y - shape.bounds.height()) / 2 + }; + break; + + case ORYX.CONFIG.EDITOR_ALIGN_TOP: + newCoordinates = { + x: shape.bounds.upperLeft().x, + y: relBounds.a.y + }; + break; + + case ORYX.CONFIG.EDITOR_ALIGN_LEFT: + newCoordinates = { + x: relBounds.a.x, + y: shape.bounds.upperLeft().y + }; + break; + + case ORYX.CONFIG.EDITOR_ALIGN_CENTER: + newCoordinates = { + x: (relBounds.a.x + relBounds.b.x - shape.bounds.width()) / 2, + y: shape.bounds.upperLeft().y + }; + break; + + case ORYX.CONFIG.EDITOR_ALIGN_RIGHT: + newCoordinates = { + x: relBounds.b.x - shape.bounds.width(), + y: shape.bounds.upperLeft().y + }; + break; + + case ORYX.CONFIG.EDITOR_ALIGN_SIZE: + if (shape.isResizable) { + this.orgPos[index] = {a: shape.bounds.upperLeft(), b: shape.bounds.lowerRight()}; + this.setBounds(shape, shape.maximumSize); + } + break; } - } - }); - } - else { - // Add a Magnet in the Center of Shape - var magnet = new ORYX.Core.Controls.Magnet(); - magnet.bounds.centerMoveTo(this.bounds.width() / 2, this.bounds.height() / 2); - this.add(magnet); - } - - /**initialize docker */ - var dockerElem = svgDocument.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_ORYX, "docker"); - - if (dockerElem && dockerElem.length > 0) { - dockerElem = dockerElem[0]; - var docker = this.createDocker(); - var cx = parseFloat(dockerElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "cx")); - var cy = parseFloat(dockerElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "cy")); - docker.bounds.centerMoveTo({ - x: cx - offsetX, - y: cy - offsetY - }); - - //get anchors - var anchors = dockerElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "anchors"); - if (anchors) { - anchors = anchors.replace("/,/g", " "); - anchors = anchors.split(" ").without(""); - - for(var i = 0; i < anchors.length; i++) { - switch(anchors[i].toLowerCase()) { - case "left": - docker.anchorLeft = true; - break; - case "right": - docker.anchorRight = true; - break; - case "top": - docker.anchorTop = true; - break; - case "bottom": - docker.anchorBottom = true; - break; - } - } + + if (newCoordinates) { + var offset = { + x: shape.bounds.upperLeft().x - newCoordinates.x, + y: shape.bounds.upperLeft().y - newCoordinates.y + } + // Set the new position + shape.bounds.moveTo(newCoordinates); + this.plugin.layoutEdges(shape, shape.getAllDockedShapes(), offset); + //shape.update() + } + }.bind(this)); + + //this.facade.getCanvas().update(); + //this.facade.updateSelection(); + }, + rollback: function () { + this.elements.each(function (shape, index) { + if (this.way == ORYX.CONFIG.EDITOR_ALIGN_SIZE) { + if (shape.isResizable) { + shape.bounds.set(this.orgPos[index]); + } + } else { + shape.bounds.moveTo(this.orgPos[index]); + } + }.bind(this)); + + //this.facade.getCanvas().update(); + //this.facade.updateSelection(); + } + }) + + var command = new commandClass(elements, bounds, maxHeight, maxWidth, parseInt(way), this); + + this.facade.executeCommands([command]); + } +});/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ + +if (!ORYX.Plugins) + ORYX.Plugins = new Object(); + +ORYX.Plugins.Save = Clazz.extend({ + + facade: undefined, + + processURI: undefined, + + changeSymbol: "*", + + construct: function (facade) { + this.facade = facade; + + document.addEventListener("keydown", function (e) { + if (e.ctrlKey && e.keyCode === 83) { + Event.stop(e); } + }, false); + + window.onbeforeunload = this.onUnLoad.bind(this); + + this.changeDifference = 0; + + // Register on event for executing commands --> store all commands in a stack + // --> Execute + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_UNDO_EXECUTE, function () { + this.changeDifference++; + this.updateTitle(); + }.bind(this)); + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_EXECUTE_COMMANDS, function () { + this.changeDifference++; + this.updateTitle(); + }.bind(this)); + // --> Saved from other places in the editor + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_SAVED, function () { + this.changeDifference = 0; + this.updateTitle(); + }.bind(this)); + + // --> Rollback + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_UNDO_ROLLBACK, function () { + this.changeDifference--; + this.updateTitle(); + }.bind(this)); + + //TODO very critical for load time performance!!! + //this.serializedDOM = DataManager.__persistDOM(this.facade); + + this.hasChanges = this._hasChanges.bind(this); + }, + + updateTitle: function () { + + var value = window.document.title || document.getElementsByTagName("title")[0].childNodes[0].nodeValue; + + if (this.changeDifference === 0 && value.startsWith(this.changeSymbol)) { + window.document.title = value.slice(1); + } else if (this.changeDifference !== 0 && !value.startsWith(this.changeSymbol)) { + window.document.title = this.changeSymbol + "" + value; } - - /**initialize labels*/ - var textElems = svgNode.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'text'); - $A(textElems).each((function(textElem){ - var label = new ORYX.Core.SVG.Label({ - textElement: textElem, - shapeId: this.id - }); - label.x -= offsetX; - label.y -= offsetY; - this._labels[label.id] = label; - - label.registerOnChange(this.layout.bind(this)); - - // Only apply fitting on form-components - if(this._stencil.id().indexOf(ORYX.CONFIG.FORM_ELEMENT_ID_PREFIX) == 0) { - label.registerOnChange(this.fitToLabels.bind(this)); - } - - }).bind(this)); }, - - fitToLabels: function() { - var y = 0; - - this.getLabels().each(function(label){ - var lr = label.getY() + label.getHeight(); - if(lr > y) { - y = lr; - } - }); - - var bounds = this.bounds; - var boundsChanged = false; - - if(this.minimumSize) { - // Check if y-value exceeds the min-value. If not, stick to this value. - var minHeight = this.minimumSize.height; - if(y < minHeight && bounds.height() > minHeight && minHeight > this.forcedHeight) { - bounds.set(bounds.upperLeft().x, bounds.upperLeft().y, bounds.lowerRight().x, bounds.upperLeft().y + minHeight); - boundsChanged = true; - } else if(y > minHeight && bounds.height() != y && y > this.forcedHeight){ - bounds.set(bounds.upperLeft().x, bounds.upperLeft().y, bounds.lowerRight().x, bounds.upperLeft().y + y); - boundsChanged = true; - } else if(bounds.height() > this.forcedHeight && this.forcedHeight > 0) { - bounds.set(bounds.upperLeft().x, bounds.upperLeft().y, bounds.lowerRight().x, bounds.upperLeft().y + this.forcedHeight); - boundsChanged = true; - } - } - - if(boundsChanged) { - // Force facade to re-layout since bounds are changed AFTER layout has been performed - if(this.facade.getCanvas() != null) { - this.facade.getCanvas().update(); - } - - // Re-select if needed to force the select - if(this.facade.getSelection().member(this)) { - var selectedNow = this.facade.getSelection(); - this.facade.setSelection([]); - this.facade.setSelection(selectedNow); - } - } - }, - - /** - * Override the Method, that a docker is not shown - * - */ - createDocker: function() { - var docker = new ORYX.Core.Controls.Docker({eventHandlerCallback: this.eventHandlerCallback}); - docker.bounds.registerCallback(this._dockerChangedCallback); - - this.dockers.push( docker ); - docker.parent = this; - docker.bounds.registerCallback(this._changedCallback); - - return docker - }, - - toString: function(){ - return this._stencil.title() + " " + this.id + + _hasChanges: function () { + return this.changeDifference !== 0 || (this.facade.getModelMetaData()['new'] && this.facade.getCanvas().getChildShapes().size() > 0); + }, + + onUnLoad: function () { + if (this._hasChanges()) { + return ORYX.I18N.Save.unsavedData; + } } -}; -ORYX.Core.Node = ORYX.Core.Shape.extend(ORYX.Core.Node); +}); /* * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. * License rights for this program may be obtained from Alfresco Software, Ltd. @@ -15040,2449 +20104,1605 @@ ORYX.Core.Node = ORYX.Core.Shape.extend(ORYX.Core.Node); * All code Copyright 2013 KIS Consultancy all rights reserved */ -NAMESPACE_SVG = "http://www.w3.org/2000/svg"; -NAMESPACE_ORYX = "http://www.b3mn.org/oryx"; +if (!ORYX.Plugins) + ORYX.Plugins = new Object(); +ORYX.Plugins.DragDropResize = ORYX.Plugins.AbstractPlugin.extend({ -/** - * Init namespaces - */ -if (!ORYX) { - var ORYX = {}; -} -if (!ORYX.Core) { - ORYX.Core = {}; -} + /** + * Constructor + * @param {Object} Facade: The Facade of the Editor + */ + construct: function (facade) { + this.facade = facade; + + // Initialize variables + this.currentShapes = []; // Current selected Shapes + //this.pluginsData = []; // Available Plugins + this.toMoveShapes = []; // Shapes there will be moved + this.distPoints = []; // Distance Points for Snap on Grid + this.isResizing = false; // Flag: If there was currently resized + this.dragEnable = false; // Flag: If Dragging is enabled + this.dragIntialized = false; // Flag: If the Dragging is initialized + this.edgesMovable = true; // Flag: If an edge is docked it is not movable + this.offSetPosition = {x: 0, y: 0}; // Offset of the Dragging + this.faktorXY = {x: 1, y: 1}; // The Current Zoom-Faktor + this.containmentParentNode; // the current future parent node for the dragged shapes + this.isAddingAllowed = false; // flag, if adding current selected shapes to containmentParentNode is allowed + this.isAttachingAllowed = false; // flag, if attaching to the current shape is allowed + + this.callbackMouseMove = this.handleMouseMove.bind(this); + this.callbackMouseUp = this.handleMouseUp.bind(this); + + // Get the SVG-Containernode + var containerNode = this.facade.getCanvas().getSvgContainer(); + + // Create the Selected Rectangle in the SVG + this.selectedRect = new ORYX.Plugins.SelectedRect(containerNode); + + // Show grid line if enabled + if (ORYX.CONFIG.SHOW_GRIDLINE) { + this.vLine = new ORYX.Plugins.GridLine(containerNode, ORYX.Plugins.GridLine.DIR_VERTICAL); + this.hLine = new ORYX.Plugins.GridLine(containerNode, ORYX.Plugins.GridLine.DIR_HORIZONTAL); + } + // Get a HTML-ContainerNode + containerNode = this.facade.getCanvas().getHTMLContainer(); + + this.scrollNode = this.facade.getCanvas().rootNode.parentNode.parentNode; + + // Create the southeastern button for resizing + this.resizerSE = new ORYX.Plugins.Resizer(containerNode, "southeast", this.facade); + this.resizerSE.registerOnResize(this.onResize.bind(this)); // register the resize callback + this.resizerSE.registerOnResizeEnd(this.onResizeEnd.bind(this)); // register the resize end callback + this.resizerSE.registerOnResizeStart(this.onResizeStart.bind(this)); // register the resize start callback + + // Create the northwestern button for resizing + this.resizerNW = new ORYX.Plugins.Resizer(containerNode, "northwest", this.facade); + this.resizerNW.registerOnResize(this.onResize.bind(this)); // register the resize callback + this.resizerNW.registerOnResizeEnd(this.onResizeEnd.bind(this)); // register the resize end callback + this.resizerNW.registerOnResizeStart(this.onResizeStart.bind(this)); // register the resize start callback + + // For the Drag and Drop + // Register on MouseDown-Event on a Shape + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEDOWN, this.handleMouseDown.bind(this)); + }, -/** - * @classDescription Abstract base class for all connections. - * @extends {ORYX.Core.Shape} - * @param options {Object} - * - * TODO da die verschiebung der Edge nicht ueber eine - * translation gemacht wird, die sich auch auf alle kind UIObjects auswirkt, - * muessen die kinder hier beim verschieben speziell betrachtet werden. - * Das sollte ueberarbeitet werden. - * - */ -ORYX.Core.Edge = { /** - * Constructor - * @param {Object} options - * @param {Stencil} stencil + * On Mouse Down + * */ - construct: function(options, stencil, facade){ - arguments.callee.$.construct.apply(this, arguments); - - this.isMovable = true; - this.isSelectable = true; - - this._dockerUpdated = false; - - this._markers = new Hash(); //a hash map of SVGMarker objects where keys are the marker ids - this._paths = []; - this._interactionPaths = []; - this._dockersByPath = new Hash(); - this._markersByPath = new Hash(); - - /* Data structures to store positioning information of attached child nodes */ - this.attachedNodePositionData = new Hash(); - - //TODO was muss hier initial erzeugt werden? - var stencilNode = this.node.childNodes[0].childNodes[0]; - stencilNode = ORYX.Editor.graft("http://www.w3.org/2000/svg", stencilNode, ['g', { - "pointer-events": "painted" - }]); - - //Add to the EventHandler - this.addEventHandlers(stencilNode.parentNode); - - - this._oldBounds = this.bounds.clone(); - - //load stencil - this._init(this._stencil.view()); - - if (stencil instanceof Array) { - this.deserialize(stencil); + handleMouseDown: function (event, uiObj) { + // If the selection Bounds not intialized and the uiObj is not member of current selectio + // then return + if (!this.dragBounds || !this.currentShapes.member(uiObj) || !this.toMoveShapes.length) { + return; } - - }, - - _update: function(force){ - if(this._dockerUpdated || this.isChanged || force) { - - this.dockers.invoke("update"); - - if (false && (this.bounds.width() === 0 || this.bounds.height() === 0)) { - var width = this.bounds.width(); - var height = this.bounds.height(); - this.bounds.extend({ - x: width === 0 ? 2 : 0, - y: height === 0 ? 2 : 0 - }); - this.bounds.moveBy({ - x: width === 0 ? -1 : 0, - y: height === 0 ? -1 : 0 - }); - - } - - // TODO: Bounds muss abhaengig des Eltern-Shapes gesetzt werden - var upL = this.bounds.upperLeft(); - var oldUpL = this._oldBounds.upperLeft(); - var oldWidth = this._oldBounds.width() === 0 ? this.bounds.width() : this._oldBounds.width(); - var oldHeight = this._oldBounds.height() === 0 ? this.bounds.height() : this._oldBounds.height(); - var diffX = upL.x - oldUpL.x; - var diffY = upL.y - oldUpL.y; - var diffWidth = (this.bounds.width() / oldWidth) || 1; - var diffHeight = (this.bounds.height() / oldHeight) || 1; - - this.dockers.each((function(docker){ - // Unregister on BoundsChangedCallback - docker.bounds.unregisterCallback(this._dockerChangedCallback); - - // If there is any changes at the edge and is there is not an DockersUpdate - // set the new bounds to the docker - if (!this._dockerUpdated) { - docker.bounds.moveBy(diffX, diffY); - - if (diffWidth !== 1 || diffHeight !== 1) { - var relX = docker.bounds.upperLeft().x - upL.x; - var relY = docker.bounds.upperLeft().y - upL.y; - - docker.bounds.moveTo(upL.x + relX * diffWidth, upL.y + relY * diffHeight); - } - } - // Do Docker update and register on DockersBoundChange - docker.update(); - docker.bounds.registerCallback(this._dockerChangedCallback); - - }).bind(this)); - - if (this._dockerUpdated) { - var a = this.dockers.first().bounds.center(); - var b = this.dockers.first().bounds.center(); - - this.dockers.each((function(docker){ - var center = docker.bounds.center(); - a.x = Math.min(a.x, center.x); - a.y = Math.min(a.y, center.y); - b.x = Math.max(b.x, center.x); - b.y = Math.max(b.y, center.y); - }).bind(this)); - - //set the bounds of the the association - this.bounds.set(Object.clone(a), Object.clone(b)); - } - - upL = this.bounds.upperLeft(); oldUpL = this._oldBounds.upperLeft(); - diffWidth = (this.bounds.width() / (oldWidth||this.bounds.width())); diffHeight = (this.bounds.height() / (oldHeight||this.bounds.height())); - diffX = upL.x - oldUpL.x; diffY = upL.y - oldUpL.y; - - //reposition labels - this.getLabels().each(function(label) { - - if (label.getReferencePoint()){ - var ref = label.getReferencePoint(); - var from = ref.segment.from, to = ref.segment.to; - if (!from || !from.parent || !to || !to.parent) { - return; - } - - var fromPosition = from.bounds.center(), toPosition = to.bounds.center(); + ; + + // Start Dragging + this.dragEnable = true; + this.dragIntialized = true; + this.edgesMovable = true; + + // Calculate the current zoom factor + var a = this.facade.getCanvas().node.getScreenCTM(); + this.faktorXY.x = a.a; + this.faktorXY.y = a.d; + + var eventX = Event.pointerX(event); + var eventY = Event.pointerY(event); + + // Set the offset position of dragging + var upL = this.dragBounds.upperLeft(); + this.offSetPosition = { + x: eventX - (upL.x * this.faktorXY.x), + y: eventY - (upL.y * this.faktorXY.y) + }; - if (fromPosition.x === ref.segment.fromPosition.x && fromPosition.y === ref.segment.fromPosition.y && - toPosition.x === ref.segment.toPosition.x && toPosition.y === ref.segment.toPosition.y && !ref.dirty){ - return; - } - - if (!this.parent.initializingShapes) { - var oldDistance = ORYX.Core.Math.getDistanceBetweenTwoPoints(ref.segment.fromPosition, ref.segment.toPosition, ref.intersection); - var newIntersection = ORYX.Core.Math.getPointBetweenTwoPoints(fromPosition, toPosition, isNaN(oldDistance) ? 0.5 : oldDistance); - - /** - * Set position - */ - // Get the orthogonal identity vector of the current segment - var oiv = ORYX.Core.Math.getOrthogonalIdentityVector(fromPosition, toPosition); - var isHor = Math.abs(oiv.y)===1, isVer = Math.abs(oiv.x)===1; - oiv.x *= ref.distance; oiv.y *= ref.distance; // vector * distance - oiv.x += newIntersection.x; oiv.y += newIntersection.y; // vector + the intersection point - var mx = isHor && ref.orientation && (ref.iorientation||ref.orientation).endsWith("r") ? -label.getWidth() : 0; - var my = isVer && ref.orientation && (ref.iorientation||ref.orientation).startsWith("l") ? -label.getHeight()+2 : 0; - label.setX(oiv.x+mx); label.setY(oiv.y+my); - - // Update the reference point - this.updateReferencePointOfLabel(label, newIntersection, from, to); - } else { - var oiv = ORYX.Core.Math.getOrthogonalIdentityVector(fromPosition, toPosition); - oiv.x *= ref.distance; oiv.y *= ref.distance; // vector * distance - oiv.x += ref.intersection.x; oiv.y += ref.intersection.y; // vector + the intersection point - label.setX(oiv.x); label.setY(oiv.y); - ref.segment.fromPosition = fromPosition; ref.segment.toPosition = toPosition; - } - - return; - } - - // Update label position if no reference point is set - if (label.position && !this.parent.initializingShapes){ - var x = label.position.x + (diffX * (diffWidth||1)); - if (x > this.bounds.lowerRight().x){ - x += this.bounds.width()-(this.bounds.width()/(diffWidth||1)); - } - - var y = label.position.y + (diffY * (diffHeight||1)); - if (y > this.bounds.lowerRight().y){ - y += this.bounds.height()-(this.bounds.height()/(diffHeight||1)); - } - label.setX(x);label.setY(y); - return; - } - - switch (label.getEdgePosition()) { - case "starttop": - var angle = this._getAngle(this.dockers[0], this.dockers[1]); - var pos = this.dockers.first().bounds.center(); - - if (angle <= 90 || angle > 270) { - label.horizontalAlign("left"); - label.verticalAlign("bottom"); - label.x = pos.x + label.getOffsetTop(); - label.y = pos.y - label.getOffsetTop(); - label.rotate(360 - angle, pos); - } else { - label.horizontalAlign("right"); - label.verticalAlign("bottom"); - label.x = pos.x - label.getOffsetTop(); - label.y = pos.y - label.getOffsetTop(); - label.rotate(180 - angle, pos); - } - - break; - - case "startmiddle": - var angle = this._getAngle(this.dockers[0], this.dockers[1]); - var pos = this.dockers.first().bounds.center(); - - if (angle <= 90 || angle > 270) { - label.horizontalAlign("left"); - label.verticalAlign("bottom"); - label.x = pos.x + 2; - label.y = pos.y + 4; - label.rotate(360 - angle, pos); - } else { - label.horizontalAlign("right"); - label.verticalAlign("bottom"); - label.x = pos.x + 1; - label.y = pos.y + 4; - label.rotate(180 - angle, pos); - } - - break; - - case "startbottom": - var angle = this._getAngle(this.dockers[0], this.dockers[1]); - var pos = this.dockers.first().bounds.center(); - - if (angle <= 90 || angle > 270) { - label.horizontalAlign("left"); - label.verticalAlign("top"); - label.x = pos.x + label.getOffsetBottom(); - label.y = pos.y + label.getOffsetBottom(); - label.rotate(360 - angle, pos); - } else { - label.horizontalAlign("right"); - label.verticalAlign("top"); - label.x = pos.x - label.getOffsetBottom(); - label.y = pos.y + label.getOffsetBottom(); - label.rotate(180 - angle, pos); - } - - break; - case "midtop": - var numOfDockers = this.dockers.length; - if(numOfDockers%2 == 0) { - var angle = this._getAngle(this.dockers[numOfDockers/2-1], this.dockers[numOfDockers/2]) - var pos1 = this.dockers[numOfDockers/2-1].bounds.center(); - var pos2 = this.dockers[numOfDockers/2].bounds.center(); - var pos = {x:(pos1.x + pos2.x)/2.0, y:(pos1.y+pos2.y)/2.0}; - - label.horizontalAlign("center"); - label.verticalAlign("bottom"); - label.x = pos.x; - label.y = pos.y - label.getOffsetTop(); - - if (angle <= 90 || angle > 270) { - label.rotate(360 - angle, pos); - } else { - label.rotate(180 - angle, pos); - } - } else { - var index = parseInt(numOfDockers/2); - var angle = this._getAngle(this.dockers[index], this.dockers[index+1]) - var pos = this.dockers[index].bounds.center(); - - if (angle <= 90 || angle > 270) { - label.horizontalAlign("left"); - label.verticalAlign("bottom"); - label.x = pos.x + label.getOffsetTop(); - label.y = pos.y - label.getOffsetTop(); - label.rotate(360 - angle, pos); - } else { - label.horizontalAlign("right"); - label.verticalAlign("bottom"); - label.x = pos.x - label.getOffsetTop(); - label.y = pos.y - label.getOffsetTop(); - label.rotate(180 - angle, pos); - } - } - - break; - case "midbottom": - var numOfDockers = this.dockers.length; - if(numOfDockers%2 == 0) { - var angle = this._getAngle(this.dockers[numOfDockers/2-1], this.dockers[numOfDockers/2]) - var pos1 = this.dockers[numOfDockers/2-1].bounds.center(); - var pos2 = this.dockers[numOfDockers/2].bounds.center(); - var pos = {x:(pos1.x + pos2.x)/2.0, y:(pos1.y+pos2.y)/2.0}; - - label.horizontalAlign("center"); - label.verticalAlign("top"); - label.x = pos.x; - label.y = pos.y + label.getOffsetTop(); - - if (angle <= 90 || angle > 270) { - label.rotate(360 - angle, pos); - } else { - label.rotate(180 - angle, pos); - } - } else { - var index = parseInt(numOfDockers/2); - var angle = this._getAngle(this.dockers[index], this.dockers[index+1]) - var pos = this.dockers[index].bounds.center(); - - if (angle <= 90 || angle > 270) { - label.horizontalAlign("left"); - label.verticalAlign("top"); - label.x = pos.x + label.getOffsetBottom(); - label.y = pos.y + label.getOffsetBottom(); - label.rotate(360 - angle, pos); - } else { - label.horizontalAlign("right"); - label.verticalAlign("top"); - label.x = pos.x - label.getOffsetBottom(); - label.y = pos.y + label.getOffsetBottom(); - label.rotate(180 - angle, pos); - } - } - - break; - case "endtop": - var length = this.dockers.length; - var angle = this._getAngle(this.dockers[length-2], this.dockers[length-1]); - var pos = this.dockers.last().bounds.center(); - - if (angle <= 90 || angle > 270) { - label.horizontalAlign("right"); - label.verticalAlign("bottom"); - label.x = pos.x - label.getOffsetTop(); - label.y = pos.y - label.getOffsetTop(); - label.rotate(360 - angle, pos); - } else { - label.horizontalAlign("left"); - label.verticalAlign("bottom"); - label.x = pos.x + label.getOffsetTop(); - label.y = pos.y - label.getOffsetTop(); - label.rotate(180 - angle, pos); - } - - break; - case "endbottom": - var length = this.dockers.length; - var angle = this._getAngle(this.dockers[length-2], this.dockers[length-1]); - var pos = this.dockers.last().bounds.center(); - - if (angle <= 90 || angle > 270) { - label.horizontalAlign("right"); - label.verticalAlign("top"); - label.x = pos.x - label.getOffsetBottom(); - label.y = pos.y + label.getOffsetBottom(); - label.rotate(360 - angle, pos); - } else { - label.horizontalAlign("left"); - label.verticalAlign("top"); - label.x = pos.x + label.getOffsetBottom(); - label.y = pos.y + label.getOffsetBottom(); - label.rotate(180 - angle, pos); - } - - break; - } - }.bind(this)); - - this.children.each(function(value) { - if(value instanceof ORYX.Core.Node) { - this.calculatePositionOfAttachedChildNode.call(this, value); - } - }.bind(this)); - - this.refreshAttachedNodes(); - this.refresh(); - - this.isChanged = false; - this._dockerUpdated = false; - - this._oldBounds = this.bounds.clone(); - } - - - // IE10 specific fix, start and end-markes get left behind when moving path - var userAgent = navigator.userAgent; - if (navigator.appVersion.indexOf("MSIE 10") !== -1 || (userAgent.indexOf('Trident') !== -1 && userAgent.indexOf('rv:11') !== -1)) - { - this.node.parentNode.insertBefore(this.node, this.node); - } + this.offsetScroll = {x: this.scrollNode.scrollLeft, y: this.scrollNode.scrollTop}; + + // Register on Global Mouse-MOVE Event + document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.callbackMouseMove, false); + // Register on Global Mouse-UP Event + document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.callbackMouseUp, true); + + return; }, - - /** - * Moves a point to the upperLeft of a node's bounds. - * - * @param {point} point - * The point to move - * @param {ORYX.Core.Bounds} bounds - * The Bounds of the related noe - */ - movePointToUpperLeftOfNode: function(point, bounds) { - point.x -= bounds.width()/2; - point.y -= bounds.height()/2; - }, - - /** - * Refreshes the visual representation of edge's attached nodes. - */ - refreshAttachedNodes: function() { - this.attachedNodePositionData.values().each(function(nodeData) { - var startPoint = nodeData.segment.docker1.bounds.center(); - var endPoint = nodeData.segment.docker2.bounds.center(); - this.relativizePoint(startPoint); - this.relativizePoint(endPoint); - - var newNodePosition = new Object(); - - /* Calculate new x-coordinate */ - newNodePosition.x = startPoint.x - + nodeData.relativDistanceFromDocker1 - * (endPoint.x - startPoint.x); - - /* Calculate new y-coordinate */ - newNodePosition.y = startPoint.y - + nodeData.relativDistanceFromDocker1 - * (endPoint.y - startPoint.y); - - /* Convert new position to the upper left of the node */ - this.movePointToUpperLeftOfNode(newNodePosition, nodeData.node.bounds); - - /* Move node to its new position */ - nodeData.node.bounds.moveTo(newNodePosition); - nodeData.node._update(); - - }.bind(this)); - }, - - /** - * Calculates the position of an edge's child node. The node is placed on - * the path of the edge. - * - * @param {node} - * The node to calculate the new position - * @return {Point} - * The calculated upper left point of the node's shape. - */ - calculatePositionOfAttachedChildNode: function(node) { - /* Initialize position */ - var position = new Object(); - position.x = 0; - position.y = 0; - - /* Case: Node was just added */ - if(!this.attachedNodePositionData[node.getId()]) { - this.attachedNodePositionData[node.getId()] = new Object(); - this.attachedNodePositionData[node.getId()] - .relativDistanceFromDocker1 = 0; - this.attachedNodePositionData[node.getId()].node = node; - this.attachedNodePositionData[node.getId()].segment = new Object(); - this.findEdgeSegmentForNode(node); - } else if (node.isChanged) { - this.findEdgeSegmentForNode(node); - } - - - - }, - - /** - * Finds the appropriate edge segement for a node. - * The segment is choosen, which has the smallest distance to the node. - * - * @param {ORYX.Core.Node} node - * The concerning node - */ - findEdgeSegmentForNode: function(node) { - var length = this.dockers.length; - var smallestDistance = undefined; - - for(i=1;i 0) { + + // Get the position and the docker + var position = this.facade.eventCoordinates(event); + var docker = this.toMoveShapes[0].dockers[0]; + + + //Command-Pattern for dragging several Shapes + var dockCommand = ORYX.Core.Command.extend({ + construct: function (docker, position, newDockedShape, facade) { + this.docker = docker; + this.newPosition = position; + this.newDockedShape = newDockedShape; + this.newParent = newDockedShape.parent || facade.getCanvas(); + this.oldPosition = docker.parent.bounds.center(); + this.oldDockedShape = docker.getDockedShape(); + this.oldParent = docker.parent.parent || facade.getCanvas(); + this.facade = facade; + + if (this.oldDockedShape) { + this.oldPosition = docker.parent.absoluteBounds().center(); + } + + }, + execute: function () { + this.dock(this.newDockedShape, this.newParent, this.newPosition); + + // Raise Event for having the docked shape on top of the other shape + this.facade.raiseEvent({type: ORYX.CONFIG.EVENT_ARRANGEMENT_TOP, excludeCommand: true}) + }, + rollback: function () { + this.dock(this.oldDockedShape, this.oldParent, this.oldPosition); + }, + dock: function (toDockShape, parent, pos) { + // Add to the same parent Shape + parent.add(this.docker.parent) + + + // Set the Docker to the new Shape + this.docker.setDockedShape(undefined); + this.docker.bounds.centerMoveTo(pos) + this.docker.setDockedShape(toDockShape); + //this.docker.update(); + + this.facade.setSelection([this.docker.parent]); + this.facade.getCanvas().update(); + this.facade.updateSelection(); + + + } + }); + + // Instanziate the dockCommand + var commands = [new dockCommand(docker, position, this.containmentParentNode, this.facade)]; + this.facade.executeCommands(commands); + + + // Check if adding is allowed to the other Shape + } else if (this.isAddingAllowed) { + + + // Refresh all Shapes --> Set the new Bounds + this.refreshSelectedShapes(); + + } + + this.facade.updateSelection(); + + //this.currentShapes.each(function(shape) {shape.update()}) + // Raise Event: Dragging is finished + this.facade.raiseEvent({type: ORYX.CONFIG.EVENT_DRAGDROP_END}); } - - path.setAttributeNS(null, "d", d); - this._interactionPaths[index].setAttributeNS(null, "d", d); - - }).bind(this)); - - - /* move child shapes of an edge */ - if(this.getChildNodes().length > 0) { - var x = this.bounds.upperLeft().x; - var y = this.bounds.upperLeft().y; - - this.node.firstChild.childNodes[1].setAttributeNS(null, "transform", "translate(" + x + ", " + y + ")"); - } - + + if (this.vLine) + this.vLine.hide(); + if (this.hLine) + this.hLine.hide(); + } + + // Disable + this.dragEnable = false; + + + // UnRegister on Global Mouse-UP/-Move Event + document.documentElement.removeEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.callbackMouseUp, true); + document.documentElement.removeEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.callbackMouseMove, false); + + return; }, - + /** - * Calculate the Border Intersection Point between two points - * @param {PointA} - * @param {PointB} - */ - getIntersectionPoint: function(){ - - var length = Math.floor(this.dockers.length / 2) - - return ORYX.Core.Math.midPoint(this.dockers[length - 1].bounds.center(), this.dockers[length].bounds.center()) - }, - - /** - * Returns TRUE if the bounds is over the edge - * @param {Bounds} + * On Key Mouse Move * */ - isBoundsIncluded: function(bounds){ - var dockers = this.dockers, size = dockers.length; - return dockers.any(function(docker, i){ - if (i == size-1){ return false; } - var a = docker.bounds.center(); - var b = dockers[i+1].bounds.center(); - - return ORYX.Core.Math.isRectOverLine(a.x, a.y, b.x, b.y, bounds.a.x, bounds.a.y, bounds.b.x, bounds.b.y); - }); - }, - - /** - * Calculate if the point is inside the Shape - * @param {PointX} - * @param {PointY} - */ - isPointIncluded: function(pointX, pointY){ - - var isbetweenAB = this.absoluteBounds().isIncluded(pointX, pointY, - ORYX.CONFIG.OFFSET_EDGE_BOUNDS); - - var isPointIncluded = undefined; - - if (isbetweenAB && this.dockers.length > 0) { - - var i = 0; - var point1, point2; - - - do { - - point1 = this.dockers[i].bounds.center(); - point2 = this.dockers[++i].bounds.center(); - - isPointIncluded = ORYX.Core.Math.isPointInLine(pointX, pointY, - point1.x, point1.y, - point2.x, point2.y, - ORYX.CONFIG.OFFSET_EDGE_BOUNDS); - - } while (!isPointIncluded && i < this.dockers.length - 1) - - } - - return isPointIncluded; + handleMouseMove: function (event) { + // If dragging is not enabled, go return + if (!this.dragEnable) { + return + } + ; + // If Dragging is initialized + if (this.dragIntialized) { + // Raise Event: Drag will be started + this.facade.raiseEvent({type: ORYX.CONFIG.EVENT_DRAGDROP_START}); + this.dragIntialized = false; + + // And hide the resizers and the highlighting + this.resizerSE.hide(); + this.resizerNW.hide(); + + // if only edges are selected, containmentParentNode must be the canvas + this._onlyEdges = this.currentShapes.all(function (currentShape) { + return (currentShape instanceof ORYX.Core.Edge); + }); + + // Do method before Drag + this.beforeDrag(); + + this._currentUnderlyingNodes = []; + + } + + + // Calculate the new position + var position = { + x: Event.pointerX(event) - this.offSetPosition.x, + y: Event.pointerY(event) - this.offSetPosition.y + } + + position.x -= this.offsetScroll.x - this.scrollNode.scrollLeft; + position.y -= this.offsetScroll.y - this.scrollNode.scrollTop; + + // If not the Control-Key are pressed + var modifierKeyPressed = event.shiftKey || event.ctrlKey; + if (ORYX.CONFIG.GRID_ENABLED && !modifierKeyPressed) { + // Snap the current position to the nearest Snap-Point + position = this.snapToGrid(position); + } else { + if (this.vLine) + this.vLine.hide(); + if (this.hLine) + this.hLine.hide(); + } + + // Adjust the point by the zoom faktor + position.x /= this.faktorXY.x; + position.y /= this.faktorXY.y; + + // Set that the position is not lower than zero + position.x = Math.max(0, position.x) + position.y = Math.max(0, position.y) + + // Set that the position is not bigger than the canvas + var c = this.facade.getCanvas(); + position.x = Math.min(c.bounds.width() - this.dragBounds.width(), position.x) + position.y = Math.min(c.bounds.height() - this.dragBounds.height(), position.y) + + + // Drag this bounds + this.dragBounds.moveTo(position); + + // Update all selected shapes and the selection rectangle + //this.refreshSelectedShapes(); + this.resizeRectangle(this.dragBounds); + + this.isAttachingAllowed = false; + + //check, if a node can be added to the underlying node + var eventCoordinates = this.facade.eventCoordinates(event); + + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + var ua = navigator.userAgent; + if (ua.indexOf('MSIE') >= 0) { + //IE 10 and below + var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); + if (zoom !== 100) { + additionalIEZoom = zoom / 100 + } + } + } + + if (additionalIEZoom !== 1) { + eventCoordinates.x = eventCoordinates.x / additionalIEZoom; + eventCoordinates.y = eventCoordinates.y / additionalIEZoom; + } + + var underlyingNodes = $A(this.facade.getCanvas().getAbstractShapesAtPosition(eventCoordinates)); + + var checkIfAttachable = this.toMoveShapes.length == 1 && this.toMoveShapes[0] instanceof ORYX.Core.Node && this.toMoveShapes[0].dockers.length > 0 + checkIfAttachable = checkIfAttachable && underlyingNodes.length != 1 + + + if (!checkIfAttachable && + underlyingNodes.length === this._currentUnderlyingNodes.length && + underlyingNodes.all(function (node, index) { + return this._currentUnderlyingNodes[index] === node + }.bind(this))) { + + return + + } else if (this._onlyEdges) { + + this.isAddingAllowed = true; + this.containmentParentNode = this.facade.getCanvas(); + + } else { + + /* Check the containment and connection rules */ + var options = { + event: event, + underlyingNodes: underlyingNodes, + checkIfAttachable: checkIfAttachable + }; + this.checkRules(options); + + } + + this._currentUnderlyingNodes = underlyingNodes.reverse(); + + //visualize the containment result + if (this.isAttachingAllowed) { + + this.facade.raiseEvent({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, + highlightId: "dragdropresize.attached", + elements: [this.containmentParentNode], + style: ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE, + color: ORYX.CONFIG.SELECTION_VALID_COLOR + }); + + } else { + + this.facade.raiseEvent({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, + highlightId: "dragdropresize.attached" + }); + } + if (!this.isAttachingAllowed) { + if (this.isAddingAllowed) { + + this.facade.raiseEvent({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, + highlightId: "dragdropresize.contain", + elements: [this.containmentParentNode], + color: ORYX.CONFIG.SELECTION_VALID_COLOR + }); + + } else { + + this.facade.raiseEvent({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, + highlightId: "dragdropresize.contain", + elements: [this.containmentParentNode], + color: ORYX.CONFIG.SELECTION_INVALID_COLOR + }); + + } + } else { + this.facade.raiseEvent({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, + highlightId: "dragdropresize.contain" + }); + } + + // Stop the Event + //Event.stop(event); + return; }, - - + +// /** +// * Rollbacks the docked shape of an edge, if the edge is not movable. +// */ +// redockEdges: function() { +// this._undockedEdgesCommand.dockers.each(function(el){ +// el.docker.setDockedShape(el.dockedShape); +// el.docker.setReferencePoint(el.refPoint); +// }) +// }, + /** - * Calculate if the point is over an special offset area - * @param {Point} + * Checks the containment and connection rules for the selected shapes. */ - isPointOverOffset: function(){ - return false - }, - - /** - * Returns TRUE if the given node - * is a child node of the shapes node - * @param {Element} node - * @return {Boolean} - * - */ - containsNode: function(node){ - if (this._paths.include(node) || - this._interactionPaths.include(node)){ - return true; - } - return false; - }, - - /** - * Returns the angle of the line between two dockers - * (0 - 359.99999999) - */ - _getAngle: function(docker1, docker2) { - var p1 = docker1 instanceof ORYX.Core.Controls.Docker ? docker1.absoluteCenterXY() : docker1; - var p2 = docker2 instanceof ORYX.Core.Controls.Docker ? docker2.absoluteCenterXY() : docker2; - - return ORYX.Core.Math.getAngle(p1, p2); - }, - - alignDockers: function(){ - this._update(true); - - var firstPoint = this.dockers.first().bounds.center(); - var lastPoint = this.dockers.last().bounds.center(); - - var deltaX = lastPoint.x - firstPoint.x; - var deltaY = lastPoint.y - firstPoint.y; - - var numOfDockers = this.dockers.length - 1; - - this.dockers.each((function(docker, index){ - var part = index / numOfDockers; - docker.bounds.unregisterCallback(this._dockerChangedCallback); - docker.bounds.moveTo(firstPoint.x + part * deltaX, firstPoint.y + part * deltaY); - docker.bounds.registerCallback(this._dockerChangedCallback); + checkRules: function (options) { + var event = options.event; + var underlyingNodes = options.underlyingNodes; + var checkIfAttachable = options.checkIfAttachable; + var noEdges = options.noEdges; + + //get underlying node that is not the same than one of the currently selected shapes or + // a child of one of the selected shapes with the highest z Order. + // The result is a shape or the canvas + this.containmentParentNode = underlyingNodes.reverse().find((function (node) { + return (node instanceof ORYX.Core.Canvas) || + (((node instanceof ORYX.Core.Node) || ((node instanceof ORYX.Core.Edge) && !noEdges)) + && (!(this.currentShapes.member(node) || + this.currentShapes.any(function (shape) { + return (shape.children.length > 0 && shape.getChildNodes(true).member(node)); + })))); }).bind(this)); - - this._dockerChanged(); - }, - - add: function(shape){ - arguments.callee.$.add.apply(this, arguments); - - // If the new shape is a Docker which is not contained - if (shape instanceof ORYX.Core.Controls.Docker && this.dockers.include(shape)){ - // Add it to the dockers list ordered by paths - var pathArray = this._dockersByPath.values()[0]; - if (pathArray) { - pathArray.splice(this.dockers.indexOf(shape), 0, shape); - } - - /* Perform nessary adjustments on the edge's child shapes */ - this.handleChildShapesAfterAddDocker(shape); - } - }, - - /** - * Performs nessary adjustments on the edge's child shapes. - * - * @param {ORYX.Core.Controls.Docker} docker - * The added docker - */ - handleChildShapesAfterAddDocker: function(docker) { - /* Ensure type of Docker */ - if(!docker instanceof ORYX.Core.Controls.Docker) {return undefined;} - - var index = this.dockers.indexOf(docker); - if(!(0 < index && index < this.dockers.length - 1)) { - /* Exception: Expect added docker between first and last node of the edge */ - return undefined; - } - - /* Get child nodes concerning the segment of the new docker */ - var startDocker = this.dockers[index-1]; - var endDocker = this.dockers[index+1]; - - /* Adjust the position of edge's child nodes */ - var segmentElements = - this.getAttachedNodePositionDataForSegment(startDocker, endDocker); - - var lengthSegmentPart1 = ORYX.Core.Math.getDistancePointToPoint( - startDocker.bounds.center(), - docker.bounds.center()); - var lengthSegmentPart2 = ORYX.Core.Math.getDistancePointToPoint( - endDocker.bounds.center(), - docker.bounds.center()); - - if(!(lengthSegmentPart1 + lengthSegmentPart2)) {return;} - - var relativDockerPosition = lengthSegmentPart1 / (lengthSegmentPart1 + lengthSegmentPart2); - - segmentElements.each(function(nodePositionData) { - /* Assign child node to the new segment */ - if(nodePositionData.value.relativDistanceFromDocker1 < relativDockerPosition) { - /* Case: before added Docker */ - nodePositionData.value.segment.docker2 = docker; - nodePositionData.value.relativDistanceFromDocker1 = - nodePositionData.value.relativDistanceFromDocker1 / relativDockerPosition; - } else { - /* Case: after added Docker */ - nodePositionData.value.segment.docker1 = docker; - var newFullDistance = 1 - relativDockerPosition; - var relativPartOfSegment = - nodePositionData.value.relativDistanceFromDocker1 - - relativDockerPosition; - - nodePositionData.value.relativDistanceFromDocker1 = - relativPartOfSegment / newFullDistance; - - } - }) - - - // Update all labels reference points - this.getLabels().each(function(label){ - - var ref = label.getReferencePoint(); - if (!ref) { - return; - } - var index = this.dockers.indexOf(docker); - if (index >= ref.segment.fromIndex && index <= ref.segment.toIndex){ - - var segment = this.findSegment(ref.intersection); - if (!segment){ - // Choose whether the first of the last segment - segment.fromDocker = ref.segment.fromIndex >= (this.dockers.length/2) ? this.dockers[0] : this.dockers[this.dockers.length-2]; - segment.toDocker = this.dockers[this.dockers.indexOf(from)+1]; // The next one if the to docker - } - - var fromPosition = segment.fromDocker.bounds.center(), toPosition = segment.toDocker.bounds.center(); - - var intersection = ORYX.Core.Math.getPointOfIntersectionPointLine( - fromPosition, // P1 - Center of the first docker - toPosition, // P2 - Center of the second docker - ref.intersection, // P3 - Center of the label - true); - //var oldDistance = ORYX.Core.Math.getDistanceBetweenTwoPoints(ref.segment.fromPosition, ref.segment.toPosition, ref.intersection); - //intersection = ORYX.Core.Math.getPointBetweenTwoPoints(fromPosition, toPosition, isNaN(oldDistance) ? 0.5 : (lengthOld*oldDistance)/lengthNew); - - // Update the reference point - this.updateReferencePointOfLabel(label, intersection, segment.fromDocker, segment.toDocker, true); - } - }.bind(this)); - - /* Update attached nodes visual representation */ - this.refreshAttachedNodes(); - }, - - /** - * Returns elements from {@link attachedNodePositiondata} that match the - * segement defined by startDocker and endDocker. - * - * @param {ORYX.Core.Controls.Docker} startDocker - * The docker defining the begin of the segment. - * @param {ORYX.Core.Controls.Docker} endDocker - * The docker defining the begin of the segment. - * - * @return {Hash} attachedNodePositionData - * Child elements matching the segment - */ - getAttachedNodePositionDataForSegment: function(startDocker, endDocker) { - /* Ensure that the segment is defined correctly */ - if(!((startDocker instanceof ORYX.Core.Controls.Docker) - && (endDocker instanceof ORYX.Core.Controls.Docker))) { - return []; - } - - /* Get elements of the segment */ - var elementsOfSegment = - this.attachedNodePositionData.findAll(function(nodePositionData) { - return nodePositionData.value.segment.docker1 === startDocker && - nodePositionData.value.segment.docker2 === endDocker; - }); - - /* Return a Hash in each case */ - if(!elementsOfSegment) {return [];} - - return elementsOfSegment; - }, - - /** - * Removes an edge's child shape - */ - remove: function(shape) { - arguments.callee.$.remove.apply(this, arguments); - - if(this.attachedNodePositionData[shape.getId()]) { - delete this.attachedNodePositionData[shape.getId()]; - } - - /* Adjust child shapes if neccessary */ - if(shape instanceof ORYX.Core.Controls.Docker) { - this.handleChildShapesAfterRemoveDocker(shape); - } - }, - - updateReferencePointOfLabel: function(label, intersection, from, to, dirty){ - if (!label.getReferencePoint() || !label.isVisible) { - return; - } - - var ref = label.getReferencePoint(); - - // - if (ref.orientation && ref.orientation !== "ce"){ - var angle = this._getAngle(from, to); - if (ref.distance >= 0){ - if(angle == 0){ - label.horizontalAlign("left");//ref.orientation == "lr" ? "right" : "left"); - label.verticalAlign("bottom"); - } else if (angle > 0 && angle < 90){ - label.horizontalAlign("right"); - label.verticalAlign("bottom"); - } else if (angle == 90){ - label.horizontalAlign("right"); - label.verticalAlign("top");//ref.orientation == "lr" ? "bottom" : "top"); - } else if (angle > 90 && angle < 180){ - label.horizontalAlign("right"); - label.verticalAlign("top"); - } else if (angle == 180){ - label.horizontalAlign("left");//ref.orientation == "ur" ? "right" : "left"); - label.verticalAlign("top"); - } else if (angle > 180 && angle < 270){ - label.horizontalAlign("left"); - label.verticalAlign("top"); - } else if (angle == 270){ - label.horizontalAlign("left"); - label.verticalAlign("top");//ref.orientation == "ll" ? "bottom" : "top"); - } else if (angle > 270 && angle <= 360){ - label.horizontalAlign("left"); - label.verticalAlign("bottom"); - } - } else { - if(angle == 0){ - label.horizontalAlign("left");//ref.orientation == "ur" ? "right" : "left"); - label.verticalAlign("top"); - } else if (angle > 0 && angle < 90){ - label.horizontalAlign("left"); - label.verticalAlign("top"); - } else if (angle == 90){ - label.horizontalAlign("left"); - label.verticalAlign("top");//ref.orientation == "ll" ? "bottom" : "top"); - } else if (angle > 90 && angle < 180){ - label.horizontalAlign("left"); - label.verticalAlign("bottom"); - } else if (angle == 180){ - label.horizontalAlign("left");//ref.orientation == "lr" ? "right" : "left"); - label.verticalAlign("bottom"); - } else if (angle > 180 && angle < 270){ - label.horizontalAlign("right"); - label.verticalAlign("bottom"); - } else if (angle == 270){ - label.horizontalAlign("right"); - label.verticalAlign("top");//ref.orientation == "lr" ? "bottom" : "top"); - } else if (angle > 270 && angle <= 360){ - label.horizontalAlign("right"); - label.verticalAlign("top"); - } - } - ref.iorientation = ref.iorientation || ref.orientation; - ref.orientation = (label.verticalAlign()=="top"?"u":"l") + (label.horizontalAlign()=="left"?"l":"r"); - } - - label.setReferencePoint(jQuery.extend({},{ - intersection: intersection, - segment: { - from: from, - fromIndex: this.dockers.indexOf(from), - fromPosition: from.bounds.center(), - to: to, - toIndex: this.dockers.indexOf(to), - toPosition: to.bounds.center() - }, - dirty: dirty || false - },ref)) - }, - /** - * Adjusts the child shapes of an edges after a docker was removed. - * - * @param{ORYX.Core.Controls.Docker} docker - * The removed docker. - */ - handleChildShapesAfterRemoveDocker: function(docker) { - /* Ensure docker type */ - if(!(docker instanceof ORYX.Core.Controls.Docker)) {return;} - - this.attachedNodePositionData.each(function(nodePositionData) { - if(nodePositionData.value.segment.docker1 === docker) { - /* The new start of the segment is the predecessor of docker2. */ - var index = this.dockers.indexOf(nodePositionData.value.segment.docker2); - if(index == -1) {return;} - nodePositionData.value.segment.docker1 = this.dockers[index - 1]; - } - else if(nodePositionData.value.segment.docker2 === docker) { - /* The new end of the segment is the successor of docker1. */ - var index = this.dockers.indexOf(nodePositionData.value.segment.docker1); - if(index == -1) {return;} - nodePositionData.value.segment.docker2 = this.dockers[index + 1]; - } - }.bind(this)); - - // Update all labels reference points - this.getLabels().each(function(label){ - var ref = label.getReferencePoint(); - if (!ref) { - return; - } - var from = ref.segment.from; - var to = ref.segment.to; - - if (from !== docker && to !== docker){ - return; - } - - var segment = this.findSegment(ref.intersection); - if (!segment){ - from = segment.fromDocker; - to = segment.toDocker; - } else { - from = from === docker ? this.dockers[this.dockers.indexOf(to)-1] : from; - to = this.dockers[this.dockers.indexOf(from)+1]; - } + if (checkIfAttachable) { - var intersection = ORYX.Core.Math.getPointOfIntersectionPointLine(from.bounds.center(), to.bounds.center(), ref.intersection, true); - // Update the reference point - this.updateReferencePointOfLabel(label, intersection, from, to, true); - }.bind(this)); - - /* Update attached nodes visual representation */ - this.refreshAttachedNodes(); - }, - - /** - *@deprecated Use the .createDocker() Method and set the point via the bounds - */ - addDocker: function(position, exDocker){ - var lastDocker; - var result; - this._dockersByPath.any((function(pair){ - return pair.value.any((function(docker, index){ - if (!lastDocker) { - lastDocker = docker; - return false; - } - else { - var point1 = lastDocker.bounds.center(); - var point2 = docker.bounds.center(); - - var additionalIEZoom = 1; - if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { - var ua = navigator.userAgent; - if (ua.indexOf('MSIE') >= 0) { - //IE 10 and below - var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); - if (zoom !== 100) { - additionalIEZoom = zoom / 100 - } - } - } - - if (additionalIEZoom !== 1) { - position.x = position.x / additionalIEZoom; - position.y = position.y / additionalIEZoom; - } - - if (ORYX.Core.Math.isPointInLine(position.x, position.y, point1.x, point1.y, point2.x, point2.y, 10)) { - var path = this._paths.find(function(path){ - return path.id === pair.key; - }); - if (path) { - var allowAttr = path.getAttributeNS(NAMESPACE_ORYX, 'allowDockers'); - if (allowAttr && allowAttr.toLowerCase() === "no") { - return true; - } + this.isAttachingAllowed = this.facade.getRules().canConnect({ + sourceShape: this.containmentParentNode, + edgeShape: this.toMoveShapes[0], + targetShape: this.toMoveShapes[0] + }); + + if (this.isAttachingAllowed) { + var point = this.facade.eventCoordinates(event); + this.isAttachingAllowed = this.containmentParentNode.isPointOverOffset(point.x, point.y); + } + } + + if (!this.isAttachingAllowed) { + //check all selected shapes, if they can be added to containmentParentNode + this.isAddingAllowed = this.toMoveShapes.all((function (currentShape) { + if (currentShape instanceof ORYX.Core.Edge || + currentShape instanceof ORYX.Core.Controls.Docker || + this.containmentParentNode === currentShape.parent) { + return true; + } else if (this.containmentParentNode !== currentShape) { + + if (!(this.containmentParentNode instanceof ORYX.Core.Edge) || !noEdges) { + + if (this.facade.getRules().canContain({ + containingShape: this.containmentParentNode, + containedShape: currentShape + })) { + return true; } - - var newDocker = (exDocker) ? exDocker : this.createDocker(this.dockers.indexOf(lastDocker) + 1, position); - newDocker.bounds.centerMoveTo(position); - if(exDocker) - this.add(newDocker, this.dockers.indexOf(lastDocker) + 1); - result = newDocker; - return true; - } - else { - lastDocker = docker; - return false; } } + return false; }).bind(this)); - }).bind(this)); - return result; + } + + if (!this.isAttachingAllowed && !this.isAddingAllowed && + (this.containmentParentNode instanceof ORYX.Core.Edge)) { + options.noEdges = true; + options.underlyingNodes.reverse(); + this.checkRules(options); + } }, - - removeDocker: function(docker){ - if (this.dockers.length > 2 && !(this.dockers.first() === docker)) { - this._dockersByPath.any((function(pair){ - if (pair.value.member(docker)) { - if (docker === pair.value.last()) { - return true; - } - else { - this.remove(docker); - this._dockersByPath[pair.key] = pair.value.without(docker); - this.isChanged = true; - this._dockerChanged(); - return true; + + /** + * Redraw the selected Shapes. + * + */ + refreshSelectedShapes: function () { + // If the selection bounds not initialized, return + if (!this.dragBounds) { + return + } + + // Calculate the offset between the bounds and the old bounds + var upL = this.dragBounds.upperLeft(); + var oldUpL = this.oldDragBounds.upperLeft(); + var offset = { + x: upL.x - oldUpL.x, + y: upL.y - oldUpL.y + }; + + // Instanciate the dragCommand + var commands = [new ORYX.Core.Command.Move(this.toMoveShapes, offset, this.containmentParentNode, this.currentShapes, this)]; + // If the undocked edges command is setted, add this command + if (this._undockedEdgesCommand instanceof ORYX.Core.Command) { + commands.unshift(this._undockedEdgesCommand); + } + // Execute the commands + this.facade.executeCommands(commands); + + // copy the bounds to the old bounds + if (this.dragBounds) + this.oldDragBounds = this.dragBounds.clone(); + + }, + + /** + * Callback for Resize + * + */ + onResize: function (bounds) { + // If the selection bounds not initialized, return + if (!this.dragBounds) { + return + } + + this.dragBounds = bounds; + this.isResizing = true; + + // Update the rectangle + this.resizeRectangle(this.dragBounds); + }, + + onResizeStart: function () { + this.facade.raiseEvent({type: ORYX.CONFIG.EVENT_RESIZE_START}); + }, + + onResizeEnd: function () { + + if (!(this.currentShapes instanceof Array) || this.currentShapes.length <= 0) { + return; + } + + // If Resizing finished, the Shapes will be resize + if (this.isResizing) { + + var commandClass = ORYX.Core.Command.extend({ + construct: function (shape, newBounds, plugin) { + this.shape = shape; + this.oldBounds = shape.bounds.clone(); + this.newBounds = newBounds; + this.plugin = plugin; + }, + execute: function () { + this.shape.bounds.set(this.newBounds.a, this.newBounds.b); + this.update(this.getOffset(this.oldBounds, this.newBounds)); + + }, + rollback: function () { + this.shape.bounds.set(this.oldBounds.a, this.oldBounds.b); + this.update(this.getOffset(this.newBounds, this.oldBounds)) + }, + + getOffset: function (b1, b2) { + return { + x: b2.a.x - b1.a.x, + y: b2.a.y - b1.a.y, + xs: b2.width() / b1.width(), + ys: b2.height() / b1.height() } + }, + update: function (offset) { + this.shape.getLabels().each(function (label) { + label.changed(); + }); + + var allEdges = [].concat(this.shape.getIncomingShapes()) + .concat(this.shape.getOutgoingShapes()) + // Remove all edges which are included in the selection from the list + .findAll(function (r) { + return r instanceof ORYX.Core.Edge + }.bind(this)) + + this.plugin.layoutEdges(this.shape, allEdges, offset); + + this.plugin.facade.setSelection([this.shape]); + this.plugin.facade.getCanvas().update(); + this.plugin.facade.updateSelection(); } - return false; - }).bind(this)); + }); + + var bounds = this.dragBounds.clone(); + var shape = this.currentShapes[0]; + + if (shape.parent) { + var parentPosition = shape.parent.absoluteXY(); + bounds.moveBy(-parentPosition.x, -parentPosition.y); + } + + var command = new commandClass(shape, bounds, this); + + this.facade.executeCommands([command]); + + this.isResizing = false; + + this.facade.raiseEvent({type: ORYX.CONFIG.EVENT_RESIZE_END}); } }, - - /** - * Removes all dockers from the edge which are on - * the line between two dockers - * @return {Object} Removed dockers in an indicied array - * (key is the removed position of the docker, value is docker themselve) - */ - removeUnusedDockers:function(){ - var marked = $H({}); - - this.dockers.each(function(docker, i){ - if (i==0||i==this.dockers.length-1){ return } - var previous = this.dockers[i-1]; - - /* Do not consider already removed dockers */ - if(marked.values().indexOf(previous) != -1 && this.dockers[i-2]) { - previous = this.dockers[i-2]; - } - var next = this.dockers[i+1]; - - var cp = previous.getDockedShape() && previous.referencePoint ? previous.getAbsoluteReferencePoint() : previous.bounds.center(); - var cn = next.getDockedShape() && next.referencePoint ? next.getAbsoluteReferencePoint() : next.bounds.center(); - var cd = docker.bounds.center(); - - if (ORYX.Core.Math.isPointInLine(cd.x, cd.y, cp.x, cp.y, cn.x, cn.y, 1)){ - marked[i] = docker; - } - }.bind(this)) - - marked.each(function(docker){ - this.removeDocker(docker.value); - }.bind(this)) - - if (marked.values().length > 0){ - this._update(true); - } - - return marked; - }, - + + /** - * Initializes the Edge after loading the SVG representation of the edge. - * @param {SVGDocument} svgDocument + * Prepare the Dragging + * */ - _init: function(svgDocument){ - arguments.callee.$._init.apply(this, arguments); - - var minPointX, minPointY, maxPointX, maxPointY; - - //init markers - var defs = svgDocument.getElementsByTagNameNS(NAMESPACE_SVG, "defs"); - if (defs.length > 0) { - defs = defs[0]; - var markerElements = $A(defs.getElementsByTagNameNS(NAMESPACE_SVG, "marker")); - var marker; - var me = this; - markerElements.each(function(markerElement){ - try { - marker = new ORYX.Core.SVG.SVGMarker(markerElement.cloneNode(true)); - me._markers[marker.id] = marker; - var textElements = $A(marker.element.getElementsByTagNameNS(NAMESPACE_SVG, "text")); - var label; - textElements.each(function(textElement){ - label = new ORYX.Core.SVG.Label({ - textElement: textElement, - shapeId: this.id - }); - me._labels[label.id] = label; - }); - } - catch (e) { - } + beforeDrag: function () { + + var undockEdgeCommand = ORYX.Core.Command.extend({ + construct: function (moveShapes) { + this.dockers = moveShapes.collect(function (shape) { + return shape instanceof ORYX.Core.Controls.Docker ? { + docker: shape, + dockedShape: shape.getDockedShape(), + refPoint: shape.referencePoint + } : undefined + }).compact(); + }, + execute: function () { + this.dockers.each(function (el) { + el.docker.setDockedShape(undefined); + }) + }, + rollback: function () { + this.dockers.each(function (el) { + el.docker.setDockedShape(el.dockedShape); + el.docker.setReferencePoint(el.refPoint); + //el.docker.update(); + }) + } + }); + + this._undockedEdgesCommand = new undockEdgeCommand(this.toMoveShapes); + this._undockedEdgesCommand.execute(); + + }, + + hideAllLabels: function (shape) { + + // Hide all labels from the shape + shape.getLabels().each(function (label) { + label.hide(); + }); + // Hide all labels from docked shapes + shape.getAllDockedShapes().each(function (dockedShape) { + var labels = dockedShape.getLabels(); + if (labels.length > 0) { + labels.each(function (label) { + label.hide(); + }); + } + }); + + // Do this recursive for all child shapes + // EXP-NICO use getShapes + shape.getChildren().each((function (value) { + if (value instanceof ORYX.Core.Shape) + this.hideAllLabels(value); + }).bind(this)); + }, + + /** + * Finished the Dragging + * + */ + afterDrag: function () { + + }, + + /** + * Show all Labels at these shape + * + */ + showAllLabels: function (shape) { + + // Show the label of these shape + //shape.getLabels().each(function(label) { + for (var i = 0; i < shape.length; i++) { + var label = shape[i]; + label.show(); + }//); + // Show all labels at docked shapes + //shape.getAllDockedShapes().each(function(dockedShape) { + var allDockedShapes = shape.getAllDockedShapes() + for (var i = 0; i < allDockedShapes.length; i++) { + var dockedShape = allDockedShapes[i]; + var labels = dockedShape.getLabels(); + if (labels.length > 0) { + labels.each(function (label) { + label.show(); + }); + } + }//); + + // Do this recursive + //shape.children.each((function(value) { + for (var i = 0; i < shape.children.length; i++) { + var value = shape.children[i]; + if (value instanceof ORYX.Core.Shape) + this.showAllLabels(value); + }//).bind(this)); + }, + + /** + * Intialize Method, if there are new Plugins + * + */ + /*registryChanged: function(pluginsData) { + // Save all new Plugin, sorted by group and index + this.pluginsData = pluginsData.sortBy( function(value) { + return (value.group + "" + value.index); + }); + },*/ + + /** + * On the Selection-Changed + * + */ + onSelectionChanged: function (event) { + var elements = event.elements; + + // Reset the drag-variables + this.dragEnable = false; + this.dragIntialized = false; + this.resizerSE.hide(); + this.resizerNW.hide(); + + // If there is no elements + if (!elements || elements.length == 0) { + // Hide all things and reset all variables + this.selectedRect.hide(); + this.currentShapes = []; + this.toMoveShapes = []; + this.dragBounds = undefined; + this.oldDragBounds = undefined; + } else { + + // Set the current Shapes + this.currentShapes = elements; + + // Get all shapes with the highest parent in object hierarchy (canvas is the top most parent) + var topLevelElements = this.facade.getCanvas().getShapesWithSharedParent(elements); + this.toMoveShapes = topLevelElements; + + this.toMoveShapes = this.toMoveShapes.findAll(function (shape) { + return shape instanceof ORYX.Core.Node && + (shape.dockers.length === 0 || !elements.member(shape.dockers.first().getDockedShape())) }); - } - - - var gs = svgDocument.getElementsByTagNameNS(NAMESPACE_SVG, "g"); - if (gs.length <= 0) { - throw "Edge: No g element found."; - } - var g = gs[0]; - - - g.setAttributeNS(null, "id", null); - - var isFirst = true; - - $A(g.childNodes).each((function(path, index){ - if (ORYX.Editor.checkClassType(path, SVGPathElement)) { - path = path.cloneNode(false); - - var pathId = this.id + "_" + index; - path.setAttributeNS(null, "id", pathId); - this._paths.push(path); - - //check, if markers are set and update the id - var markersByThisPath = []; - var markerUrl = path.getAttributeNS(null, "marker-start"); - - if (markerUrl && markerUrl !== "") { - markerUrl = markerUrl.strip(); - markerUrl = markerUrl.replace(/^url\(#/, ''); - - var markerStartId = this.getValidMarkerId(markerUrl); - path.setAttributeNS(null, "marker-start", "url(#" + markerStartId + ")"); - - markersByThisPath.push(this._markers[markerStartId]); + + elements.each((function (shape) { + if (!(shape instanceof ORYX.Core.Edge)) { + return; } - - markerUrl = path.getAttributeNS(null, "marker-mid"); - - if (markerUrl && markerUrl !== "") { - markerUrl = markerUrl.strip(); - markerUrl = markerUrl.replace(/^url\(#/, ''); - var markerMidId = this.getValidMarkerId(markerUrl); - path.setAttributeNS(null, "marker-mid", "url(#" + markerMidId + ")"); - - markersByThisPath.push(this._markers[markerMidId]); + + var dks = shape.getDockers(); + + var hasF = elements.member(dks.first().getDockedShape()); + var hasL = elements.member(dks.last().getDockedShape()); + +// if(!hasL) { +// this.toMoveShapes.push(dks.last()); +// } +// if(!hasF){ +// this.toMoveShapes.push(dks.first()) +// } + /* Enable movement of undocked edges */ + if (!hasF && !hasL) { + var isUndocked = !dks.first().getDockedShape() && !dks.last().getDockedShape(); + if (isUndocked) { + this.toMoveShapes = this.toMoveShapes.concat(dks); + } } - - markerUrl = path.getAttributeNS(null, "marker-end"); - - if (markerUrl && markerUrl !== "") { - markerUrl = markerUrl.strip(); - - var markerEndId = this.getValidMarkerId(markerUrl); - path.setAttributeNS(null, "marker-end", "url(#" + markerEndId + ")"); - - markersByThisPath.push(this._markers[markerEndId]); + + if (shape.dockers.length > 2 && hasF && hasL) { + this.toMoveShapes = this.toMoveShapes.concat(dks.findAll(function (el, index) { + return index > 0 && index < dks.length - 1 + })); } - - this._markersByPath[pathId] = markersByThisPath; - - //init dockers - var parser = new PathParser(); - var handler = new ORYX.Core.SVG.PointsPathHandler(); - parser.setHandler(handler); - parser.parsePath(path); - - if (handler.points.length < 4) { - throw "Edge: Path has to have two or more points specified."; + + }).bind(this)); + + // Calculate the new area-bounds of the selection + var newBounds = undefined; + this.toMoveShapes.each(function (value) { + var shape = value; + if (value instanceof ORYX.Core.Controls.Docker) { + /* Get the Shape */ + shape = value.parent; } - - this._dockersByPath[pathId] = []; - - for (var i = 0; i < handler.points.length; i += 2) { - //handler.points.each((function(point, pIndex){ - var x = handler.points[i]; - var y = handler.points[i+1]; - if (isFirst || i > 0) { - var docker = new ORYX.Core.Controls.Docker({ - eventHandlerCallback: this.eventHandlerCallback - }); - docker.bounds.centerMoveTo(x,y); - docker.bounds.registerCallback(this._dockerChangedCallback); - this.add(docker, this.dockers.length); - - //this._dockersByPath[pathId].push(docker); - - //calculate minPoint and maxPoint - if (minPointX) { - minPointX = Math.min(x, minPointX); - minPointY = Math.min(y, minPointY); - } - else { - minPointX = x; - minPointY = y; - } - - if (maxPointX) { - maxPointX = Math.max(x, maxPointX); - maxPointY = Math.max(y, maxPointY); - } - else { - maxPointX = x; - maxPointY = y; - } - } - //}).bind(this)); - } - isFirst = false; + + if (!newBounds) { + newBounds = shape.absoluteBounds(); + } else { + newBounds.include(shape.absoluteBounds()); + } + }.bind(this)); + + if (!newBounds) { + elements.each(function (value) { + if (!newBounds) { + newBounds = value.absoluteBounds(); + } else { + newBounds.include(value.absoluteBounds()); + } + }); + } + + // Set the new bounds + this.dragBounds = newBounds; + this.oldDragBounds = newBounds.clone(); + + // Update and show the rectangle + this.resizeRectangle(newBounds); + this.selectedRect.show(); + + // Show the resize button, if there is only one element and this is resizeable + if (elements.length == 1 && elements[0].isResizable) { + var aspectRatio = elements[0].getStencil().fixedAspectRatio() ? elements[0].bounds.width() / elements[0].bounds.height() : undefined; + this.resizerSE.setBounds(this.dragBounds, elements[0].minimumSize, elements[0].maximumSize, aspectRatio); + this.resizerSE.show(); + this.resizerNW.setBounds(this.dragBounds, elements[0].minimumSize, elements[0].maximumSize, aspectRatio); + this.resizerNW.show(); + } else { + this.resizerSE.setBounds(undefined); + this.resizerNW.setBounds(undefined); + } + + // If Snap-To-Grid is enabled, the Snap-Point will be calculate + if (ORYX.CONFIG.GRID_ENABLED) { + + // Reset all points + this.distPoints = []; + + if (this.distPointTimeout) + window.clearTimeout(this.distPointTimeout) + + this.distPointTimeout = window.setTimeout(function () { + // Get all the shapes, there will consider at snapping + // Consider only those elements who shares the same parent element + var distShapes = this.facade.getCanvas().getChildShapes(true).findAll(function (value) { + var parentShape = value.parent; + while (parentShape) { + if (elements.member(parentShape)) return false; + parentShape = parentShape.parent + } + return true; + }) + + // The current selection will delete from this array + //elements.each(function(shape) { + // distShapes = distShapes.without(shape); + //}); + + // For all these shapes + distShapes.each((function (value) { + if (!(value instanceof ORYX.Core.Edge)) { + var ul = value.absoluteXY(); + var width = value.bounds.width(); + var height = value.bounds.height(); + + // Add the upperLeft, center and lowerRight - Point to the distancePoints + this.distPoints.push({ + ul: { + x: ul.x, + y: ul.y + }, + c: { + x: ul.x + (width / 2), + y: ul.y + (height / 2) + }, + lr: { + x: ul.x + width, + y: ul.y + height + } + }); + } + }).bind(this)); + + }.bind(this), 10) + + } - }).bind(this)); - - this.bounds.set(minPointX, minPointY, maxPointX, maxPointY); - - if (false&&(this.bounds.width() === 0 || this.bounds.height() === 0)) { - var width = this.bounds.width(); - var height = this.bounds.height(); - - this.bounds.extend({ - x: width === 0 ? 2 : 0, - y: height === 0 ? 2 : 0 - }); - - this.bounds.moveBy({ - x: width === 0 ? -1 : 0, - y: height === 0 ? -1 : 0 - }); - } - - this._oldBounds = this.bounds.clone(); - - //add paths to this.node - this._paths.reverse(); - var paths = []; - this._paths.each((function(path){ - paths.push(this.node.childNodes[0].childNodes[0].childNodes[0].appendChild(path)); - }).bind(this)); - - this._paths = paths; - - //init interaction path - this._paths.each((function(path){ - var iPath = path.cloneNode(false); - iPath.setAttributeNS(null, "id", undefined); - iPath.setAttributeNS(null, "stroke-width", 10); - iPath.setAttributeNS(null, "visibility", "hidden"); - iPath.setAttributeNS(null, "stroke-dasharray", null); - iPath.setAttributeNS(null, "stroke", "black"); - iPath.setAttributeNS(null, "fill", "none"); - iPath.setAttributeNS(null, "title", this.getStencil().title()); - this._interactionPaths.push(this.node.childNodes[0].childNodes[0].childNodes[0].appendChild(iPath)); - }).bind(this)); - - this._paths.reverse(); - this._interactionPaths.reverse(); - - /**initialize labels*/ - var textElems = svgDocument.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'text'); - - $A(textElems).each((function(textElem){ - var label = new ORYX.Core.SVG.Label({ - textElement: textElem, - shapeId: this.id - }); - this.node.childNodes[0].childNodes[0].appendChild(label.node); - this._labels[label.id] = label; - - label.registerOnChange(this.layout.bind(this)); - }).bind(this)); - - - this.propertiesChanged.each(function(pair){ - pair.value = true; - }); - - - //if(this.dockers.length == 2) { - - - - // } - - //this._update(true); - }, - - getValidMarkerId: function(markerUrl) { - if(markerUrl.indexOf("url(\"#") >= 0) { - // Fix for IE9, additional quotes are added to the 0) { - defs = defs[0]; - this._markers.each(function(marker){ - var foundMarker = defs.ownerDocument.getElementById(marker.value.id); - if (foundMarker) { - marker.value.element = defs.removeChild(marker.value.element); - } - }); - } + + + if (offsetX !== undefined) { + ul.x += offsetX; + ul.x *= scale; + if (this.vLine && gridX) + this.vLine.update(gridX); + } else { + ul.x = (position.x - (position.x % (ORYX.CONFIG.GRID_DISTANCE / 2))); + if (this.vLine) + this.vLine.hide() } + + if (offsetY !== undefined) { + ul.y += offsetY; + ul.y *= scale; + if (this.hLine && gridY) + this.hLine.update(gridY); + } else { + ul.y = (position.y - (position.y % (ORYX.CONFIG.GRID_DISTANCE / 2))); + if (this.hLine) + this.hLine.hide(); + } + + return ul; }, - + + showGridLine: function () { + + }, + + /** - * Calls when a docker has changed + * Redraw of the Rectangle of the SelectedArea + * @param {Object} bounds */ - _dockerChanged: function(){ - - //this._update(true); - this._dockerUpdated = true; - + resizeRectangle: function (bounds) { + // Resize the Rectangle + this.selectedRect.resize(bounds); + } + +}); + + +ORYX.Plugins.SelectedRect = Clazz.extend({ + + construct: function (parentId) { + + this.parentId = parentId; + + this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", $(parentId), + ['g']); + + this.dashedArea = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.node, + ['rect', { + x: 0, y: 0, + 'stroke-width': 1, stroke: '#777777', fill: 'none', + 'stroke-dasharray': '2,2', + 'pointer-events': 'none' + }]); + + this.hide(); + }, - - serialize: function(){ - var result = arguments.callee.$.serialize.apply(this); - - //add dockers triple - var value = ""; - this._dockersByPath.each((function(pair){ - pair.value.each(function(docker){ - var position = docker.getDockedShape() && docker.referencePoint ? docker.referencePoint : docker.bounds.center(); - value = value.concat(position.x + " " + position.y + " "); - }); - - value += " # "; - }).bind(this)); - result.push({ - name: 'dockers', - prefix: 'oryx', - value: value, - type: 'literal' - }); - - //add parent triple dependant on the dockedShapes - //TODO change this when canvas becomes a resource -/* var source = this.dockers.first().getDockedShape(); - var target = this.dockers.last().getDockedShape(); - var sharedParent; - if (source && target) { - //get shared parent - while (source.parent) { - source = source.parent; - if (source instanceof ORYX.Core.Canvas) { - sharedParent = source; - break; - } - else { - var targetParent = target.parent; - var found; - while (targetParent) { - if (source === targetParent) { - sharedParent = source; - found = true; - break; - } - else { - targetParent = targetParent.parent; - } - } - if (found) { - break; - } - } - } + + hide: function () { + this.node.setAttributeNS(null, 'display', 'none'); + }, + + show: function () { + this.node.setAttributeNS(null, 'display', ''); + }, + + resize: function (bounds) { + var upL = bounds.upperLeft(); + + var padding = ORYX.CONFIG.SELECTED_AREA_PADDING; + + this.dashedArea.setAttributeNS(null, 'width', bounds.width() + 2 * padding); + this.dashedArea.setAttributeNS(null, 'height', bounds.height() + 2 * padding); + this.node.setAttributeNS(null, 'transform', "translate(" + (upL.x - padding) + ", " + (upL.y - padding) + ")"); + } + + +}); + + +ORYX.Plugins.GridLine = Clazz.extend({ + + construct: function (parentId, direction) { + + if (ORYX.Plugins.GridLine.DIR_HORIZONTAL !== direction && ORYX.Plugins.GridLine.DIR_VERTICAL !== direction) { + direction = ORYX.Plugins.GridLine.DIR_HORIZONTAL } - else - if (source) { - sharedParent = source.parent; - } - else - if (target) { - sharedParent = target.parent; - } -*/ - //if (sharedParent) { -/* result.push({ - name: 'parent', - prefix: 'raziel', - //value: '#' + ERDF.__stripHashes(sharedParent.resourceId), - value: '#' + ERDF.__stripHashes(this.getCanvas().resourceId), - type: 'resource' - });*/ - //} - - //serialize target and source - var lastDocker = this.dockers.last(); - - var target = lastDocker.getDockedShape(); - - if(target) { - result.push({ - name: 'target', - prefix: 'raziel', - value: '#' + ERDF.__stripHashes(target.resourceId), - type: 'resource' - }); - } - + + + this.parent = $(parentId); + this.direction = direction; + this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.parent, + ['g']); + + this.line = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.node, + ['path', { + 'stroke-width': 1, stroke: 'silver', fill: 'none', + 'stroke-dasharray': '5,5', + 'pointer-events': 'none' + }]); + + this.hide(); + + }, + + hide: function () { + this.node.setAttributeNS(null, 'display', 'none'); + }, + + show: function () { + this.node.setAttributeNS(null, 'display', ''); + }, + + getScale: function () { try { - //result = this.getStencil().serialize(this, result); - var serializeEvent = this.getStencil().serialize(); - - /* - * call serialize callback by reference, result should be found - * in serializeEvent.result - */ - if(serializeEvent.type) { - serializeEvent.shape = this; - serializeEvent.data = result; - serializeEvent.result = undefined; - serializeEvent.forceExecution = true; - - this._delegateEvent(serializeEvent); - - if(serializeEvent.result) { - result = serializeEvent.result; - } - } - } - catch (e) { + return this.parent.parentNode.transform.baseVal.getItem(0).matrix.a; + } catch (e) { + return 1; } - return result; }, - - deserialize: function(data) { - try { - //data = this.getStencil().deserialize(this, data); - - var deserializeEvent = this.getStencil().deserialize(); - - /* - * call serialize callback by reference, result should be found - * in serializeEventInfo.result - */ - if(deserializeEvent.type) { - deserializeEvent.shape = this; - deserializeEvent.data = data; - deserializeEvent.result = undefined; - deserializeEvent.forceExecution = true; - - this._delegateEvent(deserializeEvent); - if(deserializeEvent.result) { - data = deserializeEvent.result; - } - } - } - catch (e) { - } - - // Set the outgoing shapes - var target = data.find(function(ser) {return (ser.prefix+"-"+ser.name) == 'raziel-target'}); - var targetShape; - if(target) { - targetShape = this.getCanvas().getChildShapeByResourceId(target.value); - } - - var outgoing = data.findAll(function(ser){ return (ser.prefix+"-"+ser.name) == 'raziel-outgoing'}); - outgoing.each((function(obj){ - // TODO: Look at Canvas - if(!this.parent) {return}; - - // Set outgoing Shape - var next = this.getCanvas().getChildShapeByResourceId(obj.value); - - if(next){ - if(next == targetShape) { - // If this is an edge, set the last docker to the next shape - this.dockers.last().setDockedShape(next); - this.dockers.last().setReferencePoint({x: next.bounds.width() / 2.0, y: next.bounds.height() / 2.0}); - } else if(next instanceof ORYX.Core.Edge) { - //Set the first docker of the next shape - next.dockers.first().setDockedShape(this); - //next.dockers.first().setReferencePoint({x: this.bounds.width() / 2.0, y: this.bounds.height() / 2.0}); - } /*else if(next.dockers.length > 0) { //next is a node and next has a docker - next.dockers.first().setDockedShape(this); - next.dockers.first().setReferencePoint({x: this.bounds.width() / 2.0, y: this.bounds.height() / 2.0}); - }*/ - } - - }).bind(this)); - - - var oryxDockers = data.find(function(obj){ - return (obj.prefix === "oryx" && - obj.name === "dockers"); - }); - - if (oryxDockers) { - var dataByPath = oryxDockers.value.split("#").without("").without(" "); - - dataByPath.each((function(data, index){ - var values = data.replace(/,/g, " ").split(" ").without(""); - - //for each docker two values must be defined - if (values.length % 2 === 0) { - var path = this._paths[index]; - - if (path) { - if (index === 0) { - while (this._dockersByPath[path.id].length > 2) { - this.removeDocker(this._dockersByPath[path.id][1]); - } - } - else { - while (this._dockersByPath[path.id].length > 1) { - this.removeDocker(this._dockersByPath[path.id][0]); - } - } - - var dockersByPath = this._dockersByPath[path.id]; - - if (index === 0) { - //set position of first docker - var x = parseFloat(values.shift()); - var y = parseFloat(values.shift()); - - if (dockersByPath.first().getDockedShape()) { - dockersByPath.first().setReferencePoint({ - x: x, - y: y - }); - } - else { - dockersByPath.first().bounds.centerMoveTo(x, y); - } - } - - //set position of last docker - y = parseFloat(values.pop()); - x = parseFloat(values.pop()); - - if (dockersByPath.last().getDockedShape()) { - dockersByPath.last().setReferencePoint({ - x: x, - y: y - }); - } else { - dockersByPath.last().bounds.centerMoveTo(x, y); - } - - //add additional dockers - for (var i = 0; i < values.length; i++) { - x = parseFloat(values[i]); - y = parseFloat(values[++i]); - - var newDocker = this.createDocker(); - newDocker.bounds.centerMoveTo(x, y); - - //this.dockers = this.dockers.without(newDocker); - //this.dockers.splice(this.dockers.indexOf(dockersByPath.last()), 0, newDocker); - //dockersByPath.splice(this.dockers.indexOf(dockersByPath.last()), 0, newDocker); - } - } - } - }).bind(this)); + + update: function (pos) { + + if (this.direction === ORYX.Plugins.GridLine.DIR_HORIZONTAL) { + var y = pos instanceof Object ? pos.y : pos; + var cWidth = this.parent.parentNode.parentNode.width.baseVal.value / this.getScale(); + this.line.setAttributeNS(null, 'd', 'M 0 ' + y + ' L ' + cWidth + ' ' + y); } else { - this.alignDockers(); + var x = pos instanceof Object ? pos.x : pos; + var cHeight = this.parent.parentNode.parentNode.height.baseVal.value / this.getScale(); + this.line.setAttributeNS(null, 'd', 'M' + x + ' 0 L ' + x + ' ' + cHeight); + } + + this.show(); + } + + +}); + +ORYX.Plugins.GridLine.DIR_HORIZONTAL = "hor"; +ORYX.Plugins.GridLine.DIR_VERTICAL = "ver"; + +ORYX.Plugins.Resizer = Clazz.extend({ + + construct: function (parentId, orientation, facade) { + + this.parentId = parentId; + this.orientation = orientation; + this.facade = facade; + + this.node = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", $('canvasSection'), + ['div', {'class': 'resizer_' + this.orientation, style: 'left:0px; top:0px;position:absolute;'}]); + + this.node.addEventListener(ORYX.CONFIG.EVENT_MOUSEDOWN, this.handleMouseDown.bind(this), true); + document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.handleMouseUp.bind(this), true); + document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.handleMouseMove.bind(this), false); + + this.dragEnable = false; + this.offSetPosition = {x: 0, y: 0}; + this.bounds = undefined; + + this.canvasNode = this.facade.getCanvas().node; + + this.minSize = undefined; + this.maxSize = undefined; + + this.aspectRatio = undefined; + + this.resizeCallbacks = []; + this.resizeStartCallbacks = []; + this.resizeEndCallbacks = []; + this.hide(); + + // Calculate the Offset + this.scrollNode = this.node.parentNode.parentNode.parentNode; + + }, + + handleMouseDown: function (event) { + this.dragEnable = true; + + this.offsetScroll = {x: this.scrollNode.scrollLeft, y: this.scrollNode.scrollTop}; + + this.offSetPosition = { + x: Event.pointerX(event) - this.position.x, + y: Event.pointerY(event) - this.position.y + }; + + this.resizeStartCallbacks.each((function (value) { + value(this.bounds); + }).bind(this)); + + }, + + handleMouseUp: function (event) { + this.dragEnable = false; + this.containmentParentNode = null; + this.resizeEndCallbacks.each((function (value) { + value(this.bounds); + }).bind(this)); + + }, + + handleMouseMove: function (event) { + if (!this.dragEnable) { + return + } + + if (event.shiftKey || event.ctrlKey) { + this.aspectRatio = this.bounds.width() / this.bounds.height(); + } else { + this.aspectRatio = undefined; + } + + var position = { + x: Event.pointerX(event) - this.offSetPosition.x, + y: Event.pointerY(event) - this.offSetPosition.y + }; + + + position.x -= this.offsetScroll.x - this.scrollNode.scrollLeft; + position.y -= this.offsetScroll.y - this.scrollNode.scrollTop; + + position.x = Math.min(position.x, this.facade.getCanvas().bounds.width()); + position.y = Math.min(position.y, this.facade.getCanvas().bounds.height()); + + var offset = { + x: position.x - this.position.x, + y: position.y - this.position.y + }; + + if (this.aspectRatio) { + // fixed aspect ratio + newAspectRatio = (this.bounds.width() + offset.x) / (this.bounds.height() + offset.y); + if (newAspectRatio > this.aspectRatio) { + offset.x = this.aspectRatio * (this.bounds.height() + offset.y) - this.bounds.width(); + } else if (newAspectRatio < this.aspectRatio) { + offset.y = (this.bounds.width() + offset.x) / this.aspectRatio - this.bounds.height(); + } } - - arguments.callee.$.deserialize.apply(this, arguments); - - this._changed(); + + // respect minimum and maximum sizes of stencil + if (this.orientation === "northwest") { + + if (this.bounds.width() - offset.x > this.maxSize.width) { + offset.x = -(this.maxSize.width - this.bounds.width()); + if (this.aspectRatio) + offset.y = this.aspectRatio * offset.x; + } + if (this.bounds.width() - offset.x < this.minSize.width) { + offset.x = -(this.minSize.width - this.bounds.width()); + if (this.aspectRatio) + offset.y = this.aspectRatio * offset.x; + } + if (this.bounds.height() - offset.y > this.maxSize.height) { + offset.y = -(this.maxSize.height - this.bounds.height()); + if (this.aspectRatio) + offset.x = offset.y / this.aspectRatio; + } + if (this.bounds.height() - offset.y < this.minSize.height) { + offset.y = -(this.minSize.height - this.bounds.height()); + if (this.aspectRatio) + offset.x = offset.y / this.aspectRatio; + } + + } else { // defaults to southeast + if (this.bounds.width() + offset.x > this.maxSize.width) { + offset.x = this.maxSize.width - this.bounds.width(); + if (this.aspectRatio) + offset.y = this.aspectRatio * offset.x; + } + if (this.bounds.width() + offset.x < this.minSize.width) { + offset.x = this.minSize.width - this.bounds.width(); + if (this.aspectRatio) + offset.y = this.aspectRatio * offset.x; + } + if (this.bounds.height() + offset.y > this.maxSize.height) { + offset.y = this.maxSize.height - this.bounds.height(); + if (this.aspectRatio) + offset.x = offset.y / this.aspectRatio; + } + if (this.bounds.height() + offset.y < this.minSize.height) { + offset.y = this.minSize.height - this.bounds.height(); + if (this.aspectRatio) + offset.x = offset.y / this.aspectRatio; + } + } + + if (this.orientation === "northwest") { + this.bounds.extend({x: -offset.x, y: -offset.y}); + this.bounds.moveBy(offset); + } else { // defaults to southeast + this.bounds.extend(offset); + } + + this.update(); + + this.resizeCallbacks.each((function (value) { + value(this.bounds); + }).bind(this)); + + Event.stop(event); + }, - - toString: function(){ - return this.getStencil().title() + " " + this.id; + + registerOnResizeStart: function (callback) { + if (!this.resizeStartCallbacks.member(callback)) { + this.resizeStartCallbacks.push(callback); + } }, - - /** - * @return {ORYX.Core.Shape} Returns last docked shape or null. - */ - getTarget: function(){ - return this.dockers.last() ? this.dockers.last().getDockedShape() : null; + + unregisterOnResizeStart: function (callback) { + if (this.resizeStartCallbacks.member(callback)) { + this.resizeStartCallbacks = this.resizeStartCallbacks.without(callback); + } }, - - /** - * @return {ORYX.Core.Shape} Returns the first docked shape or null - */ - getSource: function() { - return this.dockers.first() ? this.dockers.first().getDockedShape() : null; - }, - - /** - * Checks whether the edge is at least docked to one shape. - * - * @return {boolean} True if edge is docked - */ - isDocked: function() { - var isDocked = false; - this.dockers.each(function(docker) { - if(docker.isDocked()) { - isDocked = true; - throw $break; - } - }); - return isDocked; - }, - - /** - * Calls {@link ORYX.Core.AbstractShape#toJSON} and add a some stencil set information. - */ - toJSON: function() { - var json = arguments.callee.$.toJSON.apply(this, arguments); - - if(this.getTarget()) { - json.target = { - resourceId: this.getTarget().resourceId - }; + + registerOnResizeEnd: function (callback) { + if (!this.resizeEndCallbacks.member(callback)) { + this.resizeEndCallbacks.push(callback); } - - return json; - } -}; -ORYX.Core.Edge = ORYX.Core.Shape.extend(ORYX.Core.Edge); -/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + }, -if(!ORYX){ var ORYX = {} } -if(!ORYX.Plugins){ ORYX.Plugins = {} } + unregisterOnResizeEnd: function (callback) { + if (this.resizeEndCallbacks.member(callback)) { + this.resizeEndCallbacks = this.resizeEndCallbacks.without(callback); + } + }, -/** - This abstract plugin class can be used to build plugins on. - It provides some more basic functionality like registering events (on*-handlers)... - @example - ORYX.Plugins.MyPlugin = ORYX.Plugins.AbstractPlugin.extend({ - construct: function() { - // Call super class constructor - arguments.callee.$.construct.apply(this, arguments); - - [...] - }, - [...] - }); - - @class ORYX.Plugins.AbstractPlugin - @constructor Creates a new instance - @author Willi Tscheschner -*/ -ORYX.Plugins.AbstractPlugin = Clazz.extend({ - /** - * The facade which offer editor-specific functionality - * @type Facade - * @memberOf ORYX.Plugins.AbstractPlugin.prototype - */ - facade: null, - - construct: function( facade ){ - this.facade = facade; - - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADED, this.onLoaded.bind(this)); - }, - - /** - Overwrite to handle load event. TODO: Document params!!! - @methodOf ORYX.Plugins.AbstractPlugin.prototype - */ - onLoaded: function(){}, - - /** - Overwrite to handle selection changed event. TODO: Document params!!! - @methodOf ORYX.Plugins.AbstractPlugin.prototype - */ - onSelectionChanged: function(){}, - - /** - Show overlay on given shape. - @methodOf ORYX.Plugins.AbstractPlugin.prototype - @example - showOverlay( - myShape, - { stroke: "green" }, - ORYX.Editor.graft("http://www.w3.org/2000/svg", null, ['path', { - "title": "Click the element to execute it!", - "stroke-width": 2.0, - "stroke": "black", - "d": "M0,-5 L5,0 L0,5 Z", - "line-captions": "round" - }]) - ) - @param {Oryx.XXX.Shape[]} shapes One shape or array of shapes the overlay should be put on - @param {Oryx.XXX.Attributes} attributes some attributes... - @param {Oryx.svg.node} svgNode The svg node which should be used as overlay - @param {String} [svgNode="NW"] The svg node position where the overlay should be placed - */ - showOverlay: function(shapes, attributes, svgNode, svgNodePosition ){ - - if( !(shapes instanceof Array) ){ - shapes = [shapes] - } - - // Define Shapes - shapes = shapes.map(function(shape){ - var el = shape; - if( typeof shape == "string" ){ - el = this.facade.getCanvas().getChildShapeByResourceId( shape ); - el = el || this.facade.getCanvas().getChildById( shape, true ); - } - return el; - }.bind(this)).compact(); - - // Define unified id - if( !this.overlayID ){ - this.overlayID = this.type + ORYX.Editor.provideId(); - } - - this.facade.raiseEvent({ - type : ORYX.CONFIG.EVENT_OVERLAY_SHOW, - id : this.overlayID, - shapes : shapes, - attributes : attributes, - node : svgNode, - nodePosition: svgNodePosition || "NW" - }); - - }, - - /** - Hide current overlay. - @methodOf ORYX.Plugins.AbstractPlugin.prototype - */ - hideOverlay: function(){ - this.facade.raiseEvent({ - type : ORYX.CONFIG.EVENT_OVERLAY_HIDE, - id : this.overlayID - }); - }, - - /** - Does a transformation with the given xslt stylesheet. - @methodOf ORYX.Plugins.AbstractPlugin.prototype - @param {String} data The data (e.g. eRDF) which should be transformed - @param {String} stylesheet URL of a stylesheet which should be used for transforming data. - */ - doTransform: function( data, stylesheet ) { - - if( !stylesheet || !data ){ - return "" - } + registerOnResize: function (callback) { + if (!this.resizeCallbacks.member(callback)) { + this.resizeCallbacks.push(callback); + } + }, - var parser = new DOMParser(); - var parsedData = parser.parseFromString(data, "text/xml"); - source=stylesheet; - new Ajax.Request(source, { - asynchronous: false, - method: 'get', - onSuccess: function(transport){ - xsl = transport.responseText - }.bind(this), - onFailure: (function(transport){ - ORYX.Log.error("XSL load failed" + transport); - }).bind(this) - }); - var xsltProcessor = new XSLTProcessor(); - var domParser = new DOMParser(); - var xslObject = domParser.parseFromString(xsl, "text/xml"); - xsltProcessor.importStylesheet(xslObject); - - try { - - var newData = xsltProcessor.transformToFragment(parsedData, document); - var serializedData = (new XMLSerializer()).serializeToString(newData); - - /* Firefox 2 to 3 problem?! */ - serializedData = !serializedData.startsWith("" + serializedData : serializedData; - - return serializedData; - - }catch (error) { - return -1; + unregisterOnResize: function (callback) { + if (this.resizeCallbacks.member(callback)) { + this.resizeCallbacks = this.resizeCallbacks.without(callback); } - - }, - - /** - * Opens a new window that shows the given XML content. - * @methodOf ORYX.Plugins.AbstractPlugin.prototype - * @param {Object} content The XML content to be shown. - * @example - * openDownloadWindow( "my.xml", "" ); - */ - openXMLWindow: function(content) { - var win = window.open( - 'data:application/xml,' + encodeURIComponent( - content - ), - '_blank', "resizable=yes,width=600,height=600,toolbar=0,scrollbars=yes" - ); - }, - - /** - * Opens a download window for downloading the given content. - * @methodOf ORYX.Plugins.AbstractPlugin.prototype - * @param {String} filename The content's file name - * @param {String} content The content to download - */ - openDownloadWindow: function(filename, content) { - var win = window.open(""); - if (win != null) { - win.document.open(); - win.document.write(""); - var submitForm = win.document.createElement("form"); - win.document.body.appendChild(submitForm); - - var createHiddenElement = function(name, value) { - var newElement = document.createElement("input"); - newElement.name=name; - newElement.type="hidden"; - newElement.value = value; - return newElement - } - - submitForm.appendChild( createHiddenElement("download", content) ); - submitForm.appendChild( createHiddenElement("file", filename) ); - - - submitForm.method = "POST"; - win.document.write(""); - win.document.close(); - submitForm.action= ORYX.PATH + "/download"; - submitForm.submit(); - } - }, - - /** - * Serializes DOM. - * @methodOf ORYX.Plugins.AbstractPlugin.prototype - * @type {String} Serialized DOM - */ - getSerializedDOM: function(){ - // Force to set all resource IDs - var serializedDOM = DataManager.serializeDOM( this.facade ); + }, - //add namespaces - serializedDOM = '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - serializedDOM + - ''; - - return serializedDOM; + hide: function () { + this.node.style.display = "none"; }, - - /** - * Sets the editor in read only mode: Edges/ dockers cannot be moved anymore, - * shapes cannot be selected anymore. - * @methodOf ORYX.Plugins.AbstractPlugin.prototype - */ - enableReadOnlyMode: function(){ - //Edges cannot be moved anymore - this.facade.disableEvent(ORYX.CONFIG.EVENT_MOUSEDOWN); - - // Stop the user from editing the diagram while the plugin is active - this._stopSelectionChange = function(){ - if(this.facade.getSelection().length > 0) { - this.facade.setSelection([]); - } - }; - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, this._stopSelectionChange.bind(this)); + + show: function () { + if (this.bounds) + this.node.style.display = ""; }, - /** - * Disables read only mode, see @see - * @methodOf ORYX.Plugins.AbstractPlugin.prototype - * @see ORYX.Plugins.AbstractPlugin.prototype.enableReadOnlyMode - */ - disableReadOnlyMode: function(){ - // Edges can be moved now again - this.facade.enableEvent(ORYX.CONFIG.EVENT_MOUSEDOWN); - - if (this._stopSelectionChange) { - this.facade.unregisterOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, this._stopSelectionChange.bind(this)); - this._stopSelectionChange = undefined; + + setBounds: function (bounds, min, max, aspectRatio) { + this.bounds = bounds; + + if (!min) + min = {width: ORYX.CONFIG.MINIMUM_SIZE, height: ORYX.CONFIG.MINIMUM_SIZE}; + + if (!max) + max = {width: ORYX.CONFIG.MAXIMUM_SIZE, height: ORYX.CONFIG.MAXIMUM_SIZE}; + + this.minSize = min; + this.maxSize = max; + + this.aspectRatio = aspectRatio; + + this.update(); + }, + + update: function () { + if (!this.bounds) { + return; + } + + var upL = this.bounds.upperLeft(); + + if (this.bounds.width() < this.minSize.width) { + this.bounds.set(upL.x, upL.y, upL.x + this.minSize.width, upL.y + this.bounds.height()); + } + ; + if (this.bounds.height() < this.minSize.height) { + this.bounds.set(upL.x, upL.y, upL.x + this.bounds.width(), upL.y + this.minSize.height); + } + ; + if (this.bounds.width() > this.maxSize.width) { + this.bounds.set(upL.x, upL.y, upL.x + this.maxSize.width, upL.y + this.bounds.height()); + } + ; + if (this.bounds.height() > this.maxSize.height) { + this.bounds.set(upL.x, upL.y, upL.x + this.bounds.width(), upL.y + this.maxSize.height); + } + ; + + var a = this.canvasNode.getScreenCTM(); + + upL.x *= a.a; + upL.y *= a.d; + + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + var ua = navigator.userAgent; + if (ua.indexOf('MSIE') >= 0) { + //IE 10 and below + var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); + if (zoom !== 100) { + additionalIEZoom = zoom / 100 + } + } + } + + if (additionalIEZoom === 1) { + upL.y = upL.y - jQuery("#canvasSection").offset().top + a.f; + upL.x = upL.x - jQuery("#canvasSection").offset().left + a.e; + + } else { + var canvasOffsetLeft = jQuery("#canvasSection").offset().left; + var canvasScrollLeft = jQuery("#canvasSection").scrollLeft(); + var canvasScrollTop = jQuery("#canvasSection").scrollTop(); + + var offset = a.e - (canvasOffsetLeft * additionalIEZoom); + var additionaloffset = 0; + if (offset > 10) { + additionaloffset = (offset / additionalIEZoom) - offset; + } + upL.y = upL.y - (jQuery("#canvasSection").offset().top * additionalIEZoom) + ((canvasScrollTop * additionalIEZoom) - canvasScrollTop) + a.f; + upL.x = upL.x - (canvasOffsetLeft * additionalIEZoom) + additionaloffset + ((canvasScrollLeft * additionalIEZoom) - canvasScrollLeft) + a.e; } + + if (this.orientation === "northwest") { + upL.x -= 13; + upL.y -= 13; + } else { // defaults to southeast + upL.x += (a.a * this.bounds.width()) + 3; + upL.y += (a.d * this.bounds.height()) + 3; + } + + this.position = upL; + + this.node.style.left = this.position.x + "px"; + this.node.style.top = this.position.y + "px"; + } +}); + + +/** + * Implements a Command to move shapes + * + */ +ORYX.Core.Command.Move = ORYX.Core.Command.extend({ + construct: function (moveShapes, offset, parent, selectedShapes, plugin) { + this.moveShapes = moveShapes; + this.selectedShapes = selectedShapes; + this.offset = offset; + this.plugin = plugin; + // Defines the old/new parents for the particular shape + this.newParents = moveShapes.collect(function (t) { + return parent || t.parent + }); + this.oldParents = moveShapes.collect(function (shape) { + return shape.parent + }); + this.dockedNodes = moveShapes.findAll(function (shape) { + return shape instanceof ORYX.Core.Node && shape.dockers.length == 1 + }).collect(function (shape) { + return { + docker: shape.dockers[0], + dockedShape: shape.dockers[0].getDockedShape(), + refPoint: shape.dockers[0].referencePoint + } + }); }, - - /** - * Extracts RDF from DOM. - * @methodOf ORYX.Plugins.AbstractPlugin.prototype - * @type {String} Extracted RFD. Null if there are transformation errors. - */ - getRDFFromDOM: function(){ - //convert to RDF - try { - var xsl = ""; - source=ORYX.PATH + "lib/extract-rdf.xsl"; - new Ajax.Request(source, { - asynchronous: false, - method: 'get', - onSuccess: function(transport){ - xsl = transport.responseText - }.bind(this), - onFailure: (function(transport){ - ORYX.Log.error("XSL load failed" + transport); - }).bind(this) - }); - - var domParser = new DOMParser(); - var xmlObject = domParser.parseFromString(this.getSerializedDOM(), "text/xml"); - var xslObject = domParser.parseFromString(xsl, "text/xml"); - var xsltProcessor = new XSLTProcessor(); - xsltProcessor.importStylesheet(xslObject); - var result = xsltProcessor.transformToFragment(xmlObject, document); - - var serializer = new XMLSerializer(); - - return serializer.serializeToString(result); - } catch(e){ - return ""; - } + execute: function () { + this.dockAllShapes() + // Moves by the offset + this.move(this.offset); + // Addes to the new parents + this.addShapeToParent(this.newParents); + // Set the selection to the current selection + this.selectCurrentShapes(); + this.plugin.facade.getCanvas().update(); + this.plugin.facade.updateSelection(); + }, + rollback: function () { + // Moves by the inverted offset + var offset = {x: -this.offset.x, y: -this.offset.y}; + this.move(offset); + // Addes to the old parents + this.addShapeToParent(this.oldParents); + this.dockAllShapes(true) + + // Set the selection to the current selection + this.selectCurrentShapes(); + this.plugin.facade.getCanvas().update(); + this.plugin.facade.updateSelection(); - }, - - /** - * Checks if a certain stencil set is loaded right now. - * - */ - isStencilSetExtensionLoaded: function(stencilSetExtensionNamespace) { - return this.facade.getStencilSets().values().any( - function(ss){ - return ss.extensions().keys().any( - function(extensionKey) { - return extensionKey == stencilSetExtensionNamespace; - }.bind(this) - ); - }.bind(this) - ); - }, - - /** - * Raises an event so that registered layouters does - * have the posiblility to layout the given shapes - * For further reading, have a look into the AbstractLayouter - * class - * @param {Object} shapes - */ - doLayout: function(shapes){ - // Raises a do layout event - if (this.facade.raiseEvent) - { - this.facade.raiseEvent({ - type : ORYX.CONFIG.EVENT_LAYOUT, - shapes : shapes - }); - } - else - { - this.facade.handleEvents({ - type : ORYX.CONFIG.EVENT_LAYOUT, - shapes : shapes - }); - } - }, - - - /** - * Does a primitive layouting with the incoming/outgoing - * edges (set the dockers to the right position) and if - * necessary, it will be called the real layouting - * @param {ORYX.Core.Node} node - * @param {Array} edges - */ - layoutEdges : function(node, allEdges, offset){ - - if (!this.facade.isExecutingCommands()){ return } - - var Command = ORYX.Core.Command.extend({ - construct: function(edges, node, offset, plugin){ - this.edges = edges; - this.node = node; - this.plugin = plugin; - this.offset = offset; - - // Get the new absolute center - var center = node.absoluteXY(); - this.ulo = {x: center.x - offset.x, y:center.y - offset.y}; - - - }, - execute: function(){ - - if (this.changes){ - this.executeAgain(); - return; - } else { - this.changes = []; - this.edges.each(function(edge){ - this.changes.push({ - edge: edge, - oldDockerPositions: edge.dockers.map(function(r){ return r.bounds.center() }) - }) - }.bind(this)); - } - - // Find all edges, which are related to the node and - // have more than two dockers - this.edges - // Find all edges with more than two dockers - .findAll(function(r){ return r.dockers.length > 2 }.bind(this)) - // For every edge, check second and one before last docker - // if there are horizontal/vertical on the same level - // and if so, align the the bounds - .each(function(edge){ - if (edge.dockers.first().getDockedShape() === this.node){ - var second = edge.dockers[1]; - if (this.align(second.bounds, edge.dockers.first())){ second.update(); } - } else if (edge.dockers.last().getDockedShape() === this.node) { - var beforeLast = edge.dockers[edge.dockers.length-2]; - if (this.align(beforeLast.bounds, edge.dockers.last())){ beforeLast.update(); } - } - edge._update(true); - edge.removeUnusedDockers(); - if (this.isBendPointIncluded(edge)){ - this.plugin.doLayout(edge); - return; - } - }.bind(this)); - - - // Find all edges, which have only to dockers - // and is located horizontal/vertical. - // Do layout with those edges - this.edges - // Find all edges with exactly two dockers - .each(function(edge){ - if (edge.dockers.length == 2){ - var p1 = edge.dockers.first().getAbsoluteReferencePoint() || edge.dockers.first().bounds.center(); - var p2 = edge.dockers.last().getAbsoluteReferencePoint() || edge.dockers.first().bounds.center(); - // Find all horizontal/vertical edges - if (Math.abs(-Math.abs(p1.x - p2.x) + Math.abs(this.offset.x)) < 2 || Math.abs(-Math.abs(p1.y - p2.y) + Math.abs(this.offset.y)) < 2){ - this.plugin.doLayout(edge); - } - } - }.bind(this)); - - this.edges.each(function(edge, i){ - this.changes[i].dockerPositions = edge.dockers.map(function(r){ return r.bounds.center() }); - }.bind(this)); - - }, - /** - * Align the bounds if the center is - * the same than the old center - * @params {Object} bounds - * @params {Object} bounds2 - */ - align: function(bounds, refDocker){ - - var abRef = refDocker.getAbsoluteReferencePoint() || refDocker.bounds.center(); - - var xdif = bounds.center().x-abRef.x; - var ydif = bounds.center().y-abRef.y; - if (Math.abs(-Math.abs(xdif) + Math.abs(this.offset.x)) < 3 && this.offset.xs === undefined){ - bounds.moveBy({x:-xdif, y:0}) - } - if (Math.abs(-Math.abs(ydif) + Math.abs(this.offset.y)) < 3 && this.offset.ys === undefined){ - bounds.moveBy({y:-ydif, x:0}) - } - - if (this.offset.xs !== undefined || this.offset.ys !== undefined){ - var absPXY = refDocker.getDockedShape().absoluteXY(); - xdif = bounds.center().x-(absPXY.x+((abRef.x-absPXY.x)/this.offset.xs)); - ydif = bounds.center().y-(absPXY.y+((abRef.y-absPXY.y)/this.offset.ys)); - - if (Math.abs(-Math.abs(xdif) + Math.abs(this.offset.x)) < 3){ - bounds.moveBy({x:-(bounds.center().x-abRef.x), y:0}) - } - - if (Math.abs(-Math.abs(ydif) + Math.abs(this.offset.y)) < 3){ - bounds.moveBy({y:-(bounds.center().y-abRef.y), x:0}) + move: function (offset, doLayout) { + + // Move all Shapes by these offset + for (var i = 0; i < this.moveShapes.length; i++) { + var value = this.moveShapes[i]; + value.bounds.moveBy(offset); + + if (value instanceof ORYX.Core.Node) { + + (value.dockers || []).each(function (d) { + d.bounds.moveBy(offset); + }) + + // Update all Dockers of Child shapes + /*var childShapesNodes = value.getChildShapes(true).findAll(function(shape){ return shape instanceof ORYX.Core.Node }); + var childDockedShapes = childShapesNodes.collect(function(shape){ return shape.getAllDockedShapes() }).flatten().uniq(); + var childDockedEdge = childDockedShapes.findAll(function(shape){ return shape instanceof ORYX.Core.Edge }); + childDockedEdge = childDockedEdge.findAll(function(shape){ return shape.getAllDockedShapes().all(function(dsh){ return childShapesNodes.include(dsh) }) }); + var childDockedDockers = childDockedEdge.collect(function(shape){ return shape.dockers }).flatten(); + + for (var j = 0; j < childDockedDockers.length; j++) { + var docker = childDockedDockers[j]; + if (!docker.getDockedShape() && !this.moveShapes.include(docker)) { + //docker.bounds.moveBy(offset); + //docker.update(); } - } - }, - - /** - * Returns a TRUE if there are bend point which overlay the shape - */ - isBendPointIncluded: function(edge){ - // Get absolute bounds - var ab = edge.dockers.first().getDockedShape(); - var bb = edge.dockers.last().getDockedShape(); - - if (ab) { - ab = ab.absoluteBounds(); - ab.widen(5); - } - - if (bb) { - bb = bb.absoluteBounds(); - bb.widen(20); // Wide with 20 because of the arrow from the edge - } - - return edge.dockers - .any(function(docker, i){ - var c = docker.bounds.center(); - // Dont count first and last - return i != 0 && i != edge.dockers.length-1 && - // Check if the point is included to the absolute bounds - ((ab && ab.isIncluded(c)) || (bb && bb.isIncluded(c))) - }) - }, - - removeAllDocker: function(edge){ - edge.dockers.slice(1, edge.dockers.length-1).each(function(docker){ - edge.removeDocker(docker); - }) - }, - executeAgain: function(){ - this.changes.each(function(change){ - // Reset the dockers - this.removeAllDocker(change.edge); - change.dockerPositions.each(function(pos, i){ - if (i==0||i==change.dockerPositions.length-1){ return } - var docker = change.edge.createDocker(undefined, pos); - docker.bounds.centerMoveTo(pos); - docker.update(); - }.bind(this)); - change.edge._update(true); - }.bind(this)); - }, - rollback: function(){ - this.changes.each(function(change){ - // Reset the dockers - this.removeAllDocker(change.edge); - change.oldDockerPositions.each(function(pos, i){ - if (i==0||i==change.oldDockerPositions.length-1){ return } - var docker = change.edge.createDocker(undefined, pos); - docker.bounds.centerMoveTo(pos); - docker.update(); - }.bind(this)); - change.edge._update(true); - }.bind(this)); - } - }); - - this.facade.executeCommands([new Command(allEdges, node, offset, this)]); + }*/ + + + var allEdges = [].concat(value.getIncomingShapes()) + .concat(value.getOutgoingShapes()) + // Remove all edges which are included in the selection from the list + .findAll(function (r) { + return r instanceof ORYX.Core.Edge && !this.moveShapes.any(function (d) { + return d == r || (d instanceof ORYX.Core.Controls.Docker && d.parent == r) + }) + }.bind(this)) + // Remove all edges which are between the node and a node contained in the selection from the list + .findAll(function (r) { + return (r.dockers.first().getDockedShape() == value || !this.moveShapes.include(r.dockers.first().getDockedShape())) && + (r.dockers.last().getDockedShape() == value || !this.moveShapes.include(r.dockers.last().getDockedShape())) + }.bind(this)) + + // Layout all outgoing/incoming edges + this.plugin.layoutEdges(value, allEdges, offset); + + + var allSameEdges = [].concat(value.getIncomingShapes()) + .concat(value.getOutgoingShapes()) + // Remove all edges which are included in the selection from the list + .findAll(function (r) { + return r instanceof ORYX.Core.Edge && r.dockers.first().isDocked() && r.dockers.last().isDocked() && !this.moveShapes.include(r) && !this.moveShapes.any(function (d) { + return d == r || (d instanceof ORYX.Core.Controls.Docker && d.parent == r) + }) + }.bind(this)) + // Remove all edges which are included in the selection from the list + .findAll(function (r) { + return this.moveShapes.indexOf(r.dockers.first().getDockedShape()) > i || this.moveShapes.indexOf(r.dockers.last().getDockedShape()) > i + }.bind(this)) + + for (var j = 0; j < allSameEdges.length; j++) { + for (var k = 1; k < allSameEdges[j].dockers.length - 1; k++) { + var docker = allSameEdges[j].dockers[k]; + if (!docker.getDockedShape() && !this.moveShapes.include(docker)) { + docker.bounds.moveBy(offset); + } + } + } + + /*var i=-1; + var nodes = value.getChildShapes(true); + var allEdges = []; + while(++i 0){ - // Do layout - this.layout(toLayout); - } - }, - - /** - * Implementation of layouting a set on shapes - * @param {Object} shapes Given shapes - * @memberOf ORYX.Plugins.AbstractLayouter.prototype - */ - layout: function(shapes){ - throw new Error("Layouter has to implement the layout function.") - } -});/* + } + + // Update the shape + //currentShape.update(); + + } + }, + selectCurrentShapes: function () { + this.plugin.facade.setSelection(this.selectedShapes); + } +}); +/* * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. * License rights for this program may be obtained from Alfresco Software, Ltd. * pursuant to a written agreement and any use of this program without such an @@ -17492,477 +21712,553 @@ ORYX.Plugins.AbstractLayouter = ORYX.Plugins.AbstractPlugin.extend({ * All code Copyright 2013 KIS Consultancy all rights reserved */ -if (!ORYX.Plugins) +if (!ORYX.Plugins) ORYX.Plugins = new Object(); -ORYX.Plugins.Edit = Clazz.extend({ - - construct: function(facade){ - +ORYX.Plugins.DragDocker = Clazz.extend({ + + /** + * Constructor + * @param {Object} Facade: The Facade of the Editor + */ + construct: function (facade) { this.facade = facade; - this.clipboard = new ORYX.Plugins.Edit.ClipBoard(); - - //this.facade.registerOnEvent(ORYX.CONFIG.EVENT_KEYDOWN, this.keyHandler.bind(this)); - - this.facade.offer({ - name: ORYX.I18N.Edit.cut, - description: ORYX.I18N.Edit.cutDesc, - icon: ORYX.PATH + "images/cut.png", - keyCodes: [{ - metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL], - keyCode: 88, - keyAction: ORYX.CONFIG.KEY_ACTION_DOWN - } - ], - functionality: this.callEdit.bind(this, this.editCut), - group: ORYX.I18N.Edit.group, - index: 1, - minShape: 1 - }); - - this.facade.offer({ - name: ORYX.I18N.Edit.copy, - description: ORYX.I18N.Edit.copyDesc, - icon: ORYX.PATH + "images/page_copy.png", - keyCodes: [{ - metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL], - keyCode: 67, - keyAction: ORYX.CONFIG.KEY_ACTION_DOWN - } - ], - functionality: this.callEdit.bind(this, this.editCopy, [true, false]), - group: ORYX.I18N.Edit.group, - index: 2, - minShape: 1 - }); - - this.facade.offer({ - name: ORYX.I18N.Edit.paste, - description: ORYX.I18N.Edit.pasteDesc, - icon: ORYX.PATH + "images/page_paste.png", - keyCodes: [{ - metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL], - keyCode: 86, - keyAction: ORYX.CONFIG.KEY_ACTION_DOWN - } - ], - functionality: this.callEdit.bind(this, this.editPaste), - isEnabled: this.clipboard.isOccupied.bind(this.clipboard), - group: ORYX.I18N.Edit.group, - index: 3, - minShape: 0, - maxShape: 0 - }); - - this.facade.offer({ - name: ORYX.I18N.Edit.del, - description: ORYX.I18N.Edit.delDesc, - icon: ORYX.PATH + "images/cross.png", - keyCodes: [{ - metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL], - keyCode: 8, - keyAction: ORYX.CONFIG.KEY_ACTION_DOWN - }, - { - keyCode: 46, - keyAction: ORYX.CONFIG.KEY_ACTION_DOWN - } - ], - functionality: this.callEdit.bind(this, this.editDelete), - group: ORYX.I18N.Edit.group, - index: 4, - minShape: 1 - }); + + // Set the valid and invalid color + this.VALIDCOLOR = ORYX.CONFIG.SELECTION_VALID_COLOR; + this.INVALIDCOLOR = ORYX.CONFIG.SELECTION_INVALID_COLOR; + + // Define Variables + this.shapeSelection = undefined; + this.docker = undefined; + this.dockerParent = undefined; + this.dockerSource = undefined; + this.dockerTarget = undefined; + this.lastUIObj = undefined; + this.isStartDocker = undefined; + this.isEndDocker = undefined; + this.undockTreshold = 10; + this.initialDockerPosition = undefined; + this.outerDockerNotMoved = undefined; + this.isValid = false; + + // For the Drag and Drop + // Register on MouseDown-Event on a Docker + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEDOWN, this.handleMouseDown.bind(this)); + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DOCKERDRAG, this.handleDockerDrag.bind(this)); + + + // Register on over/out to show / hide a docker + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEOVER, this.handleMouseOver.bind(this)); + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEOUT, this.handleMouseOut.bind(this)); + + }, - - callEdit: function(fn, args){ - window.setTimeout(function(){ - fn.apply(this, (args instanceof Array ? args : [])); - }.bind(this), 1); - }, - - /** - * Handles the mouse down event and starts the copy-move-paste action, if - * control or meta key is pressed. - */ - handleMouseDown: function(event) { - if(this._controlPressed) { - this._controlPressed = false; - this.editCopy(); -// console.log("copiedEle: %0",this.clipboard.shapesAsJson) -// console.log("mousevent: %o",event) - this.editPaste(); - event.forceExecution = true; - this.facade.raiseEvent(event, this.clipboard.shapesAsJson); - - } - }, - + /** - * The key handler for this plugin. Every action from the set of cut, copy, - * paste and delete should be accessible trough simple keyboard shortcuts. - * This method checks whether any event triggers one of those actions. + * MouseOut Handler * - * @param {Object} event The keyboard event that should be analysed for - * triggering of this plugin. */ -// keyHandler: function(event){ -// //TODO document what event.which is. -// -// ORYX.Log.debug("edit.js handles a keyEvent."); -// -// // assure we have the current event. -// if (!event) -// event = window.event; -// -// -// // get the currently pressed key and state of control key. -// var pressedKey = event.which || event.keyCode; -// var ctrlPressed = event.ctrlKey; -// -// // if the object is to be deleted, do so, and return immediately. -// if ((pressedKey == ORYX.CONFIG.KEY_CODE_DELETE) || -// ((pressedKey == ORYX.CONFIG.KEY_CODE_BACKSPACE) && -// (event.metaKey || event.appleMetaKey))) { -// -// ORYX.Log.debug("edit.js deletes the shape."); -// this.editDelete(); -// return; -// } -// -// // if control key is not pressed, we're not interested anymore. -// if (!ctrlPressed) -// return; -// -// // when ctrl is pressed, switch trough the possibilities. -// switch (pressedKey) { -// -// // cut. -// case ORYX.CONFIG.KEY_CODE_X: -// this.editCut(); -// break; -// -// // copy. -// case ORYX.CONFIG.KEY_CODE_C: -// this.editCopy(); -// break; -// -// // paste. -// case ORYX.CONFIG.KEY_CODE_V: -// this.editPaste(); -// break; -// } -// }, - + handleMouseOut: function (event, uiObj) { + // If there is a Docker, hide this + if (!this.docker && uiObj instanceof ORYX.Core.Controls.Docker) { + uiObj.hide(); + } else if (!this.docker && uiObj instanceof ORYX.Core.Edge) { + uiObj.dockers.each(function (docker) { + docker.hide(); + }); + } + }, + /** - * Returns a list of shapes which should be considered while copying. - * Besides the shapes of given ones, edges and attached nodes are added to the result set. - * If one of the given shape is a child of another given shape, it is not put into the result. + * MouseOver Handler + * */ - getAllShapesToConsider: function(shapes){ - var shapesToConsider = []; // only top-level shapes - var childShapesToConsider = []; // all child shapes of top-level shapes - - shapes.each(function(shape){ - //Throw away these shapes which have a parent in given shapes - isChildShapeOfAnother = shapes.any(function(s2){ - return s2.hasChildShape(shape); - }); - if(isChildShapeOfAnother) return; - - // This shape should be considered - shapesToConsider.push(shape); - // Consider attached nodes (e.g. intermediate events) - if (shape instanceof ORYX.Core.Node) { - var attached = shape.getOutgoingNodes(); - attached = attached.findAll(function(a){ return !shapes.include(a) }); - shapesToConsider = shapesToConsider.concat(attached); - } - - childShapesToConsider = childShapesToConsider.concat(shape.getChildShapes(true)); - }.bind(this)); - - // All edges between considered child shapes should be considered - // Look for these edges having incoming and outgoing in childShapesToConsider - var edgesToConsider = this.facade.getCanvas().getChildEdges().select(function(edge){ - // Ignore if already added - if(shapesToConsider.include(edge)) return false; - // Ignore if there are no docked shapes - if(edge.getAllDockedShapes().size() === 0) return false; - // True if all docked shapes are in considered child shapes - return edge.getAllDockedShapes().all(function(shape){ - // Remember: Edges can have other edges on outgoing, that is why edges must not be included in childShapesToConsider - return shape instanceof ORYX.Core.Edge || childShapesToConsider.include(shape); + handleMouseOver: function (event, uiObj) { + // If there is a Docker, show this + if (!this.docker && uiObj instanceof ORYX.Core.Controls.Docker) { + uiObj.show(); + } else if (!this.docker && uiObj instanceof ORYX.Core.Edge) { + uiObj.dockers.each(function (docker) { + docker.show(); }); - }); - shapesToConsider = shapesToConsider.concat(edgesToConsider); - - return shapesToConsider; + } }, - /** - * Performs the cut operation by first copy-ing and then deleting the - * current selection. + * DockerDrag Handler + * delegates the uiEvent of the drag event to the mouseDown function */ - editCut: function(){ - //TODO document why this returns false. - //TODO document what the magic boolean parameters are supposed to do. - - this.editCopy(false, true); - this.editDelete(true); - return false; + handleDockerDrag: function (event, uiObj) { + this.handleMouseDown(event.uiEvent, uiObj); }, - + /** - * Performs the copy operation. - * @param {Object} will_not_update ?? + * MouseDown Handler + * */ - editCopy: function( will_update, useNoOffset ){ - var selection = this.facade.getSelection(); - - //if the selection is empty, do not remove the previously copied elements - if(selection.length == 0) return; - - this.clipboard.refresh(selection, this.getAllShapesToConsider(selection), this.facade.getCanvas().getStencil().stencilSet().namespace(), useNoOffset); + handleMouseDown: function (event, uiObj) { + // If there is a Docker + if (uiObj instanceof ORYX.Core.Controls.Docker && uiObj.isMovable) { + + /* Buffering shape selection and clear selection*/ + this.shapeSelection = this.facade.getSelection(); + this.facade.setSelection(); + + this.docker = uiObj; + this.initialDockerPosition = this.docker.bounds.center(); + this.outerDockerNotMoved = false; + this.dockerParent = uiObj.parent; + + // Define command arguments + this._commandArg = { + docker: uiObj, + dockedShape: uiObj.getDockedShape(), + refPoint: uiObj.referencePoint || uiObj.bounds.center() + }; + + // Show the Docker + this.docker.show(); + + // If the Dockers Parent is an Edge, + // and the Docker is either the first or last Docker of the Edge + if (uiObj.parent instanceof ORYX.Core.Edge && + (uiObj.parent.dockers.first() == uiObj || uiObj.parent.dockers.last() == uiObj)) { + + // Get the Edge Source or Target + if (uiObj.parent.dockers.first() == uiObj && uiObj.parent.dockers.last().getDockedShape()) { + this.dockerTarget = uiObj.parent.dockers.last().getDockedShape(); + } else if (uiObj.parent.dockers.last() == uiObj && uiObj.parent.dockers.first().getDockedShape()) { + this.dockerSource = uiObj.parent.dockers.first().getDockedShape(); + } + + } else { + // If there parent is not an Edge, undefined the Source and Target + this.dockerSource = undefined; + this.dockerTarget = undefined; + } + + this.isStartDocker = this.docker.parent.dockers.first() === this.docker; + this.isEndDocker = this.docker.parent.dockers.last() === this.docker; + + // add to canvas while dragging + this.facade.getCanvas().add(this.docker.parent); + + // Hide all Labels from Docker + this.docker.parent.getLabels().each(function (label) { + label.hide(); + }); + + var eventCoordinates = this.facade.eventCoordinates(event); + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + var ua = navigator.userAgent; + if (ua.indexOf('MSIE') >= 0) { + //IE 10 and below + var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); + if (zoom !== 100) { + additionalIEZoom = zoom / 100 + } + } + } + + if (additionalIEZoom !== 1) { + eventCoordinates.x = eventCoordinates.x / additionalIEZoom; + eventCoordinates.y = eventCoordinates.y / additionalIEZoom; + } + + // Undocked the Docker from current Shape + if ((!this.isStartDocker && !this.isEndDocker) || !this.docker.isDocked()) { + + this.docker.setDockedShape(undefined); + // Set the Docker to the center of the mouse pointer + this.docker.bounds.centerMoveTo(eventCoordinates); + this.dockerParent._update(); + } else { + this.outerDockerNotMoved = true; + } + + var option = {movedCallback: this.dockerMoved.bind(this), upCallback: this.dockerMovedFinished.bind(this)}; + + this.startEventPos = eventCoordinates; + + // Enable the Docker for Drag'n'Drop, give the mouseMove and mouseUp-Callback with + ORYX.Core.UIEnableDrag(event, uiObj, option); + } + }, + + /** + * Docker MouseMove Handler + * + */ + dockerMoved: function (event) { + this.outerDockerNotMoved = false; + var snapToMagnet = undefined; + + if (this.docker.parent) { + if (this.isStartDocker || this.isEndDocker) { + + // Get the EventPosition and all Shapes on these point + var evPos = this.facade.eventCoordinates(event); + + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + var ua = navigator.userAgent; + if (ua.indexOf('MSIE') >= 0) { + //IE 10 and below + var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); + if (zoom !== 100) { + additionalIEZoom = zoom / 100 + } + } + } + + if (additionalIEZoom !== 1) { + evPos.x = evPos.x / additionalIEZoom; + evPos.y = evPos.y / additionalIEZoom; + } + + if (this.docker.isDocked()) { + /* Only consider start/end dockers if they are moved over a treshold */ + var distanceDockerPointer = + ORYX.Core.Math.getDistancePointToPoint(evPos, this.initialDockerPosition); + if (distanceDockerPointer < this.undockTreshold) { + this.outerDockerNotMoved = true; + return; + } + + /* Undock the docker */ + this.docker.setDockedShape(undefined); + // Set the Docker to the center of the mouse pointer + //this.docker.bounds.centerMoveTo(evPos); + this.dockerParent._update(); + } + + var shapes = this.facade.getCanvas().getAbstractShapesAtPosition(evPos); + + // Get the top level Shape on these, but not the same as Dockers parent + var uiObj = shapes.pop(); + if (this.docker.parent === uiObj) { + uiObj = shapes.pop(); + } + + // If the top level Shape the same as the last Shape, then return + if (this.lastUIObj == uiObj) { + //return; + + // If the top level uiObj instance of Shape and this isn't the parent of the docker + } else if (uiObj instanceof ORYX.Core.Shape) { + + // Ask by the StencilSet if the source, the edge and the target valid connections. + if (this.docker.parent instanceof ORYX.Core.Edge) { + + var highestParent = this.getHighestParentBeforeCanvas(uiObj); + /* Ensure that the shape to dock is not a child shape + * of the same edge. + */ + if (highestParent instanceof ORYX.Core.Edge && this.docker.parent === highestParent) { + this.isValid = false; + this.dockerParent._update(); + return; + } + this.isValid = false; + var curObj = uiObj, orgObj = uiObj; + while (!this.isValid && curObj && !(curObj instanceof ORYX.Core.Canvas)) { + uiObj = curObj; + this.isValid = this.facade.getRules().canConnect({ + sourceShape: this.dockerSource ? // Is there a docked source + this.dockerSource : // than set this + (this.isStartDocker ? // if not and if the Docker is the start docker + uiObj : // take the last uiObj + undefined), // if not set it to undefined; + edgeShape: this.docker.parent, + targetShape: this.dockerTarget ? // Is there a docked target + this.dockerTarget : // than set this + (this.isEndDocker ? // if not and if the Docker is not the start docker + uiObj : // take the last uiObj + undefined) // if not set it to undefined; + }); + curObj = curObj.parent; + } + + // Reset uiObj if no + // valid parent is found + if (!this.isValid) { + uiObj = orgObj; + } + + } else { + this.isValid = this.facade.getRules().canConnect({ + sourceShape: uiObj, + edgeShape: this.docker.parent, + targetShape: this.docker.parent + }); + } + + // If there is a lastUIObj, hide the magnets + if (this.lastUIObj) { + this.hideMagnets(this.lastUIObj); + } + + // If there is a valid connection, show the magnets + if (this.isValid) { + this.showMagnets(uiObj); + } + + // Set the Highlight Rectangle by these value + this.showHighlight(uiObj, this.isValid ? this.VALIDCOLOR : this.INVALIDCOLOR); + + // Buffer the current Shape + this.lastUIObj = uiObj; + } else { + // If there is no top level Shape, then hide the highligting of the last Shape + this.hideHighlight(); + this.lastUIObj ? this.hideMagnets(this.lastUIObj) : null; + this.lastUIObj = undefined; + this.isValid = false; + } + + // Snap to the nearest Magnet + if (this.lastUIObj && this.isValid && !(event.shiftKey || event.ctrlKey)) { + snapToMagnet = this.lastUIObj.magnets.find(function (magnet) { + return magnet.absoluteBounds().isIncluded(evPos); + }); + + if (snapToMagnet) { + this.docker.bounds.centerMoveTo(snapToMagnet.absoluteCenterXY()); + //this.docker.update() + } + } + } + } + // Snap to on the nearest Docker of the same parent + if (!(event.shiftKey || event.ctrlKey) && !snapToMagnet) { + var minOffset = ORYX.CONFIG.DOCKER_SNAP_OFFSET; + var nearestX = minOffset + 1; + var nearestY = minOffset + 1; + + var dockerCenter = this.docker.bounds.center(); + + if (this.docker.parent) { + + this.docker.parent.dockers.each((function (docker) { + if (this.docker == docker) { + return + } + ; + + var center = docker.referencePoint ? docker.getAbsoluteReferencePoint() : docker.bounds.center(); + + nearestX = Math.abs(nearestX) > Math.abs(center.x - dockerCenter.x) ? center.x - dockerCenter.x : nearestX; + nearestY = Math.abs(nearestY) > Math.abs(center.y - dockerCenter.y) ? center.y - dockerCenter.y : nearestY; + + + }).bind(this)); + + if (Math.abs(nearestX) < minOffset || Math.abs(nearestY) < minOffset) { + nearestX = Math.abs(nearestX) < minOffset ? nearestX : 0; + nearestY = Math.abs(nearestY) < minOffset ? nearestY : 0; + + this.docker.bounds.centerMoveTo(dockerCenter.x + nearestX, dockerCenter.y + nearestY); + //this.docker.update() + } else { + + + var previous = this.docker.parent.dockers[Math.max(this.docker.parent.dockers.indexOf(this.docker) - 1, 0)]; + var next = this.docker.parent.dockers[Math.min(this.docker.parent.dockers.indexOf(this.docker) + 1, this.docker.parent.dockers.length - 1)]; + + if (previous && next && previous !== this.docker && next !== this.docker) { + var cp = previous.bounds.center(); + var cn = next.bounds.center(); + var cd = this.docker.bounds.center(); + + // Checks if the point is on the line between previous and next + if (ORYX.Core.Math.isPointInLine(cd.x, cd.y, cp.x, cp.y, cn.x, cn.y, 10)) { + // Get the rise + var raise = (Number(cn.y) - Number(cp.y)) / (Number(cn.x) - Number(cp.x)); + // Calculate the intersection point + var intersecX = ((cp.y - (cp.x * raise)) - (cd.y - (cd.x * (-Math.pow(raise, -1))))) / ((-Math.pow(raise, -1)) - raise); + var intersecY = (cp.y - (cp.x * raise)) + (raise * intersecX); + + if (isNaN(intersecX) || isNaN(intersecY)) { + return; + } + + this.docker.bounds.centerMoveTo(intersecX, intersecY); + } + } - if( will_update ) this.facade.updateSelection(); + } + } + } + //this.facade.getCanvas().update(); + this.dockerParent._update(); }, - + /** - * Performs the paste operation. + * Docker MouseUp Handler + * */ - editPaste: function(){ - // Create a new canvas with childShapes - //and stencilset namespace to be JSON Import conform - var canvas = { - childShapes: this.clipboard.shapesAsJson, - stencilset:{ - namespace:this.clipboard.SSnamespace - } - }; - // Apply json helper to iterate over json object - jQuery.extend(canvas, ORYX.Core.AbstractShape.JSONHelper); - - var childShapeResourceIds = canvas.getChildShapes(true).pluck("resourceId"); - var outgoings = {}; - // Iterate over all shapes - canvas.eachChild(function(shape, parent){ - // Throw away these references where referenced shape isn't copied - shape.outgoing = shape.outgoing.select(function(out){ - return childShapeResourceIds.include(out.resourceId); - }); - shape.outgoing.each(function(out){ - if (!outgoings[out.resourceId]){ outgoings[out.resourceId] = []; } - outgoings[out.resourceId].push(shape); - }); - - return shape; - }.bind(this), true, true); - + dockerMovedFinished: function (event) { - // Iterate over all shapes - canvas.eachChild(function(shape, parent){ - - // Check if there has a valid target - if(shape.target && !(childShapeResourceIds.include(shape.target.resourceId))){ - shape.target = undefined; - shape.targetRemoved = true; + /* Reset to buffered shape selection */ + this.facade.setSelection(this.shapeSelection); + + // Hide the border + this.hideHighlight(); + + // Show all Labels from Docker + this.dockerParent.getLabels().each(function (label) { + label.show(); + //label.update(); + }); + + // If there is a last top level Shape + if (this.lastUIObj && (this.isStartDocker || this.isEndDocker)) { + // If there is a valid connection, the set as a docked Shape to them + if (this.isValid) { + + this.docker.setDockedShape(this.lastUIObj); + + this.facade.raiseEvent({ + type: ORYX.CONFIG.EVENT_DRAGDOCKER_DOCKED, + docker: this.docker, + parent: this.docker.parent, + target: this.lastUIObj + }); } - - // Check if the first docker is removed - if( shape.dockers && - shape.dockers.length >= 1 && - shape.dockers[0].getDocker && - ((shape.dockers[0].getDocker().getDockedShape() && - !childShapeResourceIds.include(shape.dockers[0].getDocker().getDockedShape().resourceId)) || - !shape.getShape().dockers[0].getDockedShape()&&!outgoings[shape.resourceId])) { - - shape.sourceRemoved = true; - } - - return shape; - }.bind(this), true, true); - - // Iterate over top-level shapes - canvas.eachChild(function(shape, parent){ - // All top-level shapes should get an offset in their bounds - // Move the shape occording to COPY_MOVE_OFFSET - if (this.clipboard.useOffset) { - shape.bounds = { - lowerRight: { - x: shape.bounds.lowerRight.x + ORYX.CONFIG.COPY_MOVE_OFFSET, - y: shape.bounds.lowerRight.y + ORYX.CONFIG.COPY_MOVE_OFFSET - }, - upperLeft: { - x: shape.bounds.upperLeft.x + ORYX.CONFIG.COPY_MOVE_OFFSET, - y: shape.bounds.upperLeft.y + ORYX.CONFIG.COPY_MOVE_OFFSET - } - }; - } - // Only apply offset to shapes with a target - if (shape.dockers){ - shape.dockers = shape.dockers.map(function(docker, i){ - // If shape had a target but the copied does not have anyone anymore, - // migrate the relative dockers to absolute ones. - if( (shape.targetRemoved === true && i == shape.dockers.length - 1&&docker.getDocker) || - (shape.sourceRemoved === true && i == 0&&docker.getDocker)){ + this.hideMagnets(this.lastUIObj); + } - docker = docker.getDocker().bounds.center(); - } + // Hide the Docker + this.docker.hide(); - // If it is the first docker and it has a docked shape, - // just return the coordinates - if ((i == 0 && docker.getDocker instanceof Function && - shape.sourceRemoved !== true && (docker.getDocker().getDockedShape() || ((outgoings[shape.resourceId]||[]).length > 0 && (!(shape.getShape() instanceof ORYX.Core.Node) || outgoings[shape.resourceId][0].getShape() instanceof ORYX.Core.Node)))) || - (i == shape.dockers.length - 1 && docker.getDocker instanceof Function && - shape.targetRemoved !== true && (docker.getDocker().getDockedShape() || shape.target))){ - - return { - x: docker.x, - y: docker.y, - getDocker: docker.getDocker - } - } else if (this.clipboard.useOffset) { - return { - x: docker.x + ORYX.CONFIG.COPY_MOVE_OFFSET, - y: docker.y + ORYX.CONFIG.COPY_MOVE_OFFSET, - getDocker: docker.getDocker - }; - } else { - return { - x: docker.x, - y: docker.y, - getDocker: docker.getDocker - }; - } - }.bind(this)); + if (this.outerDockerNotMoved) { + // Get the EventPosition and all Shapes on these point + var evPos = this.facade.eventCoordinates(event); + var shapes = this.facade.getCanvas().getAbstractShapesAtPosition(evPos); - } else if (shape.getShape() instanceof ORYX.Core.Node && shape.dockers && shape.dockers.length > 0 && (!shape.dockers.first().getDocker || shape.sourceRemoved === true || !(shape.dockers.first().getDocker().getDockedShape() || outgoings[shape.resourceId]))){ - - shape.dockers = shape.dockers.map(function(docker, i){ - - if((shape.sourceRemoved === true && i == 0&&docker.getDocker)){ - docker = docker.getDocker().bounds.center(); + /* Remove edges from selection */ + var shapeWithoutEdges = shapes.findAll(function (node) { + return node instanceof ORYX.Core.Node; + }); + shapes = shapeWithoutEdges.length ? shapeWithoutEdges : shapes; + this.facade.setSelection(shapes); + } else { + //Command-Pattern for dragging one docker + var dragDockerCommand = ORYX.Core.Command.extend({ + construct: function (docker, newPos, oldPos, newDockedShape, oldDockedShape, facade) { + this.docker = docker; + this.index = docker.parent.dockers.indexOf(docker); + this.newPosition = newPos; + this.newDockedShape = newDockedShape; + this.oldPosition = oldPos; + this.oldDockedShape = oldDockedShape; + this.facade = facade; + this.index = docker.parent.dockers.indexOf(docker); + this.shape = docker.parent; + + }, + execute: function () { + if (!this.docker.parent) { + this.docker = this.shape.dockers[this.index]; } - - if (this.clipboard.useOffset) { - return { - x: docker.x + ORYX.CONFIG.COPY_MOVE_OFFSET, - y: docker.y + ORYX.CONFIG.COPY_MOVE_OFFSET, - getDocker: docker.getDocker - }; + this.dock(this.newDockedShape, this.newPosition); + this.removedDockers = this.shape.removeUnusedDockers(); + this.facade.updateSelection(); + }, + rollback: function () { + this.dock(this.oldDockedShape, this.oldPosition); + (this.removedDockers || $H({})).each(function (d) { + this.shape.add(d.value, Number(d.key)); + this.shape._update(true); + }.bind(this)); + this.facade.updateSelection(); + }, + dock: function (toDockShape, pos) { + // Set the Docker to the new Shape + this.docker.setDockedShape(undefined); + if (toDockShape) { + this.docker.setDockedShape(toDockShape); + this.docker.setReferencePoint(pos); + //this.docker.update(); + //this.docker.parent._update(); } else { - return { - x: docker.x, - y: docker.y, - getDocker: docker.getDocker - }; + this.docker.bounds.centerMoveTo(pos); } - }.bind(this)); + + this.facade.getCanvas().update(); + } + }); + + + if (this.docker.parent) { + // Instanziate the dockCommand + var command = new dragDockerCommand(this.docker, this.docker.getDockedShape() ? this.docker.referencePoint : this.docker.bounds.center(), this._commandArg.refPoint, this.docker.getDockedShape(), this._commandArg.dockedShape, this.facade); + this.facade.executeCommands([command]); } - - return shape; - }.bind(this), false, true); + } - this.clipboard.useOffset = true; - this.facade.importJSON(canvas); + // Update all Shapes + //this.facade.updateSelection(); + + // Undefined all variables + this.docker = undefined; + this.dockerParent = undefined; + this.dockerSource = undefined; + this.dockerTarget = undefined; + this.lastUIObj = undefined; }, - + /** - * Performs the delete operation. No more asking. + * Hide the highlighting */ - editDelete: function(){ - var selection = this.facade.getSelection(); - - var clipboard = new ORYX.Plugins.Edit.ClipBoard(); - clipboard.refresh(selection, this.getAllShapesToConsider(selection)); - - var command = new ORYX.Plugins.Edit.DeleteCommand(clipboard , this.facade); - - this.facade.executeCommands([command]); - } -}); + hideHighlight: function () { + this.facade.raiseEvent({type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId: 'validDockedShape'}); + }, -ORYX.Plugins.Edit.ClipBoard = Clazz.extend({ - construct: function(){ - this.shapesAsJson = []; - this.selection = []; - this.SSnamespace=""; - this.useOffset=true; + /** + * Show the highlighting + * + */ + showHighlight: function (uiObj, color) { + + this.facade.raiseEvent({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, + highlightId: 'validDockedShape', + elements: [uiObj], + color: color + }); }, - isOccupied: function(){ - return this.shapesAsJson.length > 0; + + showMagnets: function (uiObj) { + uiObj.magnets.each(function (magnet) { + magnet.show(); + }); }, - refresh: function(selection, shapes, namespace, useNoOffset){ - this.selection = selection; - this.SSnamespace=namespace; - // Store outgoings, targets and parents to restore them later on - this.outgoings = {}; - this.parents = {}; - this.targets = {}; - this.useOffset = useNoOffset !== true; - - this.shapesAsJson = shapes.map(function(shape){ - var s = shape.toJSON(); - s.parent = {resourceId : shape.getParentShape().resourceId}; - s.parentIndex = shape.getParentShape().getChildShapes().indexOf(shape) - return s; + + hideMagnets: function (uiObj) { + uiObj.magnets.each(function (magnet) { + magnet.hide(); }); + }, + + getHighestParentBeforeCanvas: function (shape) { + if (!(shape instanceof ORYX.Core.Shape)) { + return undefined; + } + + var parent = shape.parent; + while (parent && !(parent.parent instanceof ORYX.Core.Canvas)) { + parent = parent.parent; + } + + return parent; } + }); -ORYX.Plugins.Edit.DeleteCommand = ORYX.Core.Command.extend({ - construct: function(clipboard, facade){ - this.clipboard = clipboard; - this.shapesAsJson = clipboard.shapesAsJson; - this.facade = facade; - - // Store dockers of deleted shapes to restore connections - this.dockers = this.shapesAsJson.map(function(shapeAsJson) { - var shape = shapeAsJson.getShape(); - var incomingDockers = shape.getIncomingShapes().map(function(s){return s.getDockers().last();}); - var outgoingDockers = shape.getOutgoingShapes().map(function(s){return s.getDockers().first();}); - var dockers = shape.getDockers().concat(incomingDockers, outgoingDockers).compact().map(function(docker){ - return { - object: docker, - referencePoint: docker.referencePoint, - dockedShape: docker.getDockedShape() - }; - }); - return dockers; - }).flatten(); - }, - execute: function(){ - this.shapesAsJson.each(function(shapeAsJson){ - // Delete shape - this.facade.deleteShape(shapeAsJson.getShape()); - }.bind(this)); - - this.facade.setSelection([]); - this.facade.getCanvas().update(); - this.facade.updateSelection(); - - }, - rollback: function(){ - this.shapesAsJson.each(function(shapeAsJson) { - var shape = shapeAsJson.getShape(); - var parent = this.facade.getCanvas().getChildShapeByResourceId(shapeAsJson.parent.resourceId) || this.facade.getCanvas(); - parent.add(shape, shape.parentIndex); - }.bind(this)); - - //reconnect shapes - this.dockers.each(function(d) { - d.object.setDockedShape(d.dockedShape); - d.object.setReferencePoint(d.referencePoint); - }.bind(this)); - - this.facade.setSelection(this.selectedShapes); - this.facade.getCanvas().update(); - this.facade.updateSelection(); - - } -});/* +/* * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. * License rights for this program may be obtained from Alfresco Software, Ltd. * pursuant to a written agreement and any use of this program without such an @@ -17972,601 +22268,335 @@ ORYX.Plugins.Edit.DeleteCommand = ORYX.Core.Command.extend({ * All code Copyright 2013 KIS Consultancy all rights reserved */ -/** - * @namespace Oryx name space for plugins - * @name ORYX.Plugins -*/ -if(!ORYX.Plugins) - ORYX.Plugins = new Object(); +if (!ORYX.Plugins) + ORYX.Plugins = new Object(); -/** - * The view plugin offers all of zooming functionality accessible over the - * tool bar. This are zoom in, zoom out, zoom to standard, zoom fit to model. - * - * @class ORYX.Plugins.View - * @extends Clazz - * @param {Object} facade The editor facade for plugins. -*/ -ORYX.Plugins.View = { - /** @lends ORYX.Plugins.View.prototype */ - facade: undefined, - - construct: function(facade, ownPluginData) { - this.facade = facade; - //Standard Values - this.zoomLevel = 1.0; - this.maxFitToScreenLevel=1.5; - this.minZoomLevel = 0.1; - this.maxZoomLevel = 2.5; - this.diff=5; //difference between canvas and view port, s.th. like toolbar?? - - //Read properties - if (ownPluginData !== undefined && ownPluginData !== null) { - ownPluginData.properties.each( function(property) { - if (property.zoomLevel) {this.zoomLevel = Number(1.0);} - if (property.maxFitToScreenLevel) {this.maxFitToScreenLevel=Number(property.maxFitToScreenLevel);} - if (property.minZoomLevel) {this.minZoomLevel = Number(property.minZoomLevel);} - if (property.maxZoomLevel) {this.maxZoomLevel = Number(property.maxZoomLevel);} - }.bind(this)); - } +ORYX.Plugins.AddDocker = Clazz.extend({ - - /* Register zoom in */ - this.facade.offer({ - 'name':ORYX.I18N.View.zoomIn, - 'functionality': this.zoom.bind(this, [1.0 + ORYX.CONFIG.ZOOM_OFFSET]), - 'group': ORYX.I18N.View.group, - 'icon': ORYX.PATH + "images/magnifier_zoom_in.png", - 'description': ORYX.I18N.View.zoomInDesc, - 'index': 1, - 'minShape': 0, - 'maxShape': 0, - 'isEnabled': function(){return this.zoomLevel < this.maxZoomLevel }.bind(this)}); - - /* Register zoom out */ - this.facade.offer({ - 'name':ORYX.I18N.View.zoomOut, - 'functionality': this.zoom.bind(this, [1.0 - ORYX.CONFIG.ZOOM_OFFSET]), - 'group': ORYX.I18N.View.group, - 'icon': ORYX.PATH + "images/magnifier_zoom_out.png", - 'description': ORYX.I18N.View.zoomOutDesc, - 'index': 2, - 'minShape': 0, - 'maxShape': 0, - 'isEnabled': function(){ return this._checkSize() }.bind(this)}); - - /* Register zoom standard */ - this.facade.offer({ - 'name':ORYX.I18N.View.zoomStandard, - 'functionality': this.setAFixZoomLevel.bind(this, 1), - 'group': ORYX.I18N.View.group, - 'icon': ORYX.PATH + "images/zoom_standard.png", - 'cls' : 'icon-large', - 'description': ORYX.I18N.View.zoomStandardDesc, - 'index': 3, - 'minShape': 0, - 'maxShape': 0, - 'isEnabled': function(){return this.zoomLevel != 1}.bind(this) - }); - - /* Register zoom fit to model */ - this.facade.offer({ - 'name':ORYX.I18N.View.zoomFitToModel, - 'functionality': this.zoomFitToModel.bind(this), - 'group': ORYX.I18N.View.group, - 'icon': ORYX.PATH + "images/image.png", - 'description': ORYX.I18N.View.zoomFitToModelDesc, - 'index': 4, - 'minShape': 0, - 'maxShape': 0 - }); - }, - - /** - * It sets the zoom level to a fix value and call the zooming function. - * - * @param {Number} zoomLevel - * the zoom level - */ - setAFixZoomLevel : function(zoomLevel) { - this.zoomLevel = zoomLevel; - this._checkZoomLevelRange(); - this.zoom(1); - }, - - /** - * It does the actual zooming. It changes the viewable size of the canvas - * and all to its child elements. - * - * @param {Number} factor - * the factor to adjust the zoom level - */ - zoom: function(factor) { - // TODO: Zoomen auf allen Objekten im SVG-DOM - - this.zoomLevel *= factor; - var scrollNode = this.facade.getCanvas().getHTMLContainer().parentNode.parentNode; - var canvas = this.facade.getCanvas(); - var newWidth = canvas.bounds.width() * this.zoomLevel; - var newHeight = canvas.bounds.height() * this.zoomLevel; - - /* Set new top offset */ - var offsetTop = (canvas.node.parentNode.parentNode.parentNode.offsetHeight - newHeight) / 2.0; - offsetTop = offsetTop > 20 ? offsetTop - 20 : 0; - canvas.node.parentNode.parentNode.style.marginTop = offsetTop + "px"; - offsetTop += 5; - canvas.getHTMLContainer().style.top = offsetTop + "px"; - - /*readjust scrollbar*/ - var newScrollTop= scrollNode.scrollTop - Math.round((canvas.getHTMLContainer().parentNode.getHeight()-newHeight) / 2)+this.diff; - var newScrollLeft= scrollNode.scrollLeft - Math.round((canvas.getHTMLContainer().parentNode.getWidth()-newWidth) / 2)+this.diff; - - /* Set new Zoom-Level */ - canvas.setSize({width: newWidth, height: newHeight}, true); - - /* Set Scale-Factor */ - canvas.node.setAttributeNS(null, "transform", "scale(" +this.zoomLevel+ ")"); - - /* Refresh the Selection */ - this.facade.updateSelection(); - scrollNode.scrollTop=newScrollTop; - scrollNode.scrollLeft=newScrollLeft; - - /* Update the zoom-level*/ - canvas.zoomLevel = this.zoomLevel; - }, - - - /** - * It calculates the zoom level to fit whole model into the visible area - * of the canvas. Than the model gets zoomed and the position of the - * scroll bars are adjusted. - * - */ - zoomFitToModel: function() { - - /* Get the size of the visible area of the canvas */ - var scrollNode = this.facade.getCanvas().getHTMLContainer().parentNode.parentNode; - var visibleHeight = scrollNode.getHeight() - 30; - var visibleWidth = scrollNode.getWidth() - 30; - - var nodes = this.facade.getCanvas().getChildShapes(); - - if(!nodes || nodes.length < 1) { - return false; - } - - /* Calculate size of canvas to fit the model */ - var bounds = nodes[0].absoluteBounds().clone(); - nodes.each(function(node) { - bounds.include(node.absoluteBounds().clone()); - }); - - - /* Set new Zoom Level */ - var scaleFactorWidth = visibleWidth / bounds.width(); - var scaleFactorHeight = visibleHeight / bounds.height(); - - /* Choose the smaller zoom level to fit the whole model */ - var zoomFactor = scaleFactorHeight < scaleFactorWidth ? scaleFactorHeight : scaleFactorWidth; - - /*Test if maximum zoom is reached*/ - if(zoomFactor>this.maxFitToScreenLevel){zoomFactor=this.maxFitToScreenLevel} - /* Do zooming */ - this.setAFixZoomLevel(zoomFactor); - - /* Set scroll bar position */ - scrollNode.scrollTop = Math.round(bounds.upperLeft().y * this.zoomLevel) - 5; - scrollNode.scrollLeft = Math.round(bounds.upperLeft().x * this.zoomLevel) - 5; - - }, - - /** - * It checks if the zoom level is less or equal to the level, which is required - * to schow the whole canvas. - * - * @private - */ - _checkSize:function(){ - var canvasParent=this.facade.getCanvas().getHTMLContainer().parentNode; - var minForCanvas= Math.min((canvasParent.parentNode.getWidth()/canvasParent.getWidth()),(canvasParent.parentNode.getHeight()/canvasParent.getHeight())); - return 1.05 > minForCanvas; - - }, - /** - * It checks if the zoom level is included in the definined zoom - * level range. - * - * @private - */ - _checkZoomLevelRange: function() { - /*var canvasParent=this.facade.getCanvas().getHTMLContainer().parentNode; - var maxForCanvas= Math.max((canvasParent.parentNode.getWidth()/canvasParent.getWidth()),(canvasParent.parentNode.getHeight()/canvasParent.getHeight())); - if(this.zoomLevel > maxForCanvas) { - this.zoomLevel = maxForCanvas; - }*/ - if(this.zoomLevel < this.minZoomLevel) { - this.zoomLevel = this.minZoomLevel; - } - - if(this.zoomLevel > this.maxZoomLevel) { - this.zoomLevel = this.maxZoomLevel; - } - } -}; + /** + * Constructor + * @param {Object} Facade: The Facade of the Editor + */ + construct: function (facade) { + this.facade = facade; + this.enableAdd = false; + this.enableRemove = false; + + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEDOWN, this.handleMouseDown.bind(this)); + }, + + setEnableAdd: function (enable) { + this.enableAdd = enable; + + if (this.enableAdd) { + jQuery("#add-bendpoint-button").addClass('pressed'); + } else { + jQuery("#add-bendpoint-button").removeClass('pressed'); + jQuery("#add-bendpoint-button").blur(); + } + }, + setEnableRemove: function (enable) { + this.enableRemove = enable; + + if (this.enableRemove) { + jQuery("#remove-bendpoint-button").addClass('pressed'); + } else { + jQuery("#remove-bendpoint-button").removeClass('pressed'); + jQuery("#remove-bendpoint-button").blur(); + } + }, + + enabledAdd: function (enable) { + return this.enableAdd; + }, + enabledRemove: function () { + return this.enableRemove; + }, + + /** + * MouseDown Handler + * + */ + handleMouseDown: function (event, uiObj) { + if (this.enabledAdd() && uiObj instanceof ORYX.Core.Edge) { + this.newDockerCommand({ + edge: uiObj, + position: this.facade.eventCoordinates(event) + }); + this.setEnableAdd(false); + + } else if (this.enabledRemove() && + uiObj instanceof ORYX.Core.Controls.Docker && + uiObj.parent instanceof ORYX.Core.Edge) { + this.newDockerCommand({ + edge: uiObj.parent, + docker: uiObj + }); + this.setEnableRemove(false); + } + document.body.style.cursor = 'default'; + }, + + // Options: edge (required), position (required if add), docker (required if delete) + newDockerCommand: function (options) { + if (!options.edge) + return; + + var commandClass = ORYX.Core.Command.extend({ + construct: function (addEnabled, deleteEnabled, edge, docker, pos, facade) { + this.addEnabled = addEnabled; + this.deleteEnabled = deleteEnabled; + this.edge = edge; + this.docker = docker; + this.pos = pos; + this.facade = facade; + }, + execute: function () { + if (this.addEnabled) { + if (!this.docker) { + this.docker = this.edge.addDocker(this.pos); + this.index = this.edge.dockers.indexOf(this.docker); + } else { + this.edge.add(this.docker, this.index); + } + } else if (this.deleteEnabled) { + this.index = this.edge.dockers.indexOf(this.docker); + this.pos = this.docker.bounds.center(); + this.edge.removeDocker(this.docker); + } + this.edge.getLabels().invoke("show"); + this.facade.getCanvas().update(); + this.facade.updateSelection(); + }, + rollback: function () { + if (this.addEnabled) { + if (this.docker instanceof ORYX.Core.Controls.Docker) { + this.edge.removeDocker(this.docker); + } + } else if (this.deleteEnabled) { + this.edge.add(this.docker, this.index); + } + this.edge.getLabels().invoke("show"); + this.facade.getCanvas().update(); + this.facade.updateSelection(); + } + }) + + var command = new commandClass(this.enabledAdd(), this.enabledRemove(), options.edge, options.docker, options.position, this.facade); + + this.facade.executeCommands([command]); + } +}); -ORYX.Plugins.View = Clazz.extend(ORYX.Plugins.View); /* * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. * License rights for this program may be obtained from Alfresco Software, Ltd. * pursuant to a written agreement and any use of this program without such an * agreement is prohibited. */ -if(!Signavio){ var Signavio = {} }; - if (!Signavio.Core) { Signavio.Core = {} }; - Signavio.Core.Version = "1.0"; - /* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ /* * All code Copyright 2013 KIS Consultancy all rights reserved */ -if (!Signavio) { - var Signavio = new Object(); -} +if (!ORYX.Plugins) + ORYX.Plugins = new Object(); -if (!Signavio.Plugins) { - Signavio.Plugins = new Object(); -} +ORYX.Plugins.SelectionFrame = Clazz.extend({ -if (!Signavio.Plugins.Utils) { - Signavio.Plugins.Utils = new Object(); -} + construct: function (facade) { + this.facade = facade; -if (!Signavio.Helper) { - Signavio.Helper = new Object(); -} + // Register on MouseEvents + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEDOWN, this.handleMouseDown.bind(this)); + document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.handleMouseUp.bind(this), true); + // Some initiale variables + this.position = {x: 0, y: 0}; + this.size = {width: 0, height: 0}; + this.offsetPosition = {x: 0, y: 0}; -new function() { + // (Un)Register Mouse-Move Event + this.moveCallback = undefined; + this.offsetScroll = {x: 0, y: 0}; + // HTML-Node of Selection-Frame + this.node = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", $('canvasSection'), + ['div', {'class': 'Oryx_SelectionFrame'}]); - /** - * Provides an uniq id - * @overwrite - * @return {String} - * - */ - ORYX.Editor.provideId = function() { - var res = [], hex = '0123456789ABCDEF'; - - for (var i = 0; i < 36; i++) res[i] = Math.floor(Math.random()*0x10); - - res[14] = 4; - res[19] = (res[19] & 0x3) | 0x8; - - for (var i = 0; i < 36; i++) res[i] = hex[res[i]]; - - res[8] = res[13] = res[18] = res[23] = '-'; - - return "sid-" + res.join(''); - }; + this.hide(); + }, + handleMouseDown: function (event, uiObj) { + // If there is the Canvas + if (uiObj instanceof ORYX.Core.Canvas) { + // Calculate the Offset + var scrollNode = uiObj.rootNode.parentNode.parentNode; -}(); + var a = this.facade.getCanvas().node.getScreenCTM(); + this.offsetPosition = { + x: a.e, + y: a.f + }; -/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + // Set the new Position + this.setPos({ + x: Event.pointerX(event) - jQuery("#canvasSection").offset().left, + y: Event.pointerY(event) - jQuery("#canvasSection").offset().top + 5 + }); -if (!ORYX.Plugins) { - ORYX.Plugins = new Object(); -} + // Reset the size + this.resize({width: 0, height: 0}); + this.moveCallback = this.handleMouseMove.bind(this); -/** - * This plugin is responsible for displaying loading indicators and to prevent - * the user from accidently unloading the page by, e.g., pressing the backspace - * button and returning to the previous site in history. - * @param {Object} facade The editor plugin facade to register enhancements with. - */ -ORYX.Plugins.Loading = { + // Register Mouse-Move Event + document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.moveCallback, false); - construct: function(facade){ - - this.facade = facade; - - // The parent Node - this.node = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", this.facade.getCanvas().getHTMLContainer().parentNode, ['div', { - 'class': 'LoadingIndicator' - }, '']); - - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADING_ENABLE, this.enableLoading.bind(this)); - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADING_DISABLE, this.disableLoading.bind(this)); - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADING_STATUS, this.showStatus.bind(this)); - - this.disableLoading(); + this.offsetScroll = {x: scrollNode.scrollLeft, y: scrollNode.scrollTop}; + + // Show the Frame + this.show(); + } + + Event.stop(event); }, - - enableLoading: function(options){ - if(options.text) - this.node.innerHTML = options.text + "..."; - else - this.node.innerHTML = ORYX.I18N.Loading.waiting; - this.node.removeClassName('StatusIndicator'); - this.node.addClassName('LoadingIndicator'); - this.node.style.display = "block"; - - var pos = this.facade.getCanvas().rootNode.parentNode.parentNode.parentNode.parentNode; - this.node.style.top = pos.offsetTop + 'px'; - this.node.style.left = pos.offsetLeft +'px'; - + handleMouseUp: function (event) { + // If there was an MouseMoving + if (this.moveCallback) { + // Hide the Frame + this.hide(); + + // Unregister Mouse-Move + document.documentElement.removeEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.moveCallback, false); + + this.moveCallback = undefined; + + var corrSVG = this.facade.getCanvas().node.getScreenCTM(); + + // Calculate the positions of the Frame + var a = { + x: this.size.width > 0 ? this.position.x : this.position.x + this.size.width, + y: this.size.height > 0 ? this.position.y : this.position.y + this.size.height + }; + + var b = { + x: a.x + Math.abs(this.size.width), + y: a.y + Math.abs(this.size.height) + }; + + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + var ua = navigator.userAgent; + if (ua.indexOf('MSIE') >= 0) { + //IE 10 and below + var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); + if (zoom !== 100) { + additionalIEZoom = zoom / 100 + } + } + } + + if (additionalIEZoom === 1) { + a.x = a.x - (corrSVG.e - jQuery("#canvasSection").offset().left); + a.y = a.y - (corrSVG.f - jQuery("#canvasSection").offset().top); + b.x = b.x - (corrSVG.e - jQuery("#canvasSection").offset().left); + b.y = b.y - (corrSVG.f - jQuery("#canvasSection").offset().top); + + } else { + var canvasOffsetLeft = jQuery("#canvasSection").offset().left; + var canvasScrollLeft = jQuery("#canvasSection").scrollLeft(); + var canvasScrollTop = jQuery("#canvasSection").scrollTop(); + + var offset = a.e - (canvasOffsetLeft * additionalIEZoom); + var additionaloffset = 0; + if (offset > 10) { + additionaloffset = (offset / additionalIEZoom) - offset; + } + + a.x = a.x - (corrSVG.e - (canvasOffsetLeft * additionalIEZoom) + additionaloffset + ((canvasScrollLeft * additionalIEZoom) - canvasScrollLeft)); + a.y = a.y - (corrSVG.f - (jQuery("#canvasSection").offset().top * additionalIEZoom) + ((canvasScrollTop * additionalIEZoom) - canvasScrollTop)); + b.x = b.x - (corrSVG.e - (canvasOffsetLeft * additionalIEZoom) + additionaloffset + ((canvasScrollLeft * additionalIEZoom) - canvasScrollLeft)); + b.y = b.y - (corrSVG.f - (jQuery("#canvasSection").offset().top * additionalIEZoom) + ((canvasScrollTop * additionalIEZoom) - canvasScrollTop)); + } + + + // Fit to SVG-Coordinates + a.x /= corrSVG.a; + a.y /= corrSVG.d; + b.x /= corrSVG.a; + b.y /= corrSVG.d; + + // Calculate the elements from the childs of the canvas + var elements = this.facade.getCanvas().getChildShapes(true).findAll(function (value) { + var absBounds = value.absoluteBounds(); + + var bA = absBounds.upperLeft(); + var bB = absBounds.lowerRight(); + + if (bA.x > a.x && bA.y > a.y && bB.x < b.x && bB.y < b.y) + return true; + return false; + }); + + // Set the selection + this.facade.setSelection(elements); + } + }, + + handleMouseMove: function (event) { + // Calculate the size + var size = { + width: Event.pointerX(event) - this.position.x - jQuery("#canvasSection").offset().left, + height: Event.pointerY(event) - this.position.y - jQuery("#canvasSection").offset().top + 5 + }; + + var scrollNode = this.facade.getCanvas().rootNode.parentNode.parentNode; + size.width -= this.offsetScroll.x - scrollNode.scrollLeft; + size.height -= this.offsetScroll.y - scrollNode.scrollTop; + + // Set the size + this.resize(size); + + Event.stop(event); }, - - disableLoading: function(){ + + hide: function () { this.node.style.display = "none"; }, - - showStatus: function(options) { - if(options.text) { - this.node.innerHTML = options.text; - this.node.addClassName('StatusIndicator'); - this.node.removeClassName('LoadingIndicator'); - this.node.style.display = 'block'; - - var pos = this.facade.getCanvas().rootNode.parentNode.parentNode.parentNode.parentNode; - - this.node.style.top = pos.offsetTop + 'px'; - this.node.style.left = pos.offsetLeft +'px'; - - var tout = options.timeout ? options.timeout : 2000; - - window.setTimeout((function(){ - - this.disableLoading(); - - }).bind(this), tout); - } - - } -} -ORYX.Plugins.Loading = Clazz.extend(ORYX.Plugins.Loading); -/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -if (!ORYX.Plugins) { - ORYX.Plugins = new Object(); -} + show: function () { + this.node.style.display = ""; + }, -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + setPos: function (pos) { + // Set the Position + this.node.style.top = pos.y + "px"; + this.node.style.left = pos.x + "px"; + this.position = pos; + }, -/** - * This plugin is responsible for resizing the canvas. - * @param {Object} facade The editor plugin facade to register enhancements with. - */ -ORYX.Plugins.CanvasResize = Clazz.extend({ + resize: function (size) { - construct: function(facade){ - - this.facade = facade; - new ORYX.Plugins.CanvasResizeButton( this.facade.getCanvas(), "N", this.resize.bind(this)); - new ORYX.Plugins.CanvasResizeButton( this.facade.getCanvas(), "W", this.resize.bind(this)); - new ORYX.Plugins.CanvasResizeButton( this.facade.getCanvas(), "E", this.resize.bind(this)); - new ORYX.Plugins.CanvasResizeButton( this.facade.getCanvas(), "S", this.resize.bind(this)); - - window.setTimeout(function(){jQuery(window).trigger('resize');}); - - }, - - resize: function( position, shrink ){ - - resizeCanvas = function(position, extentionSize, facade) { - var canvas = facade.getCanvas(); - var b = canvas.bounds; - var scrollNode = facade.getCanvas().getHTMLContainer().parentNode.parentNode; - - if( position == "E" || position == "W"){ - canvas.setSize({width: (b.width() + extentionSize)*canvas.zoomLevel, height: (b.height())*canvas.zoomLevel}) - - } else if( position == "S" || position == "N"){ - canvas.setSize({width: (b.width())*canvas.zoomLevel, height: (b.height() + extentionSize)*canvas.zoomLevel}) - } - - if( position == "N" || position == "W"){ - - var move = position == "N" ? {x: 0, y: extentionSize}: {x: extentionSize, y: 0 }; - - // Move all children - canvas.getChildNodes(false, function(shape){ shape.bounds.moveBy(move) }) - // Move all dockers, when the edge has at least one docked shape - var edges = canvas.getChildEdges().findAll(function(edge){ return edge.getAllDockedShapes().length > 0}) - var dockers = edges.collect(function(edge){ return edge.dockers.findAll(function(docker){ return !docker.getDockedShape() })}).flatten(); - dockers.each(function(docker){ docker.bounds.moveBy(move)}) - } else if( position == "S" ){ - scrollNode.scrollTop += extentionSize; - } else if( position == "E" ){ - scrollNode.scrollLeft += extentionSize; - } - - jQuery(window).trigger('resize'); - - canvas.update(); - facade.updateSelection(); - } - - var commandClass = ORYX.Core.Command.extend({ - construct: function(position, extentionSize, facade){ - this.position = position; - this.extentionSize = extentionSize; - this.facade = facade; - }, - execute: function(){ - resizeCanvas(this.position, this.extentionSize, this.facade); - }, - rollback: function(){ - resizeCanvas(this.position, -this.extentionSize, this.facade); - }, - update:function(){ - } - }); - - var extentionSize = ORYX.CONFIG.CANVAS_RESIZE_INTERVAL; - if(shrink) extentionSize = -extentionSize; - var command = new commandClass(position, extentionSize, this.facade); - - this.facade.executeCommands([command]); - - } - -}); + // Calculate the negative offset + this.setPos(this.position); + this.size = Object.clone(size); + if (size.width < 0) { + this.node.style.left = (this.position.x + size.width) + "px"; + size.width = -size.width; + } + if (size.height < 0) { + this.node.style.top = (this.position.y + size.height) + "px"; + size.height = -size.height; + } -ORYX.Plugins.CanvasResizeButton = Clazz.extend({ - - construct: function(canvas, position, callback){ - this.canvas = canvas; - var parentNode = canvas.getHTMLContainer().parentNode; - - window.myParent=parentNode; - - var actualScrollNode = jQuery('#canvasSection')[0]; - var scrollNode = actualScrollNode; - var canvasNode = jQuery('#canvasSection').find(".ORYX_Editor")[0]; - var svgRootNode = canvasNode.children[0]; - - var iconClass = 'glyphicon glyphicon-chevron-'; - var iconClassShrink = 'glyphicon glyphicon-chevron-'; - if(position == 'N') { - iconClass += 'up'; - iconClassShrink += 'down'; - } else if(position == 'S') { - iconClass += 'down'; - iconClassShrink += 'up'; - } else if(position == 'E') { - iconClass += 'right'; - iconClassShrink += 'left'; - } else if(position == 'W') { - iconClass += 'left'; - iconClassShrink += 'right'; - } - - // The buttons - var idGrow = 'canvas-shrink-' + position; - var idShrink = 'canvas-grow-' + position; - - var buttonGrow = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", parentNode, ['div', {'class': 'canvas_resize_indicator canvas_resize_indicator_grow' + ' ' + position, 'id': idGrow ,'title':ORYX.I18N.RESIZE.tipGrow+ORYX.I18N.RESIZE[position]}, - ['i', {'class' : iconClass}] - ]); - var buttonShrink = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", parentNode, ['div', {'class': 'canvas_resize_indicator canvas_resize_indicator_shrink' + ' ' + position, 'id': idShrink ,'title':ORYX.I18N.RESIZE.tipGrow+ORYX.I18N.RESIZE[position]}, - ['i', {'class' : iconClassShrink}] - ]); - // Defines a callback which gives back - // a boolean if the current mouse event - // is over the particular button area - var offSetWidth = 60; - var isOverOffset = function(event) { - - var isOverButton = event.target.id.indexOf("canvas-shrink") != -1 - || event.target.id.indexOf("canvas-grow") != -1 - || event.target.parentNode.id.indexOf("canvas-shrink") != -1 - || event.target.parentNode.id.indexOf("canvas-grow") != -1; - if(isOverButton) { - if(event.target.id == idGrow || event.target.id == idShrink || - event.target.parentNode.id == idGrow || event.target.parentNode.id == idShrink ) { - return true; - } else { - return false; - } - } - - if(event.target!=parentNode && event.target!=scrollNode&& event.target!=scrollNode.firstChild&& event.target!=svgRootNode&& event.target!=scrollNode){ return false; } - - //if(inCanvas){offSetWidth=30} else {offSetWidth=30*2} - //Safari work around - var X=event.offsetX !== undefined ? event.offsetX : event.layerX; - var Y=event.offsetY !== undefined ? event.offsetY : event.layerY; - - var canvasOffset = 0; - if(canvasNode.clientWidth < actualScrollNode.clientWidth) { - var widthDiff = actualScrollNode.clientWidth - canvasNode.clientWidth; - canvasOffset = widthDiff / 2; - } - - // Adjust to relative location to the actual viewport - Y = Y - actualScrollNode.scrollTop; - X = X - actualScrollNode.scrollLeft; - - - if(position == "N"){ - return Y < offSetWidth; - } else if(position == "W"){ - return X < offSetWidth + canvasOffset; - } else if(position == "E"){ - return actualScrollNode.clientWidth - X < offSetWidth + canvasOffset; - } else if(position == "S"){ - return actualScrollNode.clientHeight - Y < offSetWidth; - } - - return false; - }; - - var showButtons = (function() { - buttonGrow.show(); - - var w = canvas.bounds.width(); - var h = canvas.bounds.height(); - - if(position=="N" && (h - ORYX.CONFIG.CANVAS_RESIZE_INTERVAL > ORYX.CONFIG.CANVAS_MIN_HEIGHT)) buttonShrink.show(); - else if(position=="E" && (w - ORYX.CONFIG.CANVAS_RESIZE_INTERVAL > ORYX.CONFIG.CANVAS_MIN_WIDTH)) buttonShrink.show(); - else if(position=="S" && (h - ORYX.CONFIG.CANVAS_RESIZE_INTERVAL > ORYX.CONFIG.CANVAS_MIN_HEIGHT)) buttonShrink.show(); - else if(position=="W" && (w - ORYX.CONFIG.CANVAS_RESIZE_INTERVAL > ORYX.CONFIG.CANVAS_MIN_WIDTH)) buttonShrink.show(); - else buttonShrink.hide(); - - - }).bind(this); - - var hideButtons = function() { - buttonGrow.hide(); - buttonShrink.hide(); - }; - - // If the mouse move is over the button area, show the button - parentNode.parentNode.addEventListener( ORYX.CONFIG.EVENT_MOUSEMOVE, function(event){ if( isOverOffset(event) ){showButtons();} else {hideButtons()}} , false ); - // If the mouse is over the button, show them - buttonGrow.addEventListener( ORYX.CONFIG.EVENT_MOUSEOVER, function(event){showButtons();}, true ); - buttonShrink.addEventListener( ORYX.CONFIG.EVENT_MOUSEOVER, function(event){showButtons();}, true ); - // If the mouse is out, hide the button - //scrollNode.addEventListener( ORYX.CONFIG.EVENT_MOUSEOUT, function(event){button.hide()}, true ) - parentNode.parentNode.addEventListener( ORYX.CONFIG.EVENT_MOUSEOUT, function(event){hideButtons()} , true ); - //svgRootNode.addEventListener( ORYX.CONFIG.EVENT_MOUSEOUT, function(event){ inCanvas = false } , true ); - - // Hide the button initialy - hideButtons(); - - // Add the callbacks - buttonGrow.addEventListener('click', function() {callback( position ); showButtons();}, true); - buttonShrink.addEventListener('click', function() {callback( position, true ); showButtons();}, true); - - } - + // Set the size + this.node.style.width = size.width + "px"; + this.node.style.height = size.height + "px"; + } }); + /* * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. * License rights for this program may be obtained from Alfresco Software, Ltd. @@ -18577,399 +22607,237 @@ ORYX.Plugins.CanvasResizeButton = Clazz.extend({ * All code Copyright 2013 KIS Consultancy all rights reserved */ -if (!ORYX.Plugins) +if (!ORYX.Plugins) ORYX.Plugins = new Object(); -ORYX.Plugins.RenameShapes = Clazz.extend({ +ORYX.Plugins.ShapeHighlighting = Clazz.extend({ - facade: undefined, - - construct: function(facade){ - - this.facade = facade; - - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_CANVAS_SCROLL, this.hideField.bind(this)); - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DBLCLICK, this.actOnDBLClick.bind(this)); - this.facade.offer({ - keyCodes: [{ - keyCode: 113, // F2-Key - keyAction: ORYX.CONFIG.KEY_ACTION_DOWN - } - ], - functionality: this.renamePerF2.bind(this) - }); - - - document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEDOWN, this.hide.bind(this), true); - }, - - /** - * This method handles the "F2" key down event. The selected shape are looked - * up and the editing of title/name of it gets started. - */ - renamePerF2 : function() { - var selectedShapes = this.facade.getSelection(); - this.actOnDBLClick(undefined, selectedShapes.first()); - }, - - actOnDBLClick: function(evt, shape){ - - if( !(shape instanceof ORYX.Core.Shape) ){ return; } - - // Destroys the old input, if there is one - this.destroy(); - - // Get all properties which where at least one ref to view is set - var props = shape.getStencil().properties().findAll(function(item) { - return (item.refToView() - && item.refToView().length > 0 - && item.directlyEditable()); - }); - // from these, get all properties where write access are and the type is String or Expression - props = props.findAll(function(item) { return !item.readonly() && (item.type() == ORYX.CONFIG.TYPE_STRING || item.type() == ORYX.CONFIG.TYPE_EXPRESSION || item.type() == ORYX.CONFIG.TYPE_DATASOURCE); }); - - // Get all ref ids - var allRefToViews = props.collect(function(prop){ return prop.refToView(); }).flatten().compact(); - // Get all labels from the shape with the ref ids - var labels = shape.getLabels().findAll(function(label){ return allRefToViews.any(function(toView){ return label.id.endsWith(toView); }); }); - - // If there are no referenced labels --> return - if( labels.length == 0 ){ return; } - - // Define the nearest label - var nearestLabel = labels.length <= 1 ? labels[0] : null; - if( !nearestLabel ){ - nearestLabel = labels.find(function(label){ return label.node == evt.target || label.node == evt.target.parentNode; }); - if( !nearestLabel ){ - - var evtCoord = this.facade.eventCoordinates(evt); - - var additionalIEZoom = 1; - if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { - var ua = navigator.userAgent; - if (ua.indexOf('MSIE') >= 0) { - //IE 10 and below - var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); - if (zoom !== 100) { - additionalIEZoom = zoom / 100 - } - } - } - - if (additionalIEZoom !== 1) { - evtCoord.x = evtCoord.x / additionalIEZoom; - evtCoord.y = evtCoord.y / additionalIEZoom; - } + construct: function (facade) { - evtCoord.y += $("editor-header").clientHeight - $("canvasSection").scrollTop - 5; - if (KISBPM.HEADER_CONFIG.showAppTitle == false) - { - evtCoord.y += 61; - } - - evtCoord.x -= $("canvasSection").scrollLeft; - - var trans = this.facade.getCanvas().rootNode.lastChild.getScreenCTM(); - evtCoord.x *= trans.a; - evtCoord.y *= trans.d; - - var diff = labels.collect(function(label){ - var center = this.getCenterPosition( label.node ); - var len = Math.sqrt( Math.pow(center.x - evtCoord.x, 2) + Math.pow(center.y - evtCoord.y, 2)); - return {diff: len, label: label}; - }.bind(this)); - - diff.sort(function(a, b){ return a.diff > b.diff; }); - - nearestLabel = diff[0].label; + this.parentNode = facade.getCanvas().getSvgContainer(); + + // The parent Node + this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.parentNode, + ['g']); + + this.highlightNodes = {}; + + facade.registerOnEvent(ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, this.setHighlight.bind(this)); + facade.registerOnEvent(ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, this.hideHighlight.bind(this)); + + }, + + setHighlight: function (options) { + if (options && options.highlightId) { + var node = this.highlightNodes[options.highlightId]; + + if (!node) { + node = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.node, + ['path', { + "stroke-width": 2.0, "fill": "none" + }]); + + this.highlightNodes[options.highlightId] = node; + } + + if (options.elements && options.elements.length > 0) { + + this.setAttributesByStyle(node, options); + this.show(node); + + } else { + + this.hide(node); - } - } - // Get the particular property for the label - var prop = props.find(function(item) { return item.refToView().any(function(toView){ return nearestLabel.id == shape.id + toView; });}); - - // Get the center position from the nearest label - var width = Math.min(Math.max(100, shape.bounds.width()), 200); - var center = this.getCenterPosition( nearestLabel.node, shape ); - center.x -= (width/2); - var propId = prop.prefix() + "-" + prop.id(); - var textInput = document.createElement("textarea"); - textInput.id = 'shapeTextInput'; - textInput.style.position = 'absolute'; - textInput.style.width = width + 'px'; - textInput.style.left = (center.x < 10) ? 10 : center.x + 'px'; - textInput.style.top = (center.y - 15) + 'px'; - textInput.className = 'x-form-textarea x-form-field x_form_text_set_absolute'; - textInput.value = shape.properties[propId]; - this.oldValueText = shape.properties[propId]; - document.getElementById('canvasSection').appendChild(textInput); - this.shownTextField = textInput; - - - // Value change listener needs to be defined now since we reference it in the text field - this.updateValueFunction = function(newValue, oldValue) { - var currentEl = shape; - var facade = this.facade; - - if (oldValue != newValue) { - // Implement the specific command for property change - var commandClass = ORYX.Core.Command.extend({ - construct: function(){ - this.el = currentEl; - this.propId = propId; - this.oldValue = oldValue; - this.newValue = newValue; - this.facade = facade; - }, - execute: function(){ - this.el.setProperty(this.propId, this.newValue); - //this.el.update(); - this.facade.setSelection([this.el]); - this.facade.getCanvas().update(); - this.facade.updateSelection(); - }, - rollback: function(){ - this.el.setProperty(this.propId, this.oldValue); - //this.el.update(); - this.facade.setSelection([this.el]); - this.facade.getCanvas().update(); - this.facade.updateSelection(); - } - }); - // Instantiated the class - var command = new commandClass(); - - // Execute the command - this.facade.executeCommands([command]); - } - }.bind(this); - - jQuery("#shapeTextInput").focus(); - - jQuery("#shapeTextInput").autogrow(); - - // Disable the keydown in the editor (that when hitting the delete button, the shapes not get deleted) - this.facade.disableEvent(ORYX.CONFIG.EVENT_KEYDOWN); - - }, - - getCenterPosition: function(svgNode, shape){ - - if (!svgNode) { return {x:0, y:0}; } - - var scale = this.facade.getCanvas().node.getScreenCTM(); - var absoluteXY = shape.bounds.upperLeft(); - - var hasParent = true; - var searchShape = shape; - while (hasParent) - { - if (searchShape.getParentShape().getStencil().idWithoutNs() === 'BPMNDiagram') - { - hasParent = false; - } - else - { - var parentXY = searchShape.getParentShape().bounds.upperLeft(); - absoluteXY.x += parentXY.x; - absoluteXY.y += parentXY.y; - searchShape = searchShape.getParentShape(); - } - } - - var center = shape.bounds.midPoint(); - center.x += absoluteXY.x + scale.e; - center.y += absoluteXY.y + scale.f; - - center.x *= scale.a; - center.y *= scale.d; - - var additionalIEZoom = 1; - if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { - var ua = navigator.userAgent; - if (ua.indexOf('MSIE') >= 0) { - //IE 10 and below - var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); - if (zoom !== 100) { - additionalIEZoom = zoom / 100 - } } + } - - if (additionalIEZoom === 1) { - center.y = center.y - jQuery("#canvasSection").offset().top + 5; - center.x -= jQuery("#canvasSection").offset().left; - + }, + + hideHighlight: function (options) { + if (options && options.highlightId && this.highlightNodes[options.highlightId]) { + this.hide(this.highlightNodes[options.highlightId]); + } + }, + + hide: function (node) { + node.setAttributeNS(null, 'display', 'none'); + }, + + show: function (node) { + node.setAttributeNS(null, 'display', ''); + }, + + setAttributesByStyle: function (node, options) { + + // If the style say, that it should look like a rectangle + if (options.style && options.style == ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE) { + + // Set like this + var bo = options.elements[0].absoluteBounds(); + + var strWidth = options.strokewidth ? options.strokewidth : ORYX.CONFIG.BORDER_OFFSET + + node.setAttributeNS(null, "d", this.getPathRectangle(bo.a, bo.b, strWidth)); + node.setAttributeNS(null, "stroke", options.color ? options.color : ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR); + node.setAttributeNS(null, "stroke-opacity", options.opacity ? options.opacity : 0.2); + node.setAttributeNS(null, "stroke-width", strWidth); + + } else if (options.elements.length == 1 + && options.elements[0] instanceof ORYX.Core.Edge && + options.highlightId != "selection") { + + /* Highlight containment of edge's childs */ + var path = this.getPathEdge(options.elements[0].dockers); + if (path && path.length > 0) { + node.setAttributeNS(null, "d", path); + } + node.setAttributeNS(null, "stroke", options.color ? options.color : ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR); + node.setAttributeNS(null, "stroke-opacity", options.opacity ? options.opacity : 0.2); + node.setAttributeNS(null, "stroke-width", ORYX.CONFIG.OFFSET_EDGE_BOUNDS); + } else { - var canvasOffsetLeft = jQuery("#canvasSection").offset().left; - var canvasScrollLeft = jQuery("#canvasSection").scrollLeft(); - var canvasScrollTop = jQuery("#canvasSection").scrollTop(); - - var offset = scale.e - (canvasOffsetLeft * additionalIEZoom); - var additionaloffset = 0; - if (offset > 10) { - additionaloffset = (offset / additionalIEZoom) - offset; - } - center.y = center.y - (jQuery("#canvasSection").offset().top * additionalIEZoom) + 5 + ((canvasScrollTop * additionalIEZoom) - canvasScrollTop); - center.x = center.x - (canvasOffsetLeft * additionalIEZoom) + additionaloffset + ((canvasScrollLeft * additionalIEZoom) - canvasScrollLeft); - } - - - return center; - }, - - hide: function (e) { - if (this.shownTextField && (!e || e.target !== this.shownTextField)) { - var newValue = this.shownTextField.value; - if (newValue !== this.oldValueText) - { - this.updateValueFunction(newValue, this.oldValueText); - } - this.destroy(); - } - }, - - hideField: function (e) { - if (this.shownTextField) { - this.destroy(); - } - }, - - destroy: function (e) { - var textInputComp = jQuery("#shapeTextInput"); - if( textInputComp ){ - textInputComp.remove(); - delete this.shownTextField; - - this.facade.enableEvent(ORYX.CONFIG.EVENT_KEYDOWN); - } - } -}); -/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + // If not, set just the corners + var path = this.getPathByElements(options.elements); + if (path && path.length > 0) { + node.setAttributeNS(null, "d", path); + } + node.setAttributeNS(null, "stroke", options.color ? options.color : ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR); + node.setAttributeNS(null, "stroke-opacity", options.opacity ? options.opacity : 1.0); + node.setAttributeNS(null, "stroke-width", options.strokewidth ? options.strokewidth : 2.0); -if(!ORYX.Plugins) - ORYX.Plugins = new Object(); + } + }, -/** - * Supports EPCs by offering a syntax check and export and import ability.. - * - * - */ -ORYX.Plugins.ProcessLink = Clazz.extend({ + getPathByElements: function (elements) { + if (!elements || elements.length <= 0) { + return undefined + } + + // Get the padding and the size + var padding = ORYX.CONFIG.SELECTED_AREA_PADDING; + + var path = "" + + // Get thru all Elements + elements.each((function (element) { + if (!element) { + return + } + // Get the absolute Bounds and the two Points + var bounds = element.absoluteBounds(); + bounds.widen(padding) + var a = bounds.upperLeft(); + var b = bounds.lowerRight(); + + path = path + this.getPath(a, b); + + }).bind(this)); + + return path; + + }, + + getPath: function (a, b) { + + return this.getPathCorners(a, b); + + }, + + getPathCorners: function (a, b) { + + var size = ORYX.CONFIG.SELECTION_HIGHLIGHT_SIZE; + + var path = "" + + // Set: Upper left + path = path + "M" + a.x + " " + (a.y + size) + " l0 -" + size + " l" + size + " 0 "; + // Set: Lower left + path = path + "M" + a.x + " " + (b.y - size) + " l0 " + size + " l" + size + " 0 "; + // Set: Lower right + path = path + "M" + b.x + " " + (b.y - size) + " l0 " + size + " l-" + size + " 0 "; + // Set: Upper right + path = path + "M" + b.x + " " + (a.y + size) + " l0 -" + size + " l-" + size + " 0 "; + + return path; + }, + + getPathRectangle: function (a, b, strokeWidth) { + + var size = ORYX.CONFIG.SELECTION_HIGHLIGHT_SIZE; + + var path = "" + var offset = strokeWidth / 2.0; - facade: undefined, + // Set: Upper left + path = path + "M" + (a.x + offset) + " " + (a.y); + path = path + " L" + (a.x + offset) + " " + (b.y - offset); + path = path + " L" + (b.x - offset) + " " + (b.y - offset); + path = path + " L" + (b.x - offset) + " " + (a.y + offset); + path = path + " L" + (a.x + offset) + " " + (a.y + offset); - /** - * Offers the plugin functionality: - * - */ - construct: function(facade) { + return path; + }, - this.facade = facade; - - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_PROPERTY_CHANGED, this.propertyChanged.bind(this) ); - - }, + getPathEdge: function (edgeDockers) { + var length = edgeDockers.length; + var path = "M" + edgeDockers[0].bounds.center().x + " " + + edgeDockers[0].bounds.center().y; + for (i = 1; i < length; i++) { + var dockerPoint = edgeDockers[i].bounds.center(); + path = path + " L" + dockerPoint.x + " " + dockerPoint.y; + } - /** - * - * @param {Object} option - */ - propertyChanged: function( option, node){ - - if( option.name !== "oryx-refuri" || !node instanceof ORYX.Core.Node ){ return } - - - if( option.value && option.value.length > 0 && option.value != "undefined"){ - - this.show( node, option.value ); - - } else { + return path; + } - this.hide( node ); +}); - } - }, - - /** - * Shows the Link for a particular shape with a specific url - * - * @param {Object} shape - * @param {Object} url - */ - show: function( shape, url){ +ORYX.Plugins.HighlightingSelectedShapes = Clazz.extend({ - - // Generate the svg-representation of a link - var link = ORYX.Editor.graft("http://www.w3.org/2000/svg", null , - [ 'a', - {'target': '_blank'}, - ['path', - { "stroke-width": 1.0, "stroke":"#00DD00", "fill": "#00AA00", "d": "M3,3 l0,-2.5 l7.5,0 l0,-2.5 l7.5,4.5 l-7.5,3.5 l0,-2.5 l-8,0", "line-captions": "round"} - ] - ]); + construct: function (facade) { + this.facade = facade; + this.opacityFull = 0.9; + this.opacityLow = 0.4; - var link = ORYX.Editor.graft("http://www.w3.org/2000/svg", null , - [ 'a', - {'target': '_blank'}, - ['path', { "style": "fill:#92BFFC;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.72", "d": "M0 1.44 L0 15.05 L11.91 15.05 L11.91 5.98 L7.37 1.44 L0 1.44 Z"}], - ['path', { "style": "stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.72;fill:none;", "transform": "translate(7.5, -8.5)", "d": "M0 10.51 L0 15.05 L4.54 15.05"}], - ['path', { "style": "fill:#f28226;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.72", "transform": "translate(-3, -1)", "d": "M0 8.81 L0 13.06 L5.95 13.06 L5.95 15.05 A50.2313 50.2313 -175.57 0 0 10.77 11.08 A49.9128 49.9128 -1.28 0 0 5.95 6.54 L5.95 8.81 L0 8.81 Z"}], - ]); + // Register on Dragging-Events for show/hide of ShapeMenu + //this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DRAGDROP_START, this.hide.bind(this)); + //this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DRAGDROP_END, this.show.bind(this)); + }, - /* - * - * [ 'a', - {'target': '_blank'}, - ['path', { "style": "fill:none;stroke-width:0.5px; stroke:#000000", "d": "M7,4 l0,2"}], - ['path', { "style": "fill:none;stroke-width:0.5px; stroke:#000000", "d": "M4,8 l-2,0 l0,6"}], - ['path', { "style": "fill:none;stroke-width:0.5px; stroke:#000000", "d": "M10,8 l2,0 l0,6"}], - ['rect', { "style": "fill:#96ff96;stroke:#000000;stroke-width:1", "width": 6, "height": 4, "x": 4, "y": 0}], - ['rect', { "style": "fill:#ffafff;stroke:#000000;stroke-width:1", "width": 6, "height": 4, "x": 4, "y": 6}], - ['rect', { "style": "fill:#96ff96;stroke:#000000;stroke-width:1", "width": 6, "height": 4, "x": 0, "y": 12}], - ['rect', { "style": "fill:#96ff96;stroke:#000000;stroke-width:1", "width": 6, "height": 4, "x": 8, "y": 12}], - ['rect', { "style": "fill:none;stroke:none;pointer-events:all", "width": 14, "height": 16, "x": 0, "y": 0}] - ]); - */ - - // Set the link with the special namespace - link.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", url); - - - // Shows the link in the overlay - this.facade.raiseEvent({ - type: ORYX.CONFIG.EVENT_OVERLAY_SHOW, - id: "arissupport.urlref_" + shape.id, - shapes: [shape], - node: link, - nodePosition: "SE" - }); - - }, - - /** - * Hides the Link for a particular shape - * - * @param {Object} shape - */ - hide: function( shape ){ - - this.facade.raiseEvent({ - type: ORYX.CONFIG.EVENT_OVERLAY_HIDE, - id: "arissupport.urlref_" + shape.id - }); - - } + /** + * On the Selection-Changed + * + */ + onSelectionChanged: function (event) { + if (event.elements && event.elements.length > 1) { + this.facade.raiseEvent({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, + highlightId: 'selection', + elements: event.elements.without(event.subSelection), + color: ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR, + opacity: !event.subSelection ? this.opacityFull : this.opacityLow + }); + + if (event.subSelection) { + this.facade.raiseEvent({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, + highlightId: 'subselection', + elements: [event.subSelection], + color: ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR, + opacity: this.opacityFull + }); + } else { + this.facade.raiseEvent({type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId: 'subselection'}); + } + + } else { + this.facade.raiseEvent({type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId: 'selection'}); + this.facade.raiseEvent({type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId: 'subselection'}); + } + } });/* * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. * License rights for this program may be obtained from Alfresco Software, Ltd. @@ -18980,2751 +22848,969 @@ ORYX.Plugins.ProcessLink = Clazz.extend({ * All code Copyright 2013 KIS Consultancy all rights reserved */ -Array.prototype.insertFrom = function(from, to){ - to = Math.max(0, to); - from = Math.min( Math.max(0, from), this.length-1 ); - - var el = this[from]; - var old = this.without(el); - var newA = old.slice(0, to); - newA.push(el); - if(old.length > to ){ - newA = newA.concat(old.slice(to)) - }; - return newA; -} +if (!ORYX.Plugins) + ORYX.Plugins = new Object(); -if(!ORYX.Plugins) - ORYX.Plugins = new Object(); +ORYX.Plugins.Overlay = Clazz.extend({ -ORYX.Plugins.Arrangement = ORYX.Plugins.AbstractPlugin.extend({ + facade: undefined, - facade: undefined, + styleNode: undefined, - construct: function(facade) { - this.facade = facade; + construct: function (facade) { - // Z-Ordering - /** Hide for SIGNAVIO - - this.facade.offer({ - 'name':ORYX.I18N.Arrangement.btf, - 'functionality': this.setZLevel.bind(this, this.setToTop), - 'group': ORYX.I18N.Arrangement.groupZ, - 'icon': ORYX.PATH + "images/shape_move_front.png", - 'description': ORYX.I18N.Arrangement.btfDesc, - 'index': 1, - 'minShape': 1}); - - this.facade.offer({ - 'name':ORYX.I18N.Arrangement.btb, - 'functionality': this.setZLevel.bind(this, this.setToBack), - 'group': ORYX.I18N.Arrangement.groupZ, - 'icon': ORYX.PATH + "images/shape_move_back.png", - 'description': ORYX.I18N.Arrangement.btbDesc, - 'index': 2, - 'minShape': 1}); + this.facade = facade; - this.facade.offer({ - 'name':ORYX.I18N.Arrangement.bf, - 'functionality': this.setZLevel.bind(this, this.setForward), - 'group': ORYX.I18N.Arrangement.groupZ, - 'icon': ORYX.PATH + "images/shape_move_forwards.png", - 'description': ORYX.I18N.Arrangement.bfDesc, - 'index': 3, - 'minShape': 1}); + this.changes = []; - this.facade.offer({ - 'name':ORYX.I18N.Arrangement.bb, - 'functionality': this.setZLevel.bind(this, this.setBackward), - 'group': ORYX.I18N.Arrangement.groupZ, - 'icon': ORYX.PATH + "images/shape_move_backwards.png", - 'description': ORYX.I18N.Arrangement.bbDesc, - 'index': 4, - 'minShape': 1}); + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_OVERLAY_SHOW, this.show.bind(this)); + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_OVERLAY_HIDE, this.hide.bind(this)); - // Aligment - this.facade.offer({ - 'name':ORYX.I18N.Arrangement.ab, - 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_BOTTOM]), - 'group': ORYX.I18N.Arrangement.groupA, - 'icon': ORYX.PATH + "images/shape_align_bottom.png", - 'description': ORYX.I18N.Arrangement.abDesc, - 'index': 1, - 'minShape': 2}); + this.styleNode = document.createElement('style') + this.styleNode.setAttributeNS(null, 'type', 'text/css') + document.getElementsByTagName('head')[0].appendChild(this.styleNode) + }, - this.facade.offer({ - 'name':ORYX.I18N.Arrangement.at, - 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_TOP]), - 'group': ORYX.I18N.Arrangement.groupA, - 'icon': ORYX.PATH + "images/shape_align_top.png", - 'description': ORYX.I18N.Arrangement.atDesc, - 'index': 3, - 'minShape': 2}); + /** + * Show the overlay for specific nodes + * @param {Object} options + * + * String options.id - MUST - Define the id of the overlay (is needed for the hiding of this overlay) + * ORYX.Core.Shape[] options.shapes - MUST - Define the Shapes for the changes + * attr-name:value options.changes - Defines all the changes which should be shown + * + * + */ + show: function (options) { - this.facade.offer({ - 'name':ORYX.I18N.Arrangement.al, - 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_LEFT]), - 'group': ORYX.I18N.Arrangement.groupA, - 'icon': ORYX.PATH + "images/shape_align_left.png", - 'description': ORYX.I18N.Arrangement.alDesc, - 'index': 4, - 'minShape': 2}); + // Checks if all arguments are available + if (!options || + !options.shapes || !options.shapes instanceof Array || + !options.id || !options.id instanceof String || options.id.length == 0) { - this.facade.offer({ - 'name':ORYX.I18N.Arrangement.ar, - 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_RIGHT]), - 'group': ORYX.I18N.Arrangement.groupA, - 'icon': ORYX.PATH + "images/shape_align_right.png", - 'description': ORYX.I18N.Arrangement.arDesc, - 'index': 6, - 'minShape': 2}); + return - **/ - - this.facade.offer({ - 'name':ORYX.I18N.Arrangement.am, - 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_MIDDLE]), - 'group': ORYX.I18N.Arrangement.groupA, - 'icon': ORYX.PATH + "images/shape_align_middle.png", - 'description': ORYX.I18N.Arrangement.amDesc, - 'index': 1, - 'minShape': 2}); - - this.facade.offer({ - 'name':ORYX.I18N.Arrangement.ac, - 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_CENTER]), - 'group': ORYX.I18N.Arrangement.groupA, - 'icon': ORYX.PATH + "images/shape_align_center.png", - 'description': ORYX.I18N.Arrangement.acDesc, - 'index': 2, - 'minShape': 2}); + } - - this.facade.offer({ - 'name':ORYX.I18N.Arrangement.as, - 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_SIZE]), - 'group': ORYX.I18N.Arrangement.groupA, - 'icon': ORYX.PATH + "images/shape_align_size.png", - 'description': ORYX.I18N.Arrangement.asDesc, - 'index': 3, - 'minShape': 2}); - + //if( this.changes[options.id]){ + // this.hide( options ) + //} - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_ARRANGEMENT_TOP, this.setZLevel.bind(this, this.setToTop) ); - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_ARRANGEMENT_BACK, this.setZLevel.bind(this, this.setToBack) ); - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_ARRANGEMENT_FORWARD, this.setZLevel.bind(this, this.setForward) ); - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_ARRANGEMENT_BACKWARD, this.setZLevel.bind(this, this.setBackward) ); + // Checked if attributes are setted + if (options.attributes) { - - }, - - onSelectionChanged: function(elemnt){ - var selection = this.facade.getSelection(); - if (selection.length === 1 && selection[0] instanceof ORYX.Core.Edge) { - this.setToTop(selection); - } - }, - - setZLevel:function(callback, event){ - - //Command-Pattern for dragging one docker - var zLevelCommand = ORYX.Core.Command.extend({ - construct: function(callback, elements, facade){ - this.callback = callback; - this.elements = elements; - // For redo, the previous elements get stored - this.elAndIndex = elements.map(function(el){ return {el:el, previous:el.parent.children[el.parent.children.indexOf(el)-1]} }) - this.facade = facade; - }, - execute: function(){ - - // Call the defined z-order callback with the elements - this.callback( this.elements ) - this.facade.setSelection( this.elements ) - }, - rollback: function(){ - - // Sort all elements on the index of there containment - var sortedEl = this.elAndIndex.sortBy( function( el ) { - var value = el.el; - var t = $A(value.node.parentNode.childNodes); - return t.indexOf(value.node); - }); - - // Every element get setted back bevor the old previous element - for(var i=0; i maxSize.width) { - newBounds.a.x = shape.bounds.upperLeft().x - - (maxSize.width - shape.bounds.width())/2; - - newBounds.b.x = shape.bounds.lowerRight().x + (maxSize.width - shape.bounds.width())/2 - } - - /* If the new height of shape exceeds the maximum height, set height value to maximum. */ - if(this.maxHeight > maxSize.height) { - newBounds.a.y = shape.bounds.upperLeft().y - - (maxSize.height - shape.bounds.height())/2; - - newBounds.b.y = shape.bounds.lowerRight().y + (maxSize.height - shape.bounds.height())/2 - } - - /* set bounds of shape */ - shape.bounds.set(newBounds); - - }, - execute: function(){ - // align each shape according to the way that was specified. - this.elements.each(function(shape, index) { - this.orgPos[index] = shape.bounds.upperLeft(); - - var relBounds = this.bounds.clone(); - var newCoordinates; - if (shape.parent && !(shape.parent instanceof ORYX.Core.Canvas) ) { - var upL = shape.parent.absoluteBounds().upperLeft(); - relBounds.moveBy(-upL.x, -upL.y); - } - - switch (this.way) { - // align the shapes in the requested way. - case ORYX.CONFIG.EDITOR_ALIGN_BOTTOM: - newCoordinates = { - x: shape.bounds.upperLeft().x, - y: relBounds.b.y - shape.bounds.height() - }; break; - - case ORYX.CONFIG.EDITOR_ALIGN_MIDDLE: - newCoordinates = { - x: shape.bounds.upperLeft().x, - y: (relBounds.a.y + relBounds.b.y - shape.bounds.height()) / 2 - }; break; - - case ORYX.CONFIG.EDITOR_ALIGN_TOP: - newCoordinates = { - x: shape.bounds.upperLeft().x, - y: relBounds.a.y - }; break; - - case ORYX.CONFIG.EDITOR_ALIGN_LEFT: - newCoordinates = { - x: relBounds.a.x, - y: shape.bounds.upperLeft().y - }; break; - - case ORYX.CONFIG.EDITOR_ALIGN_CENTER: - newCoordinates = { - x: (relBounds.a.x + relBounds.b.x - shape.bounds.width()) / 2, - y: shape.bounds.upperLeft().y - }; break; - - case ORYX.CONFIG.EDITOR_ALIGN_RIGHT: - newCoordinates = { - x: relBounds.b.x - shape.bounds.width(), - y: shape.bounds.upperLeft().y - }; break; - - case ORYX.CONFIG.EDITOR_ALIGN_SIZE: - if(shape.isResizable) { - this.orgPos[index] = {a: shape.bounds.upperLeft(), b: shape.bounds.lowerRight()}; - this.setBounds(shape, shape.maximumSize); - } - break; - } - - if (newCoordinates){ - var offset = { - x: shape.bounds.upperLeft().x - newCoordinates.x, - y: shape.bounds.upperLeft().y - newCoordinates.y - } - // Set the new position - shape.bounds.moveTo(newCoordinates); - this.plugin.layoutEdges(shape, shape.getAllDockedShapes(),offset); - //shape.update() - } - }.bind(this)); - - //this.facade.getCanvas().update(); - //this.facade.updateSelection(); - }, - rollback: function(){ - this.elements.each(function(shape, index) { - if (this.way == ORYX.CONFIG.EDITOR_ALIGN_SIZE) { - if(shape.isResizable) {shape.bounds.set(this.orgPos[index]);} - } else {shape.bounds.moveTo(this.orgPos[index]);} - }.bind(this)); - - //this.facade.getCanvas().update(); - //this.facade.updateSelection(); - } - }) - - var command = new commandClass(elements, bounds, maxHeight, maxWidth, parseInt(way), this); - - this.facade.executeCommands([command]); - } -});/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + _temp.svg.setAttributeNS(null, "transform", "translate(" + x + ", " + y + ")") -if (!ORYX.Plugins) - ORYX.Plugins = new Object(); + }.bind(this) -ORYX.Plugins.Save = Clazz.extend({ - - facade: undefined, - - processURI: undefined, - - changeSymbol : "*", - - construct: function(facade){ - this.facade = facade; - - document.addEventListener("keydown", function (e) { - if (e.ctrlKey&&e.keyCode === 83){ - Event.stop(e); - } - }, false); - - window.onbeforeunload = this.onUnLoad.bind(this); - - this.changeDifference = 0; - - // Register on event for executing commands --> store all commands in a stack - // --> Execute - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_UNDO_EXECUTE, function() { this.changeDifference++; this.updateTitle(); }.bind(this) ); - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_EXECUTE_COMMANDS, function() { this.changeDifference++; this.updateTitle(); }.bind(this) ); - // --> Saved from other places in the editor - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_SAVED, function() { this.changeDifference = 0; this.updateTitle(); }.bind(this) ); - - // --> Rollback - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_UNDO_ROLLBACK, function() { this.changeDifference--; this.updateTitle(); }.bind(this) ); - - //TODO very critical for load time performance!!! - //this.serializedDOM = DataManager.__persistDOM(this.facade); - - this.hasChanges = this._hasChanges.bind(this); - }, - - updateTitle: function(){ - - var value = window.document.title || document.getElementsByTagName("title")[0].childNodes[0].nodeValue; - - if (this.changeDifference === 0 && value.startsWith(this.changeSymbol)){ - window.document.title = value.slice(1); - } else if (this.changeDifference !== 0 && !value.startsWith(this.changeSymbol)){ - window.document.title = this.changeSymbol + "" + value; - } - }, - - _hasChanges: function() { - return this.changeDifference !== 0 || (this.facade.getModelMetaData()['new'] && this.facade.getCanvas().getChildShapes().size() > 0); - }, - - onUnLoad: function(){ - if(this._hasChanges()) { - return ORYX.I18N.Save.unsavedData; - } - } -}); -/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + _temp.element = el; + _temp.callback(); -if(!ORYX.Plugins) - ORYX.Plugins = new Object(); + b.registerCallback(_temp.callback); -ORYX.Plugins.DragDropResize = ORYX.Plugins.AbstractPlugin.extend({ + } - /** - * Constructor - * @param {Object} Facade: The Facade of the Editor - */ - construct: function(facade) { - this.facade = facade; - - // Initialize variables - this.currentShapes = []; // Current selected Shapes - //this.pluginsData = []; // Available Plugins - this.toMoveShapes = []; // Shapes there will be moved - this.distPoints = []; // Distance Points for Snap on Grid - this.isResizing = false; // Flag: If there was currently resized - this.dragEnable = false; // Flag: If Dragging is enabled - this.dragIntialized = false; // Flag: If the Dragging is initialized - this.edgesMovable = true; // Flag: If an edge is docked it is not movable - this.offSetPosition = {x: 0, y: 0}; // Offset of the Dragging - this.faktorXY = {x: 1, y: 1}; // The Current Zoom-Faktor - this.containmentParentNode; // the current future parent node for the dragged shapes - this.isAddingAllowed = false; // flag, if adding current selected shapes to containmentParentNode is allowed - this.isAttachingAllowed = false; // flag, if attaching to the current shape is allowed - - this.callbackMouseMove = this.handleMouseMove.bind(this); - this.callbackMouseUp = this.handleMouseUp.bind(this); - - // Get the SVG-Containernode - var containerNode = this.facade.getCanvas().getSvgContainer(); - - // Create the Selected Rectangle in the SVG - this.selectedRect = new ORYX.Plugins.SelectedRect(containerNode); - - // Show grid line if enabled - if (ORYX.CONFIG.SHOW_GRIDLINE) { - this.vLine = new ORYX.Plugins.GridLine(containerNode, ORYX.Plugins.GridLine.DIR_VERTICAL); - this.hLine = new ORYX.Plugins.GridLine(containerNode, ORYX.Plugins.GridLine.DIR_HORIZONTAL); - } - - // Get a HTML-ContainerNode - containerNode = this.facade.getCanvas().getHTMLContainer(); - - this.scrollNode = this.facade.getCanvas().rootNode.parentNode.parentNode; - - // Create the southeastern button for resizing - this.resizerSE = new ORYX.Plugins.Resizer(containerNode, "southeast", this.facade); - this.resizerSE.registerOnResize(this.onResize.bind(this)); // register the resize callback - this.resizerSE.registerOnResizeEnd(this.onResizeEnd.bind(this)); // register the resize end callback - this.resizerSE.registerOnResizeStart(this.onResizeStart.bind(this)); // register the resize start callback - - // Create the northwestern button for resizing - this.resizerNW = new ORYX.Plugins.Resizer(containerNode, "northwest", this.facade); - this.resizerNW.registerOnResize(this.onResize.bind(this)); // register the resize callback - this.resizerNW.registerOnResizeEnd(this.onResizeEnd.bind(this)); // register the resize end callback - this.resizerNW.registerOnResizeStart(this.onResizeStart.bind(this)); // register the resize start callback - - // For the Drag and Drop - // Register on MouseDown-Event on a Shape - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEDOWN, this.handleMouseDown.bind(this)); - }, - /** - * On Mouse Down - * - */ - handleMouseDown: function(event, uiObj) { - // If the selection Bounds not intialized and the uiObj is not member of current selectio - // then return - if(!this.dragBounds || !this.currentShapes.member(uiObj) || !this.toMoveShapes.length) {return;}; - - // Start Dragging - this.dragEnable = true; - this.dragIntialized = true; - this.edgesMovable = true; - - // Calculate the current zoom factor - var a = this.facade.getCanvas().node.getScreenCTM(); - this.faktorXY.x = a.a; - this.faktorXY.y = a.d; - - var eventX = Event.pointerX(event); - var eventY = Event.pointerY(event); - - // Set the offset position of dragging - var upL = this.dragBounds.upperLeft(); - this.offSetPosition = { - x: eventX - (upL.x * this.faktorXY.x), - y: eventY - (upL.y * this.faktorXY.y)}; - - this.offsetScroll = {x:this.scrollNode.scrollLeft,y:this.scrollNode.scrollTop}; - - // Register on Global Mouse-MOVE Event - document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.callbackMouseMove, false); - // Register on Global Mouse-UP Event - document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.callbackMouseUp, true); - - return; - }, + options._temps.push(_temp) - /** - * On Key Mouse Up - * - */ - handleMouseUp: function(event) { - - //disable containment highlighting - this.facade.raiseEvent({ - type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, - highlightId:"dragdropresize.contain" - }); - - this.facade.raiseEvent({ - type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, - highlightId:"dragdropresize.attached" - }); - - // If Dragging is finished - if(this.dragEnable) { - - // and update the current selection - if(!this.dragIntialized) { - - // Do Method after Dragging - this.afterDrag(); - - // Check if the Shape is allowed to dock to the other Shape - if ( this.isAttachingAllowed && - this.toMoveShapes.length == 1 && this.toMoveShapes[0] instanceof ORYX.Core.Node && - this.toMoveShapes[0].dockers.length > 0) { - - // Get the position and the docker - var position = this.facade.eventCoordinates( event ); - var docker = this.toMoveShapes[0].dockers[0]; - - - - //Command-Pattern for dragging several Shapes - var dockCommand = ORYX.Core.Command.extend({ - construct: function(docker, position, newDockedShape, facade){ - this.docker = docker; - this.newPosition = position; - this.newDockedShape = newDockedShape; - this.newParent = newDockedShape.parent || facade.getCanvas(); - this.oldPosition = docker.parent.bounds.center(); - this.oldDockedShape = docker.getDockedShape(); - this.oldParent = docker.parent.parent || facade.getCanvas(); - this.facade = facade; - - if( this.oldDockedShape ){ - this.oldPosition = docker.parent.absoluteBounds().center(); - } - - }, - execute: function(){ - this.dock( this.newDockedShape, this.newParent, this.newPosition ); - - // Raise Event for having the docked shape on top of the other shape - this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_ARRANGEMENT_TOP, excludeCommand: true}) - }, - rollback: function(){ - this.dock( this.oldDockedShape, this.oldParent, this.oldPosition ); - }, - dock:function( toDockShape, parent, pos ){ - // Add to the same parent Shape - parent.add( this.docker.parent ) - - - // Set the Docker to the new Shape - this.docker.setDockedShape( undefined ); - this.docker.bounds.centerMoveTo( pos ) - this.docker.setDockedShape( toDockShape ); - //this.docker.update(); - - this.facade.setSelection( [this.docker.parent] ); - this.facade.getCanvas().update(); - this.facade.updateSelection(); - - - } - }); - - // Instanziate the dockCommand - var commands = [new dockCommand(docker, position, this.containmentParentNode, this.facade)]; - this.facade.executeCommands(commands); - - - // Check if adding is allowed to the other Shape - } else if( this.isAddingAllowed ) { - - - // Refresh all Shapes --> Set the new Bounds - this.refreshSelectedShapes(); - - } - - this.facade.updateSelection(); - - //this.currentShapes.each(function(shape) {shape.update()}) - // Raise Event: Dragging is finished - this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_DRAGDROP_END}); - } - - if (this.vLine) - this.vLine.hide(); - if (this.hLine) - this.hLine.hide(); - } + }.bind(this)) - // Disable - this.dragEnable = false; - - // UnRegister on Global Mouse-UP/-Move Event - document.documentElement.removeEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.callbackMouseUp, true); - document.documentElement.removeEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.callbackMouseMove, false); - - return; - }, + } - /** - * On Key Mouse Move - * - */ - handleMouseMove: function(event) { - // If dragging is not enabled, go return - if(!this.dragEnable) { return }; - // If Dragging is initialized - if(this.dragIntialized) { - // Raise Event: Drag will be started - this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_DRAGDROP_START}); - this.dragIntialized = false; - - // And hide the resizers and the highlighting - this.resizerSE.hide(); - this.resizerNW.hide(); - - // if only edges are selected, containmentParentNode must be the canvas - this._onlyEdges = this.currentShapes.all(function(currentShape) { - return (currentShape instanceof ORYX.Core.Edge); - }); - - // Do method before Drag - this.beforeDrag(); - - this._currentUnderlyingNodes = []; - - } - - // Calculate the new position - var position = { - x: Event.pointerX(event) - this.offSetPosition.x, - y: Event.pointerY(event) - this.offSetPosition.y} - - position.x -= this.offsetScroll.x - this.scrollNode.scrollLeft; - position.y -= this.offsetScroll.y - this.scrollNode.scrollTop; - - // If not the Control-Key are pressed - var modifierKeyPressed = event.shiftKey || event.ctrlKey; - if(ORYX.CONFIG.GRID_ENABLED && !modifierKeyPressed) { - // Snap the current position to the nearest Snap-Point - position = this.snapToGrid(position); - } else { - if (this.vLine) - this.vLine.hide(); - if (this.hLine) - this.hLine.hide(); - } + // Store the changes + if (!this.changes[options.id]) { + this.changes[options.id] = []; + } + + this.changes[options.id].push(options); + + }, + + /** + * Hide the overlay with the spefic id + * @param {Object} options + */ + hide: function (options) { - // Adjust the point by the zoom faktor - position.x /= this.faktorXY.x; - position.y /= this.faktorXY.y; + // Checks if all arguments are available + if (!options || + !options.id || !options.id instanceof String || options.id.length == 0 || + !this.changes[options.id]) { - // Set that the position is not lower than zero - position.x = Math.max( 0 , position.x) - position.y = Math.max( 0 , position.y) + return - // Set that the position is not bigger than the canvas - var c = this.facade.getCanvas(); - position.x = Math.min( c.bounds.width() - this.dragBounds.width(), position.x) - position.y = Math.min( c.bounds.height() - this.dragBounds.height(), position.y) - + } - // Drag this bounds - this.dragBounds.moveTo(position); - // Update all selected shapes and the selection rectangle - //this.refreshSelectedShapes(); - this.resizeRectangle(this.dragBounds); + // Delete all added attributes + // FOR EACH - Shape + this.changes[options.id].each(function (option) { - this.isAttachingAllowed = false; + option.shapes.each(function (el, index) { - //check, if a node can be added to the underlying node - var eventCoordinates = this.facade.eventCoordinates(event); - - var additionalIEZoom = 1; - if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { - var ua = navigator.userAgent; - if (ua.indexOf('MSIE') >= 0) { - //IE 10 and below - var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); - if (zoom !== 100) { - additionalIEZoom = zoom / 100 + // Checks if the node is a Shape + if (!el instanceof ORYX.Core.Shape) { + return } - } - } - - if (additionalIEZoom !== 1) { - eventCoordinates.x = eventCoordinates.x / additionalIEZoom; - eventCoordinates.y = eventCoordinates.y / additionalIEZoom; - } - - var underlyingNodes = $A(this.facade.getCanvas().getAbstractShapesAtPosition(eventCoordinates)); - - var checkIfAttachable = this.toMoveShapes.length == 1 && this.toMoveShapes[0] instanceof ORYX.Core.Node && this.toMoveShapes[0].dockers.length > 0 - checkIfAttachable = checkIfAttachable && underlyingNodes.length != 1 - - - if (!checkIfAttachable && - underlyingNodes.length === this._currentUnderlyingNodes.length && - underlyingNodes.all(function(node, index){return this._currentUnderlyingNodes[index] === node}.bind(this))) { - - return - - } else if(this._onlyEdges) { - - this.isAddingAllowed = true; - this.containmentParentNode = this.facade.getCanvas(); - - } else { - - /* Check the containment and connection rules */ - var options = { - event : event, - underlyingNodes : underlyingNodes, - checkIfAttachable : checkIfAttachable - }; - this.checkRules(options); - - } - - this._currentUnderlyingNodes = underlyingNodes.reverse(); - - //visualize the containment result - if( this.isAttachingAllowed ) { - - this.facade.raiseEvent({ - type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, - highlightId: "dragdropresize.attached", - elements: [this.containmentParentNode], - style: ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE, - color: ORYX.CONFIG.SELECTION_VALID_COLOR - }); - - } else { - - this.facade.raiseEvent({ - type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, - highlightId:"dragdropresize.attached" - }); - } - - if( !this.isAttachingAllowed ){ - if( this.isAddingAllowed ) { - this.facade.raiseEvent({ - type:ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, - highlightId:"dragdropresize.contain", - elements:[this.containmentParentNode], - color: ORYX.CONFIG.SELECTION_VALID_COLOR - }); + this.deleteAttributes(el.node) - } else { + }.bind(this)); - this.facade.raiseEvent({ - type:ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, - highlightId:"dragdropresize.contain", - elements:[this.containmentParentNode], - color: ORYX.CONFIG.SELECTION_INVALID_COLOR - }); - } - } else { - this.facade.raiseEvent({ - type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, - highlightId:"dragdropresize.contain" - }); - } - - // Stop the Event - //Event.stop(event); - return; - }, - -// /** -// * Rollbacks the docked shape of an edge, if the edge is not movable. -// */ -// redockEdges: function() { -// this._undockedEdgesCommand.dockers.each(function(el){ -// el.docker.setDockedShape(el.dockedShape); -// el.docker.setReferencePoint(el.refPoint); -// }) -// }, - - /** - * Checks the containment and connection rules for the selected shapes. - */ - checkRules : function(options) { - var event = options.event; - var underlyingNodes = options.underlyingNodes; - var checkIfAttachable = options.checkIfAttachable; - var noEdges = options.noEdges; - - //get underlying node that is not the same than one of the currently selected shapes or - // a child of one of the selected shapes with the highest z Order. - // The result is a shape or the canvas - this.containmentParentNode = underlyingNodes.reverse().find((function(node) { - return (node instanceof ORYX.Core.Canvas) || - (((node instanceof ORYX.Core.Node) || ((node instanceof ORYX.Core.Edge) && !noEdges)) - && (!(this.currentShapes.member(node) || - this.currentShapes.any(function(shape) { - return (shape.children.length > 0 && shape.getChildNodes(true).member(node)); - })))); - }).bind(this)); - - if( checkIfAttachable ){ - - this.isAttachingAllowed = this.facade.getRules().canConnect({ - sourceShape: this.containmentParentNode, - edgeShape: this.toMoveShapes[0], - targetShape: this.toMoveShapes[0] - }); - - if ( this.isAttachingAllowed ) { - var point = this.facade.eventCoordinates(event); - this.isAttachingAllowed = this.containmentParentNode.isPointOverOffset( point.x, point.y ); - } - } - - if( !this.isAttachingAllowed ){ - //check all selected shapes, if they can be added to containmentParentNode - this.isAddingAllowed = this.toMoveShapes.all((function(currentShape) { - if(currentShape instanceof ORYX.Core.Edge || - currentShape instanceof ORYX.Core.Controls.Docker || - this.containmentParentNode === currentShape.parent) { - return true; - } else if(this.containmentParentNode !== currentShape) { - - if(!(this.containmentParentNode instanceof ORYX.Core.Edge) || !noEdges) { - - if(this.facade.getRules().canContain({containingShape:this.containmentParentNode, - containedShape:currentShape})) { - return true; - } - } - } - return false; - }).bind(this)); - } - - if(!this.isAttachingAllowed && !this.isAddingAllowed && - (this.containmentParentNode instanceof ORYX.Core.Edge)) { - options.noEdges = true; - options.underlyingNodes.reverse(); - this.checkRules(options); - } - }, - - /** - * Redraw the selected Shapes. - * - */ - refreshSelectedShapes: function() { - // If the selection bounds not initialized, return - if(!this.dragBounds) {return} - - // Calculate the offset between the bounds and the old bounds - var upL = this.dragBounds.upperLeft(); - var oldUpL = this.oldDragBounds.upperLeft(); - var offset = { - x: upL.x - oldUpL.x, - y: upL.y - oldUpL.y }; - - // Instanciate the dragCommand - var commands = [new ORYX.Core.Command.Move(this.toMoveShapes, offset, this.containmentParentNode, this.currentShapes, this)]; - // If the undocked edges command is setted, add this command - if( this._undockedEdgesCommand instanceof ORYX.Core.Command ){ - commands.unshift( this._undockedEdgesCommand ); - } - // Execute the commands - this.facade.executeCommands( commands ); + if (option._temps) { + + option._temps.each(function (tmp) { + // Delete the added Node, if there is one + if (tmp.svg && tmp.svg.parentNode) { + tmp.svg.parentNode.removeChild(tmp.svg) + } + + // If + if (tmp.callback && tmp.element) { + // It has to be unregistered from the edge + tmp.element.bounds.unregisterCallback(tmp.callback) + } + + }.bind(this)) + + } - // copy the bounds to the old bounds - if( this.dragBounds ) - this.oldDragBounds = this.dragBounds.clone(); - }, - - /** - * Callback for Resize - * - */ - onResize: function(bounds) { - // If the selection bounds not initialized, return - if(!this.dragBounds) {return} - - this.dragBounds = bounds; - this.isResizing = true; - - // Update the rectangle - this.resizeRectangle(this.dragBounds); - }, - - onResizeStart: function() { - this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_RESIZE_START}); - }, + }.bind(this)); - onResizeEnd: function() { - - if (!(this.currentShapes instanceof Array)||this.currentShapes.length<=0) { - return; - } - - // If Resizing finished, the Shapes will be resize - if(this.isResizing) { - - var commandClass = ORYX.Core.Command.extend({ - construct: function(shape, newBounds, plugin){ - this.shape = shape; - this.oldBounds = shape.bounds.clone(); - this.newBounds = newBounds; - this.plugin = plugin; - }, - execute: function(){ - this.shape.bounds.set(this.newBounds.a, this.newBounds.b); - this.update(this.getOffset(this.oldBounds, this.newBounds)); - - }, - rollback: function(){ - this.shape.bounds.set(this.oldBounds.a, this.oldBounds.b); - this.update(this.getOffset(this.newBounds, this.oldBounds)) - }, - - getOffset:function(b1, b2){ - return { - x: b2.a.x - b1.a.x, - y: b2.a.y - b1.a.y, - xs: b2.width()/b1.width(), - ys: b2.height()/b1.height() - } - }, - update:function(offset){ - this.shape.getLabels().each(function(label) { - label.changed(); - }); - - var allEdges = [].concat(this.shape.getIncomingShapes()) - .concat(this.shape.getOutgoingShapes()) - // Remove all edges which are included in the selection from the list - .findAll(function(r){ return r instanceof ORYX.Core.Edge }.bind(this)) - - this.plugin.layoutEdges(this.shape, allEdges, offset); - - this.plugin.facade.setSelection([this.shape]); - this.plugin.facade.getCanvas().update(); - this.plugin.facade.updateSelection(); - } - }); - - var bounds = this.dragBounds.clone(); - var shape = this.currentShapes[0]; - - if(shape.parent) { - var parentPosition = shape.parent.absoluteXY(); - bounds.moveBy(-parentPosition.x, -parentPosition.y); - } - - var command = new commandClass(shape, bounds, this); - - this.facade.executeCommands([command]); - - this.isResizing = false; - - this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_RESIZE_END}); - } - }, - - /** - * Prepare the Dragging - * - */ - beforeDrag: function(){ - - var undockEdgeCommand = ORYX.Core.Command.extend({ - construct: function(moveShapes){ - this.dockers = moveShapes.collect(function(shape){ return shape instanceof ORYX.Core.Controls.Docker ? {docker:shape, dockedShape:shape.getDockedShape(), refPoint:shape.referencePoint} : undefined }).compact(); - }, - execute: function(){ - this.dockers.each(function(el){ - el.docker.setDockedShape(undefined); - }) - }, - rollback: function(){ - this.dockers.each(function(el){ - el.docker.setDockedShape(el.dockedShape); - el.docker.setReferencePoint(el.refPoint); - //el.docker.update(); - }) - } - }); - - this._undockedEdgesCommand = new undockEdgeCommand( this.toMoveShapes ); - this._undockedEdgesCommand.execute(); - - }, + this.changes[options.id] = null; - hideAllLabels: function(shape) { - - // Hide all labels from the shape - shape.getLabels().each(function(label) { - label.hide(); - }); - // Hide all labels from docked shapes - shape.getAllDockedShapes().each(function(dockedShape) { - var labels = dockedShape.getLabels(); - if(labels.length > 0) { - labels.each(function(label) { - label.hide(); - }); - } - }); - // Do this recursive for all child shapes - // EXP-NICO use getShapes - shape.getChildren().each((function(value) { - if(value instanceof ORYX.Core.Shape) - this.hideAllLabels(value); - }).bind(this)); - }, + }, - /** - * Finished the Dragging - * - */ - afterDrag: function(){ - - }, - /** - * Show all Labels at these shape - * - */ - showAllLabels: function(shape) { - - // Show the label of these shape - //shape.getLabels().each(function(label) { - for(var i=0; i 0) { - labels.each(function(label) { - label.show(); - }); - } - }//); - - // Do this recursive - //shape.children.each((function(value) { - for(var i=0; i 2 && hasF && hasL){ - this.toMoveShapes = this.toMoveShapes.concat(dks.findAll(function(el,index){ return index > 0 && index < dks.length-1})); - } - - }).bind(this)); - - // Calculate the new area-bounds of the selection - var newBounds = undefined; - this.toMoveShapes.each(function(value) { - var shape = value; - if(value instanceof ORYX.Core.Controls.Docker) { - /* Get the Shape */ - shape = value.parent; - } - - if(!newBounds){ - newBounds = shape.absoluteBounds(); - } - else { - newBounds.include(shape.absoluteBounds()); - } - }.bind(this)); - - if(!newBounds){ - elements.each(function(value){ - if(!newBounds) { - newBounds = value.absoluteBounds(); - } else { - newBounds.include(value.absoluteBounds()); - } - }); - } - - // Set the new bounds - this.dragBounds = newBounds; - this.oldDragBounds = newBounds.clone(); - - // Update and show the rectangle - this.resizeRectangle(newBounds); - this.selectedRect.show(); - - // Show the resize button, if there is only one element and this is resizeable - if(elements.length == 1 && elements[0].isResizable) { - var aspectRatio = elements[0].getStencil().fixedAspectRatio() ? elements[0].bounds.width() / elements[0].bounds.height() : undefined; - this.resizerSE.setBounds(this.dragBounds, elements[0].minimumSize, elements[0].maximumSize, aspectRatio); - this.resizerSE.show(); - this.resizerNW.setBounds(this.dragBounds, elements[0].minimumSize, elements[0].maximumSize, aspectRatio); - this.resizerNW.show(); - } else { - this.resizerSE.setBounds(undefined); - this.resizerNW.setBounds(undefined); - } + var ids = [] - // If Snap-To-Grid is enabled, the Snap-Point will be calculate - if(ORYX.CONFIG.GRID_ENABLED) { - - // Reset all points - this.distPoints = []; - - if (this.distPointTimeout) - window.clearTimeout(this.distPointTimeout) - - this.distPointTimeout = window.setTimeout(function(){ - // Get all the shapes, there will consider at snapping - // Consider only those elements who shares the same parent element - var distShapes = this.facade.getCanvas().getChildShapes(true).findAll(function(value){ - var parentShape = value.parent; - while(parentShape){ - if(elements.member(parentShape)) return false; - parentShape = parentShape.parent - } - return true; - }) - - // The current selection will delete from this array - //elements.each(function(shape) { - // distShapes = distShapes.without(shape); - //}); - - // For all these shapes - distShapes.each((function(value) { - if(!(value instanceof ORYX.Core.Edge)) { - var ul = value.absoluteXY(); - var width = value.bounds.width(); - var height = value.bounds.height(); - - // Add the upperLeft, center and lowerRight - Point to the distancePoints - this.distPoints.push({ - ul: { - x: ul.x, - y: ul.y - }, - c: { - x: ul.x + (width / 2), - y: ul.y + (height / 2) - }, - lr: { - x: ul.x + width, - y: ul.y + height - } - }); - } - }).bind(this)); - - }.bind(this), 10) + // Add all Attributes which have relation to another node in this document and concate the pure id out of it + // This is for example important for the markers of a edge + childs.each(function (e) { + ids.push($A(e.attributes).findAll(function (attr) { + return attr.nodeValue.startsWith('url(#') + })) + }) + ids = ids.flatten().compact(); + ids = ids.collect(function (s) { + return s.nodeValue + }).uniq(); + ids = ids.collect(function (s) { + return s.slice(5, s.length - 1) + }) + // Add the node ID to the id + ids.unshift(node.id + ' .me') - } - } - }, + var attr = $H(attributes); + var attrValue = attr.toJSON().gsub(',', ';').gsub('"', ''); + var attrMarkerValue = attributes.stroke ? attrValue.slice(0, attrValue.length - 1) + "; fill:" + attributes.stroke + ";}" : attrValue; + var attrTextValue; + if (attributes.fill) { + var copyAttr = Object.clone(attributes); + copyAttr.fill = "black"; + attrTextValue = $H(copyAttr).toJSON().gsub(',', ';').gsub('"', ''); + } - /** - * Adjust an Point to the Snap Points - * - */ - snapToGrid: function(position) { - - // Get the current Bounds - var bounds = this.dragBounds; - - var point = {}; - - var ulThres = 6; - var cThres = 10; - var lrThres = 6; - - var scale = this.vLine ? this.vLine.getScale() : 1; - - var ul = { x: (position.x/scale), y: (position.y/scale)}; - var c = { x: (position.x/scale) + (bounds.width()/2), y: (position.y/scale) + (bounds.height()/2)}; - var lr = { x: (position.x/scale) + (bounds.width()), y: (position.y/scale) + (bounds.height())}; - - var offsetX, offsetY; - var gridX, gridY; - - // For each distant point - this.distPoints.each(function(value) { - - var x, y, gx, gy; - if (Math.abs(value.c.x-c.x) < cThres){ - x = value.c.x-c.x; - gx = value.c.x; - }/* else if (Math.abs(value.ul.x-ul.x) < ulThres){ - x = value.ul.x-ul.x; - gx = value.ul.x; - } else if (Math.abs(value.lr.x-lr.x) < lrThres){ - x = value.lr.x-lr.x; - gx = value.lr.x; - } */ - + // Create the CSS-Tags Style out of the ids and the attributes + csstags = ids.collect(function (s, i) { + return "#" + s + " * " + (!i ? attrValue : attrMarkerValue) + "" + (attrTextValue ? " #" + s + " text * " + attrTextValue : "") + }) - if (Math.abs(value.c.y-c.y) < cThres){ - y = value.c.y-c.y; - gy = value.c.y; - }/* else if (Math.abs(value.ul.y-ul.y) < ulThres){ - y = value.ul.y-ul.y; - gy = value.ul.y; - } else if (Math.abs(value.lr.y-lr.y) < lrThres){ - y = value.lr.y-lr.y; - gy = value.lr.y; - } */ + // Join all the tags + var s = csstags.join(" ") + "\n" - if (x !== undefined) { - offsetX = offsetX === undefined ? x : (Math.abs(x) < Math.abs(offsetX) ? x : offsetX); - if (offsetX === x) - gridX = gx; - } + // And add to the end of the style tag + this.styleNode.appendChild(document.createTextNode(s)); - if (y !== undefined) { - offsetY = offsetY === undefined ? y : (Math.abs(y) < Math.abs(offsetY) ? y : offsetY); - if (offsetY === y) - gridY = gy; - } - }); - - - if (offsetX !== undefined) { - ul.x += offsetX; - ul.x *= scale; - if (this.vLine&&gridX) - this.vLine.update(gridX); - } else { - ul.x = (position.x - (position.x % (ORYX.CONFIG.GRID_DISTANCE/2))); - if (this.vLine) - this.vLine.hide() - } - - if (offsetY !== undefined) { - ul.y += offsetY; - ul.y *= scale; - if (this.hLine&&gridY) - this.hLine.update(gridY); - } else { - ul.y = (position.y - (position.y % (ORYX.CONFIG.GRID_DISTANCE/2))); - if (this.hLine) - this.hLine.hide(); - } - - return ul; - }, - - showGridLine: function(){ - - }, + }, + + /** + * Deletes all attributes which are + * added in a special style sheet for that node + * @param {HTMLElement} node + */ + deleteAttributes: function (node) { + + // Get all children which contains the node id + var delEl = $A(this.styleNode.childNodes) + .findAll(function (e) { + return e.textContent.include('#' + node.id) + }); + + // Remove all of them + delEl.each(function (el) { + el.parentNode.removeChild(el); + }); + }, + + getAllChilds: function (node) { + + var childs = $A(node.childNodes) + + $A(node.childNodes).each(function (e) { + childs.push(this.getAllChilds(e)) + }.bind(this)) + + return childs.flatten(); + } - /** - * Redraw of the Rectangle of the SelectedArea - * @param {Object} bounds - */ - resizeRectangle: function(bounds) { - // Resize the Rectangle - this.selectedRect.resize(bounds); - } }); +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ +if (!ORYX.Plugins) + ORYX.Plugins = new Object(); -ORYX.Plugins.SelectedRect = Clazz.extend({ +ORYX.Plugins.KeysMove = ORYX.Plugins.AbstractPlugin.extend({ - construct: function(parentId) { + facade: undefined, - this.parentId = parentId; + construct: function (facade) { - this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", $(parentId), - ['g']); + this.facade = facade; + this.copyElements = []; - this.dashedArea = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.node, - ['rect', {x: 0, y: 0, - 'stroke-width': 1, stroke: '#777777', fill: 'none', - 'stroke-dasharray': '2,2', - 'pointer-events': 'none'}]); + //this.facade.registerOnEvent(ORYX.CONFIG.EVENT_KEYDOWN, this.keyHandler.bind(this)); - this.hide(); + // SELECT ALL + this.facade.offer({ + keyCodes: [{ + metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL], + keyCode: 65, + keyAction: ORYX.CONFIG.KEY_ACTION_DOWN + } + ], + functionality: this.selectAll.bind(this) + }); - }, + // MOVE LEFT SMALL + this.facade.offer({ + keyCodes: [{ + metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL], + keyCode: ORYX.CONFIG.KEY_CODE_LEFT, + keyAction: ORYX.CONFIG.KEY_ACTION_DOWN + } + ], + functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_LEFT, false) + }); - hide: function() { - this.node.setAttributeNS(null, 'display', 'none'); - }, + // MOVE LEFT + this.facade.offer({ + keyCodes: [{ + keyCode: ORYX.CONFIG.KEY_CODE_LEFT, + keyAction: ORYX.CONFIG.KEY_ACTION_DOWN + } + ], + functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_LEFT, true) + }); - show: function() { - this.node.setAttributeNS(null, 'display', ''); - }, + // MOVE RIGHT SMALL + this.facade.offer({ + keyCodes: [{ + metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL], + keyCode: ORYX.CONFIG.KEY_CODE_RIGHT, + keyAction: ORYX.CONFIG.KEY_ACTION_DOWN + } + ], + functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_RIGHT, false) + }); - resize: function(bounds) { - var upL = bounds.upperLeft(); + // MOVE RIGHT + this.facade.offer({ + keyCodes: [{ + keyCode: ORYX.CONFIG.KEY_CODE_RIGHT, + keyAction: ORYX.CONFIG.KEY_ACTION_DOWN + } + ], + functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_RIGHT, true) + }); - var padding = ORYX.CONFIG.SELECTED_AREA_PADDING; + // MOVE UP SMALL + this.facade.offer({ + keyCodes: [{ + metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL], + keyCode: ORYX.CONFIG.KEY_CODE_UP, + keyAction: ORYX.CONFIG.KEY_ACTION_DOWN + } + ], + functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_UP, false) + }); - this.dashedArea.setAttributeNS(null, 'width', bounds.width() + 2*padding); - this.dashedArea.setAttributeNS(null, 'height', bounds.height() + 2*padding); - this.node.setAttributeNS(null, 'transform', "translate("+ (upL.x - padding) +", "+ (upL.y - padding) +")"); - } + // MOVE UP + this.facade.offer({ + keyCodes: [{ + keyCode: ORYX.CONFIG.KEY_CODE_UP, + keyAction: ORYX.CONFIG.KEY_ACTION_DOWN + } + ], + functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_UP, true) + }); + // MOVE DOWN SMALL + this.facade.offer({ + keyCodes: [{ + metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL], + keyCode: ORYX.CONFIG.KEY_CODE_DOWN, + keyAction: ORYX.CONFIG.KEY_ACTION_DOWN + } + ], + functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_DOWN, false) + }); -}); + // MOVE DOWN + this.facade.offer({ + keyCodes: [{ + keyCode: ORYX.CONFIG.KEY_CODE_DOWN, + keyAction: ORYX.CONFIG.KEY_ACTION_DOWN + } + ], + functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_DOWN, true) + }); + }, -ORYX.Plugins.GridLine = Clazz.extend({ - - construct: function(parentId, direction) { + /** + * Select all shapes in the editor + * + */ + selectAll: function (e) { + Event.stop(e.event); + this.facade.setSelection(this.facade.getCanvas().getChildShapes(true)) + }, - if (ORYX.Plugins.GridLine.DIR_HORIZONTAL !== direction && ORYX.Plugins.GridLine.DIR_VERTICAL !== direction) { - direction = ORYX.Plugins.GridLine.DIR_HORIZONTAL - } - - - this.parent = $(parentId); - this.direction = direction; - this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.parent, - ['g']); + move: function (key, far, e) { - this.line = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.node, - ['path', { - 'stroke-width': 1, stroke: 'silver', fill: 'none', - 'stroke-dasharray': '5,5', - 'pointer-events': 'none'}]); + Event.stop(e.event); - this.hide(); + // calculate the distance to move the objects and get the selection. + var distance = far ? 20 : 5; + var selection = this.facade.getSelection(); + var currentSelection = this.facade.getSelection(); + var p = {x: 0, y: 0}; + + // switch on the key pressed and populate the point to move by. + switch (key) { + + case ORYX.CONFIG.KEY_CODE_LEFT: + p.x = -1 * distance; + break; + case ORYX.CONFIG.KEY_CODE_RIGHT: + p.x = distance; + break; + case ORYX.CONFIG.KEY_CODE_UP: + p.y = -1 * distance; + break; + case ORYX.CONFIG.KEY_CODE_DOWN: + p.y = distance; + break; + } - }, + // move each shape in the selection by the point calculated and update it. + selection = selection.findAll(function (shape) { + // Check if this shape is docked to an shape in the selection + if (shape instanceof ORYX.Core.Node && shape.dockers.length == 1 && selection.include(shape.dockers.first().getDockedShape())) { + return false + } - hide: function() { - this.node.setAttributeNS(null, 'display', 'none'); - }, + // Check if any of the parent shape is included in the selection + var s = shape.parent; + do { + if (selection.include(s)) { + return false + } + } while (s = s.parent); - show: function() { - this.node.setAttributeNS(null, 'display', ''); - }, + // Otherwise, return true + return true; - getScale: function(){ - try { - return this.parent.parentNode.transform.baseVal.getItem(0).matrix.a; - } catch(e) { - return 1; - } - }, - - update: function(pos) { - - if (this.direction === ORYX.Plugins.GridLine.DIR_HORIZONTAL) { - var y = pos instanceof Object ? pos.y : pos; - var cWidth = this.parent.parentNode.parentNode.width.baseVal.value/this.getScale(); - this.line.setAttributeNS(null, 'd', 'M 0 '+y+ ' L '+cWidth+' '+y); - } else { - var x = pos instanceof Object ? pos.x : pos; - var cHeight = this.parent.parentNode.parentNode.height.baseVal.value/this.getScale(); - this.line.setAttributeNS(null, 'd', 'M'+x+ ' 0 L '+x+' '+cHeight); - } - - this.show(); - } + }); + /* Edges must not be movable, if only edges are selected and at least + * one of them is docked. + */ + var edgesMovable = true; + var onlyEdgesSelected = selection.all(function (shape) { + if (shape instanceof ORYX.Core.Edge) { + if (shape.isDocked()) { + edgesMovable = false; + } + return true; + } + return false; + }); -}); + if (onlyEdgesSelected && !edgesMovable) { + /* Abort moving shapes */ + return; + } -ORYX.Plugins.GridLine.DIR_HORIZONTAL = "hor"; -ORYX.Plugins.GridLine.DIR_VERTICAL = "ver"; + selection = selection.map(function (shape) { + if (shape instanceof ORYX.Core.Node) { + /*if( shape.dockers.length == 1 ){ + return shape.dockers.first() + } else {*/ + return shape + //} + } else if (shape instanceof ORYX.Core.Edge) { -ORYX.Plugins.Resizer = Clazz.extend({ + var dockers = shape.dockers; - construct: function(parentId, orientation, facade) { + if (selection.include(shape.dockers.first().getDockedShape())) { + dockers = dockers.without(shape.dockers.first()) + } - this.parentId = parentId; - this.orientation = orientation; - this.facade = facade; - - this.node = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", $('canvasSection'), - ['div', {'class': 'resizer_'+ this.orientation, style:'left:0px; top:0px;position:absolute;'}]); + if (selection.include(shape.dockers.last().getDockedShape())) { + dockers = dockers.without(shape.dockers.last()) + } - this.node.addEventListener(ORYX.CONFIG.EVENT_MOUSEDOWN, this.handleMouseDown.bind(this), true); - document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.handleMouseUp.bind(this), true); - document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.handleMouseMove.bind(this), false); + return dockers - this.dragEnable = false; - this.offSetPosition = {x: 0, y: 0}; - this.bounds = undefined; + } else { + return null + } - this.canvasNode = this.facade.getCanvas().node; + }).flatten().compact(); - this.minSize = undefined; - this.maxSize = undefined; - - this.aspectRatio = undefined; + if (selection.size() > 0) { - this.resizeCallbacks = []; - this.resizeStartCallbacks = []; - this.resizeEndCallbacks = []; - this.hide(); - - // Calculate the Offset - this.scrollNode = this.node.parentNode.parentNode.parentNode; + //Stop moving at canvas borders + var selectionBounds = [this.facade.getCanvas().bounds.lowerRight().x, + this.facade.getCanvas().bounds.lowerRight().y, + 0, + 0]; + selection.each(function (s) { + selectionBounds[0] = Math.min(selectionBounds[0], s.bounds.upperLeft().x); + selectionBounds[1] = Math.min(selectionBounds[1], s.bounds.upperLeft().y); + selectionBounds[2] = Math.max(selectionBounds[2], s.bounds.lowerRight().x); + selectionBounds[3] = Math.max(selectionBounds[3], s.bounds.lowerRight().y); + }); + if (selectionBounds[0] + p.x < 0) + p.x = -selectionBounds[0]; + if (selectionBounds[1] + p.y < 0) + p.y = -selectionBounds[1]; + if (selectionBounds[2] + p.x > this.facade.getCanvas().bounds.lowerRight().x) + p.x = this.facade.getCanvas().bounds.lowerRight().x - selectionBounds[2]; + if (selectionBounds[3] + p.y > this.facade.getCanvas().bounds.lowerRight().y) + p.y = this.facade.getCanvas().bounds.lowerRight().y - selectionBounds[3]; + + if (p.x != 0 || p.y != 0) { + // Instantiate the moveCommand + var commands = [new ORYX.Core.Command.Move(selection, p, null, currentSelection, this)]; + // Execute the commands + this.facade.executeCommands(commands); + } - }, + } + }, - handleMouseDown: function(event) { - this.dragEnable = true; - - this.offsetScroll = {x:this.scrollNode.scrollLeft,y:this.scrollNode.scrollTop}; - - this.offSetPosition = { - x: Event.pointerX(event) - this.position.x, - y: Event.pointerY(event) - this.position.y}; - - this.resizeStartCallbacks.each((function(value) { - value(this.bounds); - }).bind(this)); + getUndockedCommant: function (shapes) { + + var undockEdgeCommand = ORYX.Core.Command.extend({ + construct: function (moveShapes) { + this.dockers = moveShapes.collect(function (shape) { + return shape instanceof ORYX.Core.Controls.Docker ? { + docker: shape, + dockedShape: shape.getDockedShape(), + refPoint: shape.referencePoint + } : undefined + }).compact(); + }, + execute: function () { + this.dockers.each(function (el) { + el.docker.setDockedShape(undefined); + }) + }, + rollback: function () { + this.dockers.each(function (el) { + el.docker.setDockedShape(el.dockedShape); + el.docker.setReferencePoint(el.refPoint); + //el.docker.update(); + }) + } + }); - }, + command = new undockEdgeCommand(shapes); + command.execute(); + return command; + }, - handleMouseUp: function(event) { - this.dragEnable = false; - this.containmentParentNode = null; - this.resizeEndCallbacks.each((function(value) { - value(this.bounds); - }).bind(this)); - - }, +// /** +// * The key handler for this plugin. Every action from the set of cut, copy, +// * paste and delete should be accessible trough simple keyboard shortcuts. +// * This method checks whether any event triggers one of those actions. +// * +// * @param {Object} event The keyboard event that should be analysed for +// * triggering of this plugin. +// */ +// keyHandler: function(event){ +// //TODO document what event.which is. +// +// ORYX.Log.debug("keysMove.js handles a keyEvent."); +// +// // assure we have the current event. +// if (!event) +// event = window.event; +// +// // get the currently pressed key and state of control key. +// var pressedKey = event.which || event.keyCode; +// var ctrlPressed = event.ctrlKey; +// +// // if the key is one of the arrow keys, forward to move and return. +// if ([ORYX.CONFIG.KEY_CODE_LEFT, ORYX.CONFIG.KEY_CODE_RIGHT, +// ORYX.CONFIG.KEY_CODE_UP, ORYX.CONFIG.KEY_CODE_DOWN].include(pressedKey)) { +// +// this.move(pressedKey, !ctrlPressed); +// return; +// } +// +// } - handleMouseMove: function(event) { - if(!this.dragEnable) { return } - - if(event.shiftKey || event.ctrlKey) { - this.aspectRatio = this.bounds.width() / this.bounds.height(); - } else { - this.aspectRatio = undefined; - } +}); +/* + * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ +/* + * All code Copyright 2013 KIS Consultancy all rights reserved + */ - var position = { - x: Event.pointerX(event) - this.offSetPosition.x, - y: Event.pointerY(event) - this.offSetPosition.y}; - - - position.x -= this.offsetScroll.x - this.scrollNode.scrollLeft; - position.y -= this.offsetScroll.y - this.scrollNode.scrollTop; - - position.x = Math.min( position.x, this.facade.getCanvas().bounds.width()); - position.y = Math.min( position.y, this.facade.getCanvas().bounds.height()); - - var offset = { - x: position.x - this.position.x, - y: position.y - this.position.y - }; - - if(this.aspectRatio) { - // fixed aspect ratio - newAspectRatio = (this.bounds.width()+offset.x) / (this.bounds.height()+offset.y); - if(newAspectRatio>this.aspectRatio) { - offset.x = this.aspectRatio * (this.bounds.height()+offset.y) - this.bounds.width(); - } else if(newAspectRatio this.maxSize.width) { - offset.x = -(this.maxSize.width - this.bounds.width()); - if(this.aspectRatio) - offset.y = this.aspectRatio * offset.x; - } - if(this.bounds.width()-offset.x < this.minSize.width) { - offset.x = -(this.minSize.width - this.bounds.width()); - if(this.aspectRatio) - offset.y = this.aspectRatio * offset.x; - } - if(this.bounds.height()-offset.y > this.maxSize.height) { - offset.y = -(this.maxSize.height - this.bounds.height()); - if(this.aspectRatio) - offset.x = offset.y / this.aspectRatio; - } - if(this.bounds.height()-offset.y < this.minSize.height) { - offset.y = -(this.minSize.height - this.bounds.height()); - if(this.aspectRatio) - offset.x = offset.y / this.aspectRatio; - } - - } else { // defaults to southeast - if(this.bounds.width()+offset.x > this.maxSize.width) { - offset.x = this.maxSize.width - this.bounds.width(); - if(this.aspectRatio) - offset.y = this.aspectRatio * offset.x; - } - if(this.bounds.width()+offset.x < this.minSize.width) { - offset.x = this.minSize.width - this.bounds.width(); - if(this.aspectRatio) - offset.y = this.aspectRatio * offset.x; - } - if(this.bounds.height()+offset.y > this.maxSize.height) { - offset.y = this.maxSize.height - this.bounds.height(); - if(this.aspectRatio) - offset.x = offset.y / this.aspectRatio; - } - if(this.bounds.height()+offset.y < this.minSize.height) { - offset.y = this.minSize.height - this.bounds.height(); - if(this.aspectRatio) - offset.x = offset.y / this.aspectRatio; - } - } +if (!ORYX.Plugins) { + ORYX.Plugins = {} +} +if (!ORYX.Plugins.Layouter) { + ORYX.Plugins.Layouter = {} +} - if(this.orientation==="northwest") { - this.bounds.extend({x:-offset.x, y:-offset.y}); - this.bounds.moveBy(offset); - } else { // defaults to southeast - this.bounds.extend(offset); - } +new function () { - this.update(); + /** + * Edge layouter is an implementation to layout an edge + * @class ORYX.Plugins.Layouter.EdgeLayouter + * @author Willi Tscheschner + */ + ORYX.Plugins.Layouter.EdgeLayouter = ORYX.Plugins.AbstractLayouter.extend({ - this.resizeCallbacks.each((function(value) { - value(this.bounds); - }).bind(this)); + /** + * Layout only Edges + */ + layouted: ["http://b3mn.org/stencilset/bpmn1.1#SequenceFlow", + "http://b3mn.org/stencilset/bpmn1.1#MessageFlow", + "http://b3mn.org/stencilset/timjpdl3#SequenceFlow", + "http://b3mn.org/stencilset/jbpm4#SequenceFlow", + "http://b3mn.org/stencilset/bpmn2.0#MessageFlow", + "http://b3mn.org/stencilset/bpmn2.0#SequenceFlow", + "http://b3mn.org/stencilset/bpmn2.0choreography#MessageFlow", + "http://b3mn.org/stencilset/bpmn2.0choreography#SequenceFlow", + "http://b3mn.org/stencilset/bpmn2.0conversation#ConversationLink", + "http://b3mn.org/stencilset/epc#ControlFlow", + "http://www.signavio.com/stencilsets/processmap#ProcessLink", + "http://www.signavio.com/stencilsets/organigram#connection"], - Event.stop(event); + /** + * Layout a set on edges + * @param {Object} edges + */ + layout: function (edges) { + edges.each(function (edge) { + this.doLayout(edge) + }.bind(this)) + }, - }, - - registerOnResizeStart: function(callback) { - if(!this.resizeStartCallbacks.member(callback)) { - this.resizeStartCallbacks.push(callback); - } - }, - - unregisterOnResizeStart: function(callback) { - if(this.resizeStartCallbacks.member(callback)) { - this.resizeStartCallbacks = this.resizeStartCallbacks.without(callback); - } - }, + /** + * Layout one edge + * @param {Object} edge + */ + doLayout: function (edge) { + // Get from and to node + var from = edge.getIncomingNodes()[0]; + var to = edge.getOutgoingNodes()[0]; + + // Return if one is null + if (!from || !to) { + return + } - registerOnResizeEnd: function(callback) { - if(!this.resizeEndCallbacks.member(callback)) { - this.resizeEndCallbacks.push(callback); - } - }, - - unregisterOnResizeEnd: function(callback) { - if(this.resizeEndCallbacks.member(callback)) { - this.resizeEndCallbacks = this.resizeEndCallbacks.without(callback); - } - }, - - registerOnResize: function(callback) { - if(!this.resizeCallbacks.member(callback)) { - this.resizeCallbacks.push(callback); - } - }, + var positions = this.getPositions(from, to, edge); - unregisterOnResize: function(callback) { - if(this.resizeCallbacks.member(callback)) { - this.resizeCallbacks = this.resizeCallbacks.without(callback); - } - }, + if (positions.length > 0) { + this.setDockers(edge, positions[0].a, positions[0].b); + } - hide: function() { - this.node.style.display = "none"; - }, + }, - show: function() { - if(this.bounds) - this.node.style.display = ""; - }, + /** + * Returns a set on positions which are not containt either + * in the bounds in from or to. + * @param {Object} from Shape where the edge is come from + * @param {Object} to Shape where the edge is leading to + * @param {Object} edge Edge between from and to + */ + getPositions: function (from, to, edge) { + + // Get absolute bounds + var ab = from.absoluteBounds(); + var bb = to.absoluteBounds(); + + // Get center from and to + var a = ab.center(); + var b = bb.center(); + + var am = ab.midPoint(); + var bm = bb.midPoint(); + + // Get first and last reference point + var first = Object.clone(edge.dockers.first().referencePoint); + var last = Object.clone(edge.dockers.last().referencePoint); + // Get the absolute one + var aFirst = edge.dockers.first().getAbsoluteReferencePoint(); + var aLast = edge.dockers.last().getAbsoluteReferencePoint(); + + // IF ------> + // or | + // V + // Do nothing + if (Math.abs(aFirst.x - aLast.x) < 1 || Math.abs(aFirst.y - aLast.y) < 1) { + return [] + } - setBounds: function(bounds, min, max, aspectRatio) { - this.bounds = bounds; + // Calc center position, between a and b + // depending on there weight + var m = {} + m.x = a.x < b.x ? + (((b.x - bb.width() / 2) - (a.x + ab.width() / 2)) / 2) + (a.x + ab.width() / 2) : + (((a.x - ab.width() / 2) - (b.x + bb.width() / 2)) / 2) + (b.x + bb.width() / 2); - if(!min) - min = {width: ORYX.CONFIG.MINIMUM_SIZE, height: ORYX.CONFIG.MINIMUM_SIZE}; + m.y = a.y < b.y ? + (((b.y - bb.height() / 2) - (a.y + ab.height() / 2)) / 2) + (a.y + ab.height() / 2) : + (((a.y - ab.height() / 2) - (b.y + bb.height() / 2)) / 2) + (b.y + bb.height() / 2); - if(!max) - max = {width: ORYX.CONFIG.MAXIMUM_SIZE, height: ORYX.CONFIG.MAXIMUM_SIZE}; - this.minSize = min; - this.maxSize = max; - - this.aspectRatio = aspectRatio; + // Enlarge both bounds with 10 + ab.widen(5); // Wide the from less than + bb.widen(20);// the to because of the arrow from the edge - this.update(); - }, + var positions = []; + var off = this.getOffset.bind(this); - update: function() { - if(!this.bounds) { return; } - - var upL = this.bounds.upperLeft(); - - if(this.bounds.width() < this.minSize.width) { this.bounds.set(upL.x, upL.y, upL.x + this.minSize.width, upL.y + this.bounds.height());}; - if(this.bounds.height() < this.minSize.height) { this.bounds.set(upL.x, upL.y, upL.x + this.bounds.width(), upL.y + this.minSize.height);}; - if(this.bounds.width() > this.maxSize.width) { this.bounds.set(upL.x, upL.y, upL.x + this.maxSize.width, upL.y + this.bounds.height());}; - if(this.bounds.height() > this.maxSize.height) { this.bounds.set(upL.x, upL.y, upL.x + this.bounds.width(), upL.y + this.maxSize.height);}; - - var a = this.canvasNode.getScreenCTM(); - - upL.x *= a.a; - upL.y *= a.d; - - var additionalIEZoom = 1; - if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { - var ua = navigator.userAgent; - if (ua.indexOf('MSIE') >= 0) { - //IE 10 and below - var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); - if (zoom !== 100) { - additionalIEZoom = zoom / 100 - } + // Checks ----+ + // | + // V + if (!ab.isIncluded(b.x, a.y) && !bb.isIncluded(b.x, a.y)) { + positions.push({ + a: {x: b.x + off(last, bm, "x"), y: a.y + off(first, am, "y")}, + z: this.getWeight(from, a.x < b.x ? "r" : "l", to, a.y < b.y ? "t" : "b", edge) + }); } - } - - if (additionalIEZoom === 1) { - upL.y = upL.y - jQuery("#canvasSection").offset().top + a.f; - upL.x = upL.x - jQuery("#canvasSection").offset().left + a.e; - - } else { - var canvasOffsetLeft = jQuery("#canvasSection").offset().left; - var canvasScrollLeft = jQuery("#canvasSection").scrollLeft(); - var canvasScrollTop = jQuery("#canvasSection").scrollTop(); - - var offset = a.e - (canvasOffsetLeft * additionalIEZoom); - var additionaloffset = 0; - if (offset > 10) { - additionaloffset = (offset / additionalIEZoom) - offset; - } - upL.y = upL.y - (jQuery("#canvasSection").offset().top * additionalIEZoom) + ((canvasScrollTop * additionalIEZoom) - canvasScrollTop) + a.f; - upL.x = upL.x - (canvasOffsetLeft * additionalIEZoom) + additionaloffset + ((canvasScrollLeft * additionalIEZoom) - canvasScrollLeft) + a.e; - } - - if(this.orientation==="northwest") { - upL.x -= 13; - upL.y -= 13; - } else { // defaults to southeast - upL.x += (a.a * this.bounds.width()) + 3 ; - upL.y += (a.d * this.bounds.height()) + 3; - } - - this.position = upL; - this.node.style.left = this.position.x + "px"; - this.node.style.top = this.position.y + "px"; - } -}); + // Checks | + // +---> + if (!ab.isIncluded(a.x, b.y) && !bb.isIncluded(a.x, b.y)) { + positions.push({ + a: {x: a.x + off(first, am, "x"), y: b.y + off(last, bm, "y")}, + z: this.getWeight(from, a.y < b.y ? "b" : "t", to, a.x < b.x ? "l" : "r", edge) + }); + } + // Checks --+ + // | + // +---> + if (!ab.isIncluded(m.x, a.y) && !bb.isIncluded(m.x, b.y)) { + positions.push({ + a: {x: m.x, y: a.y + off(first, am, "y")}, + b: {x: m.x, y: b.y + off(last, bm, "y")}, + z: this.getWeight(from, "r", to, "l", edge, a.x > b.x) + }); + } + // Checks | + // +---+ + // | + // V + if (!ab.isIncluded(a.x, m.y) && !bb.isIncluded(b.x, m.y)) { + positions.push({ + a: {x: a.x + off(first, am, "x"), y: m.y}, + b: {x: b.x + off(last, bm, "x"), y: m.y}, + z: this.getWeight(from, "b", to, "t", edge, a.y > b.y) + }); + } -/** - * Implements a Command to move shapes - * - */ -ORYX.Core.Command.Move = ORYX.Core.Command.extend({ - construct: function(moveShapes, offset, parent, selectedShapes, plugin){ - this.moveShapes = moveShapes; - this.selectedShapes = selectedShapes; - this.offset = offset; - this.plugin = plugin; - // Defines the old/new parents for the particular shape - this.newParents = moveShapes.collect(function(t){ return parent || t.parent }); - this.oldParents = moveShapes.collect(function(shape){ return shape.parent }); - this.dockedNodes= moveShapes.findAll(function(shape){ return shape instanceof ORYX.Core.Node && shape.dockers.length == 1}).collect(function(shape){ return {docker:shape.dockers[0], dockedShape:shape.dockers[0].getDockedShape(), refPoint:shape.dockers[0].referencePoint} }); - }, - execute: function(){ - this.dockAllShapes() - // Moves by the offset - this.move( this.offset); - // Addes to the new parents - this.addShapeToParent( this.newParents ); - // Set the selection to the current selection - this.selectCurrentShapes(); - this.plugin.facade.getCanvas().update(); - this.plugin.facade.updateSelection(); - }, - rollback: function(){ - // Moves by the inverted offset - var offset = { x:-this.offset.x, y:-this.offset.y }; - this.move( offset ); - // Addes to the old parents - this.addShapeToParent( this.oldParents ); - this.dockAllShapes(true) - - // Set the selection to the current selection - this.selectCurrentShapes(); - this.plugin.facade.getCanvas().update(); - this.plugin.facade.updateSelection(); - - }, - move:function(offset, doLayout){ - - // Move all Shapes by these offset - for(var i=0; i i || this.moveShapes.indexOf(r.dockers.last().getDockedShape()) > i}.bind(this)) - - for (var j = 0; j < allSameEdges.length; j++) { - for (var k = 1; k < allSameEdges[j].dockers.length-1; k++) { - var docker = allSameEdges[j].dockers[k]; - if (!docker.getDockedShape() && !this.moveShapes.include(docker)) { - docker.bounds.moveBy(offset); - } - } - } - - /*var i=-1; - var nodes = value.getChildShapes(true); - var allEdges = []; - while(++i "l") + */ + getWeight: function (from, d1, to, d2, edge, reverse) { - /** - * Constructor - * @param {Object} Facade: The Facade of the Editor - */ - construct: function(facade) { - this.facade = facade; - - // Set the valid and invalid color - this.VALIDCOLOR = ORYX.CONFIG.SELECTION_VALID_COLOR; - this.INVALIDCOLOR = ORYX.CONFIG.SELECTION_INVALID_COLOR; - - // Define Variables - this.shapeSelection = undefined; - this.docker = undefined; - this.dockerParent = undefined; - this.dockerSource = undefined; - this.dockerTarget = undefined; - this.lastUIObj = undefined; - this.isStartDocker = undefined; - this.isEndDocker = undefined; - this.undockTreshold = 10; - this.initialDockerPosition = undefined; - this.outerDockerNotMoved = undefined; - this.isValid = false; - - // For the Drag and Drop - // Register on MouseDown-Event on a Docker - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEDOWN, this.handleMouseDown.bind(this)); - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DOCKERDRAG, this.handleDockerDrag.bind(this)); - - - // Register on over/out to show / hide a docker - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEOVER, this.handleMouseOver.bind(this)); - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEOUT, this.handleMouseOut.bind(this)); - - - }, - - /** - * MouseOut Handler - * - */ - handleMouseOut: function(event, uiObj) { - // If there is a Docker, hide this - if(!this.docker && uiObj instanceof ORYX.Core.Controls.Docker) { - uiObj.hide(); - } else if(!this.docker && uiObj instanceof ORYX.Core.Edge) { - uiObj.dockers.each(function(docker){ - docker.hide(); - }); - } - }, + d1 = (d1 || "").toLowerCase(); + d2 = (d2 || "").toLowerCase(); - /** - * MouseOver Handler - * - */ - handleMouseOver: function(event, uiObj) { - // If there is a Docker, show this - if(!this.docker && uiObj instanceof ORYX.Core.Controls.Docker) { - uiObj.show(); - } else if(!this.docker && uiObj instanceof ORYX.Core.Edge) { - uiObj.dockers.each(function(docker){ - docker.show(); - }); - } - }, - /** - * DockerDrag Handler - * delegates the uiEvent of the drag event to the mouseDown function - */ - handleDockerDrag: function(event, uiObj) { - this.handleMouseDown(event.uiEvent, uiObj); - }, - - /** - * MouseDown Handler - * - */ - handleMouseDown: function(event, uiObj) { - // If there is a Docker - if(uiObj instanceof ORYX.Core.Controls.Docker && uiObj.isMovable) { - - /* Buffering shape selection and clear selection*/ - this.shapeSelection = this.facade.getSelection(); - this.facade.setSelection(); - - this.docker = uiObj; - this.initialDockerPosition = this.docker.bounds.center(); - this.outerDockerNotMoved = false; - this.dockerParent = uiObj.parent; - - // Define command arguments - this._commandArg = {docker:uiObj, dockedShape:uiObj.getDockedShape(), refPoint:uiObj.referencePoint || uiObj.bounds.center()}; - - // Show the Docker - this.docker.show(); - - // If the Dockers Parent is an Edge, - // and the Docker is either the first or last Docker of the Edge - if(uiObj.parent instanceof ORYX.Core.Edge && - (uiObj.parent.dockers.first() == uiObj || uiObj.parent.dockers.last() == uiObj)) { - - // Get the Edge Source or Target - if(uiObj.parent.dockers.first() == uiObj && uiObj.parent.dockers.last().getDockedShape()) { - this.dockerTarget = uiObj.parent.dockers.last().getDockedShape(); - } else if(uiObj.parent.dockers.last() == uiObj && uiObj.parent.dockers.first().getDockedShape()) { - this.dockerSource = uiObj.parent.dockers.first().getDockedShape(); - } - - } else { - // If there parent is not an Edge, undefined the Source and Target - this.dockerSource = undefined; - this.dockerTarget = undefined; - } - - this.isStartDocker = this.docker.parent.dockers.first() === this.docker; - this.isEndDocker = this.docker.parent.dockers.last() === this.docker; - - // add to canvas while dragging - this.facade.getCanvas().add(this.docker.parent); - - // Hide all Labels from Docker - this.docker.parent.getLabels().each(function(label) { - label.hide(); - }); - - var eventCoordinates = this.facade.eventCoordinates(event); - var additionalIEZoom = 1; - if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { - var ua = navigator.userAgent; - if (ua.indexOf('MSIE') >= 0) { - //IE 10 and below - var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); - if (zoom !== 100) { - additionalIEZoom = zoom / 100 - } - } + if (!["t", "r", "b", "l"].include(d1)) { + d1 = "r" } - - if (additionalIEZoom !== 1) { - eventCoordinates.x = eventCoordinates.x / additionalIEZoom; - eventCoordinates.y = eventCoordinates.y / additionalIEZoom; + if (!["t", "r", "b", "l"].include(d2)) { + d1 = "l" } - - // Undocked the Docker from current Shape - if ((!this.isStartDocker && !this.isEndDocker) || !this.docker.isDocked()) { - - this.docker.setDockedShape(undefined); - // Set the Docker to the center of the mouse pointer - this.docker.bounds.centerMoveTo(eventCoordinates); - this.dockerParent._update(); - } else { - this.outerDockerNotMoved = true; - } - - var option = {movedCallback: this.dockerMoved.bind(this), upCallback: this.dockerMovedFinished.bind(this)}; - - this.startEventPos = eventCoordinates; - - // Enable the Docker for Drag'n'Drop, give the mouseMove and mouseUp-Callback with - ORYX.Core.UIEnableDrag(event, uiObj, option); - } - }, - - /** - * Docker MouseMove Handler - * - */ - dockerMoved: function(event) { - this.outerDockerNotMoved = false; - var snapToMagnet = undefined; - - if (this.docker.parent) { - if (this.isStartDocker || this.isEndDocker) { - - // Get the EventPosition and all Shapes on these point - var evPos = this.facade.eventCoordinates(event); - - var additionalIEZoom = 1; - if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { - var ua = navigator.userAgent; - if (ua.indexOf('MSIE') >= 0) { - //IE 10 and below - var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); - if (zoom !== 100) { - additionalIEZoom = zoom / 100 - } - } - } - - if (additionalIEZoom !== 1) { - evPos.x = evPos.x / additionalIEZoom; - evPos.y = evPos.y / additionalIEZoom; - } - - if(this.docker.isDocked()) { - /* Only consider start/end dockers if they are moved over a treshold */ - var distanceDockerPointer = - ORYX.Core.Math.getDistancePointToPoint(evPos, this.initialDockerPosition); - if(distanceDockerPointer < this.undockTreshold) { - this.outerDockerNotMoved = true; - return; - } - - /* Undock the docker */ - this.docker.setDockedShape(undefined); - // Set the Docker to the center of the mouse pointer - //this.docker.bounds.centerMoveTo(evPos); - this.dockerParent._update(); - } - - var shapes = this.facade.getCanvas().getAbstractShapesAtPosition(evPos); - - // Get the top level Shape on these, but not the same as Dockers parent - var uiObj = shapes.pop(); - if (this.docker.parent === uiObj) { - uiObj = shapes.pop(); - } - - // If the top level Shape the same as the last Shape, then return - if (this.lastUIObj == uiObj) { - //return; - - // If the top level uiObj instance of Shape and this isn't the parent of the docker - } - else - if (uiObj instanceof ORYX.Core.Shape) { - - // Ask by the StencilSet if the source, the edge and the target valid connections. - if (this.docker.parent instanceof ORYX.Core.Edge) { - - var highestParent = this.getHighestParentBeforeCanvas(uiObj); - /* Ensure that the shape to dock is not a child shape - * of the same edge. - */ - if (highestParent instanceof ORYX.Core.Edge && this.docker.parent === highestParent) - { - this.isValid = false; - this.dockerParent._update(); - return; - } - this.isValid = false; - var curObj = uiObj, orgObj = uiObj; - while (!this.isValid && curObj && !(curObj instanceof ORYX.Core.Canvas)) - { - uiObj = curObj; - this.isValid = this.facade.getRules().canConnect({ - sourceShape: this.dockerSource ? // Is there a docked source - this.dockerSource : // than set this - (this.isStartDocker ? // if not and if the Docker is the start docker - uiObj : // take the last uiObj - undefined), // if not set it to undefined; - edgeShape: this.docker.parent, - targetShape: this.dockerTarget ? // Is there a docked target - this.dockerTarget : // than set this - (this.isEndDocker ? // if not and if the Docker is not the start docker - uiObj : // take the last uiObj - undefined) // if not set it to undefined; - }); - curObj = curObj.parent; - } - - // Reset uiObj if no - // valid parent is found - if (!this.isValid){ - uiObj = orgObj; - } - - } - else { - this.isValid = this.facade.getRules().canConnect({ - sourceShape: uiObj, - edgeShape: this.docker.parent, - targetShape: this.docker.parent - }); - } - - // If there is a lastUIObj, hide the magnets - if (this.lastUIObj) { - this.hideMagnets(this.lastUIObj); - } - - // If there is a valid connection, show the magnets - if (this.isValid) { - this.showMagnets(uiObj); - } - - // Set the Highlight Rectangle by these value - this.showHighlight(uiObj, this.isValid ? this.VALIDCOLOR : this.INVALIDCOLOR); - - // Buffer the current Shape - this.lastUIObj = uiObj; - } - else { - // If there is no top level Shape, then hide the highligting of the last Shape - this.hideHighlight(); - this.lastUIObj ? this.hideMagnets(this.lastUIObj) : null; - this.lastUIObj = undefined; - this.isValid = false; - } - - // Snap to the nearest Magnet - if (this.lastUIObj && this.isValid && !(event.shiftKey || event.ctrlKey)) { - snapToMagnet = this.lastUIObj.magnets.find(function(magnet){ - return magnet.absoluteBounds().isIncluded(evPos); - }); - - if (snapToMagnet) { - this.docker.bounds.centerMoveTo(snapToMagnet.absoluteCenterXY()); - //this.docker.update() - } - } - } - } - // Snap to on the nearest Docker of the same parent - if(!(event.shiftKey || event.ctrlKey) && !snapToMagnet) { - var minOffset = ORYX.CONFIG.DOCKER_SNAP_OFFSET; - var nearestX = minOffset + 1; - var nearestY = minOffset + 1; - - var dockerCenter = this.docker.bounds.center(); - - if (this.docker.parent) { - - this.docker.parent.dockers.each((function(docker){ - if (this.docker == docker) { - return - }; - - var center = docker.referencePoint ? docker.getAbsoluteReferencePoint() : docker.bounds.center(); - - nearestX = Math.abs(nearestX) > Math.abs(center.x - dockerCenter.x) ? center.x - dockerCenter.x : nearestX; - nearestY = Math.abs(nearestY) > Math.abs(center.y - dockerCenter.y) ? center.y - dockerCenter.y : nearestY; - - - }).bind(this)); - - if (Math.abs(nearestX) < minOffset || Math.abs(nearestY) < minOffset) { - nearestX = Math.abs(nearestX) < minOffset ? nearestX : 0; - nearestY = Math.abs(nearestY) < minOffset ? nearestY : 0; - - this.docker.bounds.centerMoveTo(dockerCenter.x + nearestX, dockerCenter.y + nearestY); - //this.docker.update() - } else { - - - - var previous = this.docker.parent.dockers[Math.max(this.docker.parent.dockers.indexOf(this.docker)-1, 0)]; - var next = this.docker.parent.dockers[Math.min(this.docker.parent.dockers.indexOf(this.docker)+1, this.docker.parent.dockers.length-1)]; - - if (previous && next && previous !== this.docker && next !== this.docker){ - var cp = previous.bounds.center(); - var cn = next.bounds.center(); - var cd = this.docker.bounds.center(); - - // Checks if the point is on the line between previous and next - if (ORYX.Core.Math.isPointInLine(cd.x, cd.y, cp.x, cp.y, cn.x, cn.y, 10)) { - // Get the rise - var raise = (Number(cn.y)-Number(cp.y))/(Number(cn.x)-Number(cp.x)); - // Calculate the intersection point - var intersecX = ((cp.y-(cp.x*raise))-(cd.y-(cd.x*(-Math.pow(raise,-1)))))/((-Math.pow(raise,-1))-raise); - var intersecY = (cp.y-(cp.x*raise))+(raise*intersecX); - - if(isNaN(intersecX) || isNaN(intersecY)) {return;} - - this.docker.bounds.centerMoveTo(intersecX, intersecY); - } - } - - } - } - } - //this.facade.getCanvas().update(); - this.dockerParent._update(); - }, - /** - * Docker MouseUp Handler - * - */ - dockerMovedFinished: function(event) { - - /* Reset to buffered shape selection */ - this.facade.setSelection(this.shapeSelection); - - // Hide the border - this.hideHighlight(); - - // Show all Labels from Docker - this.dockerParent.getLabels().each(function(label){ - label.show(); - //label.update(); - }); - - // If there is a last top level Shape - if(this.lastUIObj && (this.isStartDocker || this.isEndDocker)){ - // If there is a valid connection, the set as a docked Shape to them - if(this.isValid) { - - this.docker.setDockedShape(this.lastUIObj); - - this.facade.raiseEvent({ - type :ORYX.CONFIG.EVENT_DRAGDOCKER_DOCKED, - docker : this.docker, - parent : this.docker.parent, - target : this.lastUIObj - }); - } - - this.hideMagnets(this.lastUIObj); - } - - // Hide the Docker - this.docker.hide(); - - if(this.outerDockerNotMoved) { - // Get the EventPosition and all Shapes on these point - var evPos = this.facade.eventCoordinates(event); - var shapes = this.facade.getCanvas().getAbstractShapesAtPosition(evPos); - - /* Remove edges from selection */ - var shapeWithoutEdges = shapes.findAll(function(node) { - return node instanceof ORYX.Core.Node; - }); - shapes = shapeWithoutEdges.length ? shapeWithoutEdges : shapes; - this.facade.setSelection(shapes); - } else { - //Command-Pattern for dragging one docker - var dragDockerCommand = ORYX.Core.Command.extend({ - construct: function(docker, newPos, oldPos, newDockedShape, oldDockedShape, facade){ - this.docker = docker; - this.index = docker.parent.dockers.indexOf(docker); - this.newPosition = newPos; - this.newDockedShape = newDockedShape; - this.oldPosition = oldPos; - this.oldDockedShape = oldDockedShape; - this.facade = facade; - this.index = docker.parent.dockers.indexOf(docker); - this.shape = docker.parent; - - }, - execute: function(){ - if (!this.docker.parent){ - this.docker = this.shape.dockers[this.index]; - } - this.dock( this.newDockedShape, this.newPosition ); - this.removedDockers = this.shape.removeUnusedDockers(); - this.facade.updateSelection(); - }, - rollback: function(){ - this.dock( this.oldDockedShape, this.oldPosition ); - (this.removedDockers||$H({})).each(function (d) { - this.shape.add(d.value, Number(d.key)); - this.shape._update(true); - }.bind(this)); - this.facade.updateSelection(); - }, - dock:function( toDockShape, pos ){ - // Set the Docker to the new Shape - this.docker.setDockedShape( undefined ); - if( toDockShape ){ - this.docker.setDockedShape( toDockShape ); - this.docker.setReferencePoint( pos ); - //this.docker.update(); - //this.docker.parent._update(); - } else { - this.docker.bounds.centerMoveTo( pos ); - } - - this.facade.getCanvas().update(); - } - }); - - - if (this.docker.parent){ - // Instanziate the dockCommand - var command = new dragDockerCommand(this.docker, this.docker.getDockedShape() ? this.docker.referencePoint : this.docker.bounds.center(), this._commandArg.refPoint, this.docker.getDockedShape(), this._commandArg.dockedShape, this.facade); - this.facade.executeCommands( [command] ); - } - } - - // Update all Shapes - //this.facade.updateSelection(); - - // Undefined all variables - this.docker = undefined; - this.dockerParent = undefined; - this.dockerSource = undefined; - this.dockerTarget = undefined; - this.lastUIObj = undefined; - }, - - /** - * Hide the highlighting - */ - hideHighlight: function() { - this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId:'validDockedShape'}); - }, + // If reverse is set + if (reverse) { + // Reverse d1 and d2 + d1 = d1 == "t" ? "b" : (d1 == "r" ? "l" : (d1 == "b" ? "t" : (d1 == "l" ? "r" : "r"))) + d2 = d2 == "t" ? "b" : (d2 == "r" ? "l" : (d2 == "b" ? "t" : (d2 == "l" ? "r" : "r"))) + } - /** - * Show the highlighting - * - */ - showHighlight: function(uiObj, color) { - - this.facade.raiseEvent({ - type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, - highlightId:'validDockedShape', - elements: [uiObj], - color: color - }); - }, - - showMagnets: function(uiObj){ - uiObj.magnets.each(function(magnet) { - magnet.show(); - }); - }, - - hideMagnets: function(uiObj){ - uiObj.magnets.each(function(magnet) { - magnet.hide(); - }); - }, - - getHighestParentBeforeCanvas: function(shape) { - if(!(shape instanceof ORYX.Core.Shape)) {return undefined;} - - var parent = shape.parent; - while(parent && !(parent.parent instanceof ORYX.Core.Canvas)) { - parent = parent.parent; - } - - return parent; - } -}); + var weight = 0; + // Get rules for from "out" and to "in" + var dr1 = this.facade.getRules().getLayoutingRules(from, edge)["out"]; + var dr2 = this.facade.getRules().getLayoutingRules(to, edge)["in"]; + + var fromWeight = dr1[d1]; + var toWeight = dr2[d2]; + + + /** + * Return a true if the center 1 is in the same direction than center 2 + * @param {Object} direction + * @param {Object} center1 + * @param {Object} center2 + */ + var sameDirection = function (direction, center1, center2) { + switch (direction) { + case "t": + return Math.abs(center1.x - center2.x) < 2 && center1.y < center2.y + case "r": + return center1.x > center2.x && Math.abs(center1.y - center2.y) < 2 + case "b": + return Math.abs(center1.x - center2.x) < 2 && center1.y > center2.y + case "l": + return center1.x < center2.x && Math.abs(center1.y - center2.y) < 2 + default: + return false; + } + } -/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + // Check if there are same incoming edges from 'from' + var sameIncomingFrom = from + .getIncomingShapes() + .findAll(function (a) { + return a instanceof ORYX.Core.Edge + }) + .any(function (e) { + return sameDirection(d1, e.dockers[e.dockers.length - 2].bounds.center(), e.dockers.last().bounds.center()); + }); -if(!ORYX.Plugins) - ORYX.Plugins = new Object(); + // Check if there are same outgoing edges from 'to' + var sameOutgoingTo = to + .getOutgoingShapes() + .findAll(function (a) { + return a instanceof ORYX.Core.Edge + }) + .any(function (e) { + return sameDirection(d2, e.dockers[1].bounds.center(), e.dockers.first().bounds.center()); + }); -ORYX.Plugins.AddDocker = Clazz.extend({ + // If there are equivalent edges, set 0 + //fromWeight = sameIncomingFrom ? 0 : fromWeight; + //toWeight = sameOutgoingTo ? 0 : toWeight; - /** - * Constructor - * @param {Object} Facade: The Facade of the Editor - */ - construct: function(facade) { - this.facade = facade; - this.enableAdd = false; - this.enableRemove = false; - - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEDOWN, this.handleMouseDown.bind(this)); - }, - - setEnableAdd: function(enable){ - this.enableAdd = enable; - - if(this.enableAdd) { - jQuery("#add-bendpoint-button").addClass('pressed'); - } else { - jQuery("#add-bendpoint-button").removeClass('pressed'); - jQuery("#add-bendpoint-button").blur(); - } - }, - setEnableRemove: function(enable){ - this.enableRemove = enable; - - if(this.enableRemove) { - jQuery("#remove-bendpoint-button").addClass('pressed'); - } else { - jQuery("#remove-bendpoint-button").removeClass('pressed'); - jQuery("#remove-bendpoint-button").blur(); - } - }, - - enabledAdd: function(enable){ - return this.enableAdd; - }, - enabledRemove: function(){ - return this.enableRemove; - }, - - /** - * MouseDown Handler - * - */ - handleMouseDown: function(event, uiObj) { - if (this.enabledAdd() && uiObj instanceof ORYX.Core.Edge) { - this.newDockerCommand({ - edge: uiObj, - position: this.facade.eventCoordinates(event) - }); - this.setEnableAdd(false); - - } else if (this.enabledRemove() && - uiObj instanceof ORYX.Core.Controls.Docker && - uiObj.parent instanceof ORYX.Core.Edge) { - this.newDockerCommand({ - edge: uiObj.parent, - docker: uiObj - }); - this.setEnableRemove(false); - } - document.body.style.cursor = 'default'; - }, - - // Options: edge (required), position (required if add), docker (required if delete) - newDockerCommand: function(options){ - if(!options.edge) - return; + // Get the sum of "out" and the direction plus "in" and the direction + return (sameIncomingFrom || sameOutgoingTo ? 0 : fromWeight + toWeight); + }, - var commandClass = ORYX.Core.Command.extend({ - construct: function(addEnabled, deleteEnabled, edge, docker, pos, facade){ - this.addEnabled = addEnabled; - this.deleteEnabled = deleteEnabled; - this.edge = edge; - this.docker = docker; - this.pos = pos; - this.facade = facade; - }, - execute: function(){ - if (this.addEnabled) { - if (!this.docker){ - this.docker = this.edge.addDocker(this.pos); - this.index = this.edge.dockers.indexOf(this.docker); - } else { - this.edge.add(this.docker, this.index); - } - } - else if (this.deleteEnabled) { - this.index = this.edge.dockers.indexOf(this.docker); - this.pos = this.docker.bounds.center(); - this.edge.removeDocker(this.docker); - } - this.edge.getLabels().invoke("show"); - this.facade.getCanvas().update(); - this.facade.updateSelection(); - }, - rollback: function(){ - if (this.addEnabled) { - if (this.docker instanceof ORYX.Core.Controls.Docker) { - this.edge.removeDocker(this.docker); - } - } - else if (this.deleteEnabled) { - this.edge.add(this.docker, this.index); - } - this.edge.getLabels().invoke("show"); - this.facade.getCanvas().update(); - this.facade.updateSelection(); + /** + * Removes all current dockers from the node + * (except the start and end) and adds two new + * dockers, on the position a and b. + * @param {Object} edge + * @param {Object} a + * @param {Object} b + */ + setDockers: function (edge, a, b) { + if (!edge) { + return } - }) - - var command = new commandClass(this.enabledAdd(), this.enabledRemove(), options.edge, options.docker, options.position, this.facade); - - this.facade.executeCommands([command]); - } -}); + // Remove all dockers (implicit, + // start and end dockers will not removed) + edge.dockers.each(function (r) { + edge.removeDocker(r); + }); + + // For a and b (if exists), create + // a new docker and set position + [a, b].compact().each(function (pos) { + var docker = edge.createDocker(undefined, pos); + docker.bounds.centerMoveTo(pos); + }); + + // Update all dockers from the edge + edge.dockers.each(function (docker) { + docker.update() + }) + + // Update edge + //edge.refresh(); + edge._update(true); + + } + }); + + +}() /* * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. * License rights for this program may be obtained from Alfresco Software, Ltd. @@ -21735,2211 +23821,873 @@ ORYX.Plugins.AddDocker = Clazz.extend({ * All code Copyright 2013 KIS Consultancy all rights reserved */ -if(!ORYX.Plugins) - ORYX.Plugins = new Object(); +if (!ORYX.Plugins) + ORYX.Plugins = new Object(); - ORYX.Plugins.SelectionFrame = Clazz.extend({ +new function () { - construct: function(facade) { - this.facade = facade; + ORYX.Plugins.BPMN2_0 = { - // Register on MouseEvents - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEDOWN, this.handleMouseDown.bind(this)); - document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.handleMouseUp.bind(this), true); + /** + * Constructor + * @param {Object} Facade: The Facade of the Editor + */ + construct: function (facade) { + this.facade = facade; - // Some initiale variables - this.position = {x:0, y:0}; - this.size = {width:0, height:0}; - this.offsetPosition = {x: 0, y: 0}; + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DRAGDOCKER_DOCKED, this.handleDockerDocked.bind(this)); + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_PROPWINDOW_PROP_CHANGED, this.handlePropertyChanged.bind(this)); + this.facade.registerOnEvent('layout.bpmn2_0.pool', this.handleLayoutPool.bind(this)); + this.facade.registerOnEvent('layout.bpmn2_0.subprocess', this.handleSubProcess.bind(this)); + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_SHAPEREMOVED, this.handleShapeRemove.bind(this)); - // (Un)Register Mouse-Move Event - this.moveCallback = undefined; - this.offsetScroll = {x:0,y:0}; - // HTML-Node of Selection-Frame - this.node = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", $('canvasSection'), - ['div', {'class':'Oryx_SelectionFrame'}]); + this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADED, this.afterLoad.bind(this)); - this.hide(); - }, - handleMouseDown: function(event, uiObj) { - // If there is the Canvas - if( uiObj instanceof ORYX.Core.Canvas ) { - // Calculate the Offset - var scrollNode = uiObj.rootNode.parentNode.parentNode; - - var a = this.facade.getCanvas().node.getScreenCTM(); - this.offsetPosition = { - x: a.e, - y: a.f - }; - - // Set the new Position - this.setPos({ - x: Event.pointerX(event) - jQuery("#canvasSection").offset().left, - y: Event.pointerY(event) - jQuery("#canvasSection").offset().top + 5 - }); - - // Reset the size - this.resize({width:0, height:0}); - this.moveCallback = this.handleMouseMove.bind(this); - - // Register Mouse-Move Event - document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.moveCallback, false); - - this.offsetScroll = {x:scrollNode.scrollLeft,y:scrollNode.scrollTop}; - - // Show the Frame - this.show(); - } + this.namespace = undefined; + }, - Event.stop(event); - }, + /** + * Force to update every pool + */ + afterLoad: function () { + this.facade.getCanvas().getChildNodes().each(function (shape) { + if (shape.getStencil().id().endsWith("Pool")) { + this.handleLayoutPool({ + shape: shape + }); + } + }.bind(this)) + }, - handleMouseUp: function(event) { - // If there was an MouseMoving - if(this.moveCallback) { - // Hide the Frame - this.hide(); - - // Unregister Mouse-Move - document.documentElement.removeEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.moveCallback, false); - - this.moveCallback = undefined; - - var corrSVG = this.facade.getCanvas().node.getScreenCTM(); - - // Calculate the positions of the Frame - var a = { - x: this.size.width > 0 ? this.position.x : this.position.x + this.size.width, - y: this.size.height > 0 ? this.position.y : this.position.y + this.size.height - }; - - var b = { - x: a.x + Math.abs(this.size.width), - y: a.y + Math.abs(this.size.height) - }; - - var additionalIEZoom = 1; - if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { - var ua = navigator.userAgent; - if (ua.indexOf('MSIE') >= 0) { - //IE 10 and below - var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); - if (zoom !== 100) { - additionalIEZoom = zoom / 100 + /** + * If a pool is selected and contains no lane, + * a lane is created automagically + */ + onSelectionChanged: function (event) { + var selection = event.elements; + + if (selection && selection.length === 1) { + var namespace = this.getNamespace(); + var shape = selection[0]; + if (shape.getStencil().idWithoutNs() === "Pool") { + if (shape.getChildNodes().length === 0) { + // create a lane inside the selected pool + var option = { + type: namespace + "Lane", + position: {x: 0, y: 0}, + namespace: shape.getStencil().namespace(), + parent: shape + }; + this.facade.createShape(option); + this.facade.getCanvas().update(); + this.facade.setSelection([shape]); } } } - - if (additionalIEZoom === 1) { - a.x = a.x - (corrSVG.e - jQuery("#canvasSection").offset().left); - a.y = a.y - (corrSVG.f - jQuery("#canvasSection").offset().top); - b.x = b.x - (corrSVG.e - jQuery("#canvasSection").offset().left); - b.y = b.y - (corrSVG.f - jQuery("#canvasSection").offset().top); - - } else { - var canvasOffsetLeft = jQuery("#canvasSection").offset().left; - var canvasScrollLeft = jQuery("#canvasSection").scrollLeft(); - var canvasScrollTop = jQuery("#canvasSection").scrollTop(); - - var offset = a.e - (canvasOffsetLeft * additionalIEZoom); - var additionaloffset = 0; - if (offset > 10) { - additionaloffset = (offset / additionalIEZoom) - offset; - } - - a.x = a.x - (corrSVG.e - (canvasOffsetLeft * additionalIEZoom) + additionaloffset + ((canvasScrollLeft * additionalIEZoom) - canvasScrollLeft)); - a.y = a.y - (corrSVG.f - (jQuery("#canvasSection").offset().top * additionalIEZoom) + ((canvasScrollTop * additionalIEZoom) - canvasScrollTop)); - b.x = b.x - (corrSVG.e - (canvasOffsetLeft * additionalIEZoom) + additionaloffset + ((canvasScrollLeft * additionalIEZoom) - canvasScrollLeft)); - b.y = b.y - (corrSVG.f - (jQuery("#canvasSection").offset().top * additionalIEZoom) + ((canvasScrollTop * additionalIEZoom) - canvasScrollTop)); - } - - - - // Fit to SVG-Coordinates - a.x /= corrSVG.a; a.y /= corrSVG.d; - b.x /= corrSVG.a; b.y /= corrSVG.d; - - // Calculate the elements from the childs of the canvas - var elements = this.facade.getCanvas().getChildShapes(true).findAll(function(value) { - var absBounds = value.absoluteBounds(); - - var bA = absBounds.upperLeft(); - var bB = absBounds.lowerRight(); - - if(bA.x > a.x && bA.y > a.y && bB.x < b.x && bB.y < b.y) - return true; - return false; - }); - // Set the selection - this.facade.setSelection(elements); - } - }, - - handleMouseMove: function(event) { - // Calculate the size - var size = { - width : Event.pointerX(event) - this.position.x - jQuery("#canvasSection").offset().left, - height : Event.pointerY(event) - this.position.y - jQuery("#canvasSection").offset().top + 5 - }; - - var scrollNode = this.facade.getCanvas().rootNode.parentNode.parentNode; - size.width -= this.offsetScroll.x - scrollNode.scrollLeft; - size.height -= this.offsetScroll.y - scrollNode.scrollTop; - - // Set the size - this.resize(size); - - Event.stop(event); - }, + // Preventing selection of all lanes but not the pool + if (selection.any(function (s) { + return s instanceof ORYX.Core.Node && s.getStencil().id().endsWith("Lane") + })) { + var lanes = selection.findAll(function (s) { + return s instanceof ORYX.Core.Node && s.getStencil().id().endsWith("Lane") + }); - hide: function() { - this.node.style.display = "none"; - }, + var pools = []; + var unselectLanes = []; + lanes.each(function (lane) { + pools.push(this.getParentPool(lane)) + }.bind(this)); - show: function() { - this.node.style.display = ""; - }, + pools = pools.uniq().findAll(function (pool) { + var childLanes = this.getLanes(pool, true); + if (childLanes.all(function (lane) { + return lanes.include(lane) + })) { + unselectLanes = unselectLanes.concat(childLanes); + return true; + } else if (selection.include(pool) && childLanes.any(function (lane) { + return lanes.include(lane) + })) { + unselectLanes = unselectLanes.concat(childLanes); + return true; + } else { + return false; + } + }.bind(this)) - setPos: function(pos) { - // Set the Position - this.node.style.top = pos.y + "px"; - this.node.style.left = pos.x + "px"; - this.position = pos; - }, + if (unselectLanes.length > 0 && pools.length > 0) { + selection = selection.without.apply(selection, unselectLanes); + selection = selection.concat(pools); + this.facade.setSelection(selection.uniq()); + } + } + }, - resize: function(size) { + handleShapeRemove: function (option) { - // Calculate the negative offset - this.setPos(this.position); - this.size = Object.clone(size); - - if(size.width < 0) { - this.node.style.left = (this.position.x + size.width) + "px"; - size.width = - size.width; - } - if(size.height < 0) { - this.node.style.top = (this.position.y + size.height) + "px"; - size.height = - size.height; - } + var sh = option.shape; + var parent = option.parent; - // Set the size - this.node.style.width = size.width + "px"; - this.node.style.height = size.height + "px"; - } + if (sh instanceof ORYX.Core.Node && sh.getStencil().idWithoutNs() === "Lane" && this.facade.isExecutingCommands()) { -}); + var pool = this.getParentPool(parent); + if (pool && pool.parent) { + var isLeafFn = function (leaf) { + return !leaf.getChildNodes().any(function (r) { + return r.getStencil().idWithoutNs() === "Lane" + }); + } -/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + var isLeaf = isLeafFn(sh); + var parentHasMoreLanes = parent.getChildNodes().any(function (r) { + return r.getStencil().idWithoutNs() === "Lane" + }); -if(!ORYX.Plugins) - ORYX.Plugins = new Object(); + if (isLeaf && parentHasMoreLanes) { -ORYX.Plugins.ShapeHighlighting = Clazz.extend({ + var command = new ResizeLanesCommand(sh, parent, pool, this); + this.facade.executeCommands([command]); - construct: function(facade) { - - this.parentNode = facade.getCanvas().getSvgContainer(); - - // The parent Node - this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.parentNode, - ['g']); + } else if (!isLeaf && + !this.facade.getSelection().any(function (select) { // Find one of the selection, which is a lane and child of "sh" and is a leaf lane + return select instanceof ORYX.Core.Node && select.getStencil().idWithoutNs() === "Lane" && + select.isParent(sh) && isLeafFn(select); + })) { - this.highlightNodes = {}; - - facade.registerOnEvent(ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, this.setHighlight.bind(this)); - facade.registerOnEvent(ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, this.hideHighlight.bind(this)); + var Command = ORYX.Core.Command.extend({ + construct: function (shape, facade) { + this.children = shape.getChildNodes(true); + this.facade = facade; + }, + execute: function () { + this.children.each(function (child) { + child.bounds.moveBy(30, 0) + }); + //this.facade.getCanvas().update(); + }, + rollback: function () { + this.children.each(function (child) { + child.bounds.moveBy(-30, 0) + }) + //this.facade.getCanvas().update(); + } + }); + this.facade.executeCommands([new Command(sh, this.facade)]); - }, + } else if (isLeaf && !parentHasMoreLanes && parent == pool) { + parent.add(sh); + } + } - setHighlight: function(options) { - if(options && options.highlightId){ - var node = this.highlightNodes[options.highlightId]; - - if(!node){ - node= ORYX.Editor.graft("http://www.w3.org/2000/svg", this.node, - ['path', { - "stroke-width": 2.0, "fill":"none" - }]); - - this.highlightNodes[options.highlightId] = node; - } + } - if(options.elements && options.elements.length > 0) { - - this.setAttributesByStyle( node, options ); - this.show(node); - - } else { - - this.hide(node); - - } - - } - }, - - hideHighlight: function(options) { - if(options && options.highlightId && this.highlightNodes[options.highlightId]){ - this.hide(this.highlightNodes[options.highlightId]); - } - }, - - hide: function(node) { - node.setAttributeNS(null, 'display', 'none'); - }, + }, - show: function(node) { - node.setAttributeNS(null, 'display', ''); - }, - - setAttributesByStyle: function( node, options ){ - - // If the style say, that it should look like a rectangle - if( options.style && options.style == ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE ){ - - // Set like this - var bo = options.elements[0].absoluteBounds(); - - var strWidth = options.strokewidth ? options.strokewidth : ORYX.CONFIG.BORDER_OFFSET - - node.setAttributeNS(null, "d", this.getPathRectangle( bo.a, bo.b , strWidth ) ); - node.setAttributeNS(null, "stroke", options.color ? options.color : ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR); - node.setAttributeNS(null, "stroke-opacity", options.opacity ? options.opacity : 0.2); - node.setAttributeNS(null, "stroke-width", strWidth); - - } else if(options.elements.length == 1 - && options.elements[0] instanceof ORYX.Core.Edge && - options.highlightId != "selection") { - - /* Highlight containment of edge's childs */ - var path = this.getPathEdge(options.elements[0].dockers); - if (path && path.length > 0) - { - node.setAttributeNS(null, "d", path); - } - node.setAttributeNS(null, "stroke", options.color ? options.color : ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR); - node.setAttributeNS(null, "stroke-opacity", options.opacity ? options.opacity : 0.2); - node.setAttributeNS(null, "stroke-width", ORYX.CONFIG.OFFSET_EDGE_BOUNDS); - - }else { - // If not, set just the corners - var path = this.getPathByElements(options.elements); - if (path && path.length > 0) - { - node.setAttributeNS(null, "d", path); - } - node.setAttributeNS(null, "stroke", options.color ? options.color : ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR); - node.setAttributeNS(null, "stroke-opacity", options.opacity ? options.opacity : 1.0); - node.setAttributeNS(null, "stroke-width", options.strokewidth ? options.strokewidth : 2.0); - - } - }, - - getPathByElements: function(elements){ - if(!elements || elements.length <= 0) {return undefined} - - // Get the padding and the size - var padding = ORYX.CONFIG.SELECTED_AREA_PADDING; - - var path = "" - - // Get thru all Elements - elements.each((function(element) { - if(!element) {return} - // Get the absolute Bounds and the two Points - var bounds = element.absoluteBounds(); - bounds.widen(padding) - var a = bounds.upperLeft(); - var b = bounds.lowerRight(); - - path = path + this.getPath(a ,b); - - }).bind(this)); - return path; - - }, + hashedSubProcesses: {}, - getPath: function(a, b){ - - return this.getPathCorners(a, b); - - }, - - getPathCorners: function(a, b){ - - var size = ORYX.CONFIG.SELECTION_HIGHLIGHT_SIZE; - - var path = "" - - // Set: Upper left - path = path + "M" + a.x + " " + (a.y + size) + " l0 -" + size + " l" + size + " 0 "; - // Set: Lower left - path = path + "M" + a.x + " " + (b.y - size) + " l0 " + size + " l" + size + " 0 "; - // Set: Lower right - path = path + "M" + b.x + " " + (b.y - size) + " l0 " + size + " l-" + size + " 0 "; - // Set: Upper right - path = path + "M" + b.x + " " + (a.y + size) + " l0 -" + size + " l-" + size + " 0 "; - - return path; - }, - - getPathRectangle: function(a, b, strokeWidth){ - - var size = ORYX.CONFIG.SELECTION_HIGHLIGHT_SIZE; - - var path = "" - var offset = strokeWidth / 2.0; - - // Set: Upper left - path = path + "M" + (a.x + offset) + " " + (a.y); - path = path + " L" + (a.x + offset) + " " + (b.y - offset); - path = path + " L" + (b.x - offset) + " " + (b.y - offset); - path = path + " L" + (b.x - offset) + " " + (a.y + offset); - path = path + " L" + (a.x + offset) + " " + (a.y + offset); - - return path; - }, - - getPathEdge: function(edgeDockers) { - var length = edgeDockers.length; - var path = "M" + edgeDockers[0].bounds.center().x + " " - + edgeDockers[0].bounds.center().y; - - for(i=1; i 1) { - this.facade.raiseEvent({ - type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, - highlightId:'selection', - elements: event.elements.without(event.subSelection), - color: ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR, - opacity: !event.subSelection ? this.opacityFull : this.opacityLow - }); - - if(event.subSelection){ - this.facade.raiseEvent({ - type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, - highlightId:'subselection', - elements: [event.subSelection], - color: ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR, - opacity: this.opacityFull - }); - } else { - this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId:'subselection'}); - } - - } else { - this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId:'selection'}); - this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId:'subselection'}); - } - } -});/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + var offset = sh.absoluteXY(); + offset.x -= this.hashedSubProcesses[sh.id].x; + offset.y -= this.hashedSubProcesses[sh.id].y; -if (!ORYX.Plugins) - ORYX.Plugins = new Object(); + var resized = this.hashedSubProcesses[sh.id].width !== sh.bounds.width() || this.hashedSubProcesses[sh.id].height !== sh.bounds.height(); -ORYX.Plugins.Overlay = Clazz.extend({ + this.hashedSubProcesses[sh.id] = sh.absoluteXY(); + this.hashedSubProcesses[sh.id].width = sh.bounds.width(); + this.hashedSubProcesses[sh.id].height = sh.bounds.height(); + this.hashChildShapes(sh); - facade: undefined, - - styleNode: undefined, - - construct: function(facade){ - - this.facade = facade; - this.changes = []; + // Move dockers only if currently is not resizing + if (this.facade.isExecutingCommands() && !resized) { + this.moveChildDockers(sh, offset); + } + }, - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_OVERLAY_SHOW, this.show.bind(this)); - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_OVERLAY_HIDE, this.hide.bind(this)); + moveChildDockers: function (shape, offset) { - this.styleNode = document.createElement('style') - this.styleNode.setAttributeNS(null, 'type', 'text/css') - - document.getElementsByTagName('head')[0].appendChild( this.styleNode ) + if (!offset.x && !offset.y) { + return; + } - }, - - /** - * Show the overlay for specific nodes - * @param {Object} options - * - * String options.id - MUST - Define the id of the overlay (is needed for the hiding of this overlay) - * ORYX.Core.Shape[] options.shapes - MUST - Define the Shapes for the changes - * attr-name:value options.changes - Defines all the changes which should be shown - * - * - */ - show: function( options ){ - - // Checks if all arguments are available - if( !options || - !options.shapes || !options.shapes instanceof Array || - !options.id || !options.id instanceof String || options.id.length == 0) { - - return - - } - - //if( this.changes[options.id]){ - // this.hide( options ) - //} - - - // Checked if attributes are setted - if( options.attributes ){ - - // FOR EACH - Shape - options.shapes.each(function(el){ - - // Checks if the node is a Shape - if( !el instanceof ORYX.Core.Shape){ return } - - this.setAttributes( el.node , options.attributes ) - - }.bind(this)) - - } - - var isSVG = true - try { - isSVG = options.node && options.node instanceof SVGElement; - } catch(e){} - - // Checks if node is setted and if this is an SVGElement - if ( options.node && isSVG) { - - options["_temps"] = [] - - // FOR EACH - Node - options.shapes.each(function(el, index){ - - // Checks if the node is a Shape - if( !el instanceof ORYX.Core.Shape){ return } - - var _temp = {} - _temp.svg = options.dontCloneNode ? options.node : options.node.cloneNode( true ); - - // Add the svg node to the ORYX-Shape - el.node.firstChild.appendChild( _temp.svg ) - - // If - if (el instanceof ORYX.Core.Edge && !options.nodePosition) { - options['nodePosition'] = "START" - } - - // If the node position is setted, it has to be transformed - if( options.nodePosition ){ - - var b = el.bounds; - var p = options.nodePosition.toUpperCase(); - - // Check the values of START and END - if( el instanceof ORYX.Core.Node && p == "START"){ - p = "NW"; - } else if(el instanceof ORYX.Core.Node && p == "END"){ - p = "SE"; - } else if(el instanceof ORYX.Core.Edge && p == "START"){ - b = el.getDockers().first().bounds - } else if(el instanceof ORYX.Core.Edge && p == "END"){ - b = el.getDockers().last().bounds - } + var children = shape.getChildNodes(true); - // Create a callback for the changing the position - // depending on the position string - _temp.callback = function(){ - - var x = 0; var y = 0; - - if( p == "NW" ){ - // Do Nothing - } else if( p == "N" ) { - x = b.width() / 2; - } else if( p == "NE" ) { - x = b.width(); - } else if( p == "E" ) { - x = b.width(); y = b.height() / 2; - } else if( p == "SE" ) { - x = b.width(); y = b.height(); - } else if( p == "S" ) { - x = b.width() / 2; y = b.height(); - } else if( p == "SW" ) { - y = b.height(); - } else if( p == "W" ) { - y = b.height() / 2; - } else if( p == "START" || p == "END") { - x = b.width() / 2; y = b.height() / 2; - } else { - return - } - - if( el instanceof ORYX.Core.Edge){ - x += b.upperLeft().x ; y += b.upperLeft().y ; - } - - _temp.svg.setAttributeNS(null, "transform", "translate(" + x + ", " + y + ")") - - }.bind(this) - - _temp.element = el; - _temp.callback(); - - b.registerCallback( _temp.callback ); - - } - - - options._temps.push( _temp ) - - }.bind(this)) - - - - } - - - // Store the changes - if( !this.changes[options.id] ){ - this.changes[options.id] = []; - } - - this.changes[options.id].push( options ); - - }, - - /** - * Hide the overlay with the spefic id - * @param {Object} options - */ - hide: function( options ){ - - // Checks if all arguments are available - if( !options || - !options.id || !options.id instanceof String || options.id.length == 0 || - !this.changes[options.id]) { - - return - - } - - - // Delete all added attributes - // FOR EACH - Shape - this.changes[options.id].each(function(option){ - - option.shapes.each(function(el, index){ - - // Checks if the node is a Shape - if( !el instanceof ORYX.Core.Shape){ return } - - this.deleteAttributes( el.node ) - - }.bind(this)); - - - if( option._temps ){ - - option._temps.each(function(tmp){ - // Delete the added Node, if there is one - if( tmp.svg && tmp.svg.parentNode ){ - tmp.svg.parentNode.removeChild( tmp.svg ) - } - - // If - if( tmp.callback && tmp.element){ - // It has to be unregistered from the edge - tmp.element.bounds.unregisterCallback( tmp.callback ) - } - - }.bind(this)) - - } - - - }.bind(this)); + // Get all nodes + var dockers = children + // Get all incoming and outgoing edges + .map(function (node) { + return [].concat(node.getIncomingShapes()) + .concat(node.getOutgoingShapes()) + }) + // Flatten all including arrays into one + .flatten() + // Get every edge only once + .uniq() + // Get all dockers + .map(function (edge) { + return edge.dockers.length > 2 ? + edge.dockers.slice(1, edge.dockers.length - 1) : + []; + }) + // Flatten the dockers lists + .flatten(); - - this.changes[options.id] = null; - - - }, - - - /** - * Set the given css attributes to that node - * @param {HTMLElement} node - * @param {Object} attributes - */ - setAttributes: function( node, attributes ) { - - - // Get all the childs from ME - var childs = this.getAllChilds( node.firstChild.firstChild ) - - var ids = [] - - // Add all Attributes which have relation to another node in this document and concate the pure id out of it - // This is for example important for the markers of a edge - childs.each(function (e) { ids.push( $A(e.attributes).findAll(function(attr){ return attr.nodeValue.startsWith('url(#')}) )}) - ids = ids.flatten().compact(); - ids = ids.collect(function(s){return s.nodeValue}).uniq(); - ids = ids.collect(function(s){return s.slice(5, s.length-1)}) - - // Add the node ID to the id - ids.unshift( node.id + ' .me') - - var attr = $H(attributes); - var attrValue = attr.toJSON().gsub(',', ';').gsub('"', ''); - var attrMarkerValue = attributes.stroke ? attrValue.slice(0, attrValue.length-1) + "; fill:" + attributes.stroke + ";}" : attrValue; - var attrTextValue; - if( attributes.fill ){ - var copyAttr = Object.clone(attributes); - copyAttr.fill = "black"; - attrTextValue = $H(copyAttr).toJSON().gsub(',', ';').gsub('"', ''); - } - - // Create the CSS-Tags Style out of the ids and the attributes - csstags = ids.collect(function(s, i){return "#" + s + " * " + (!i? attrValue : attrMarkerValue) + "" + (attrTextValue ? " #" + s + " text * " + attrTextValue : "") }) - - // Join all the tags - var s = csstags.join(" ") + "\n" - - // And add to the end of the style tag - this.styleNode.appendChild(document.createTextNode(s)); - - - }, - - /** - * Deletes all attributes which are - * added in a special style sheet for that node - * @param {HTMLElement} node - */ - deleteAttributes: function( node ) { - - // Get all children which contains the node id - var delEl = $A(this.styleNode.childNodes) - .findAll(function (e) { return e.textContent.include( '#' + node.id ) }); - - // Remove all of them - delEl.each(function(el){ - el.parentNode.removeChild(el); - }); - }, - - getAllChilds: function( node ){ - - var childs = $A(node.childNodes) - - $A(node.childNodes).each(function( e ){ - childs.push( this.getAllChilds( e ) ) - }.bind(this)) - - return childs.flatten(); - } - - -}); -/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + var abs = shape.absoluteBounds(); + abs.moveBy(-offset.x, -offset.y) + var obj = {}; + dockers.each(function (docker) { -if (!ORYX.Plugins) - ORYX.Plugins = new Object(); + if (docker.isChanged) { + return; + } -ORYX.Plugins.KeysMove = ORYX.Plugins.AbstractPlugin.extend({ + var off = Object.clone(offset); - facade: undefined, - - construct: function(facade){ - - this.facade = facade; - this.copyElements = []; - - //this.facade.registerOnEvent(ORYX.CONFIG.EVENT_KEYDOWN, this.keyHandler.bind(this)); + if (!abs.isIncluded(docker.bounds.center())) { + var index = docker.parent.dockers.indexOf(docker); + var size = docker.parent.dockers.length; + var from = docker.parent.getSource(); + var to = docker.parent.getTarget(); - // SELECT ALL - this.facade.offer({ - keyCodes: [{ - metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL], - keyCode: 65, - keyAction: ORYX.CONFIG.KEY_ACTION_DOWN - } - ], - functionality: this.selectAll.bind(this) - }); - - // MOVE LEFT SMALL - this.facade.offer({ - keyCodes: [{ - metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL], - keyCode: ORYX.CONFIG.KEY_CODE_LEFT, - keyAction: ORYX.CONFIG.KEY_ACTION_DOWN - } - ], - functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_LEFT, false) - }); - - // MOVE LEFT - this.facade.offer({ - keyCodes: [{ - keyCode: ORYX.CONFIG.KEY_CODE_LEFT, - keyAction: ORYX.CONFIG.KEY_ACTION_DOWN - } - ], - functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_LEFT, true) - }); - - // MOVE RIGHT SMALL - this.facade.offer({ - keyCodes: [{ - metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL], - keyCode: ORYX.CONFIG.KEY_CODE_RIGHT, - keyAction: ORYX.CONFIG.KEY_ACTION_DOWN - } - ], - functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_RIGHT, false) - }); - - // MOVE RIGHT - this.facade.offer({ - keyCodes: [{ - keyCode: ORYX.CONFIG.KEY_CODE_RIGHT, - keyAction: ORYX.CONFIG.KEY_ACTION_DOWN - } - ], - functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_RIGHT, true) - }); - - // MOVE UP SMALL - this.facade.offer({ - keyCodes: [{ - metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL], - keyCode: ORYX.CONFIG.KEY_CODE_UP, - keyAction: ORYX.CONFIG.KEY_ACTION_DOWN - } - ], - functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_UP, false) - }); - - // MOVE UP - this.facade.offer({ - keyCodes: [{ - keyCode: ORYX.CONFIG.KEY_CODE_UP, - keyAction: ORYX.CONFIG.KEY_ACTION_DOWN - } - ], - functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_UP, true) - }); - - // MOVE DOWN SMALL - this.facade.offer({ - keyCodes: [{ - metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL], - keyCode: ORYX.CONFIG.KEY_CODE_DOWN, - keyAction: ORYX.CONFIG.KEY_ACTION_DOWN - } - ], - functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_DOWN, false) - }); - - // MOVE DOWN - this.facade.offer({ - keyCodes: [{ - keyCode: ORYX.CONFIG.KEY_CODE_DOWN, - keyAction: ORYX.CONFIG.KEY_ACTION_DOWN - } - ], - functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_DOWN, true) - }); - - - }, - - /** - * Select all shapes in the editor - * - */ - selectAll: function (e) { - Event.stop(e.event); - this.facade.setSelection(this.facade.getCanvas().getChildShapes(true)) - }, - - move: function(key, far, e) { - - Event.stop(e.event); - - // calculate the distance to move the objects and get the selection. - var distance = far? 20 : 5; - var selection = this.facade.getSelection(); - var currentSelection = this.facade.getSelection(); - var p = {x: 0, y: 0}; - - // switch on the key pressed and populate the point to move by. - switch(key) { - - case ORYX.CONFIG.KEY_CODE_LEFT: - p.x = -1*distance; - break; - case ORYX.CONFIG.KEY_CODE_RIGHT: - p.x = distance; - break; - case ORYX.CONFIG.KEY_CODE_UP: - p.y = -1*distance; - break; - case ORYX.CONFIG.KEY_CODE_DOWN: - p.y = distance; - break; - } - - // move each shape in the selection by the point calculated and update it. - selection = selection.findAll(function(shape){ - // Check if this shape is docked to an shape in the selection - if(shape instanceof ORYX.Core.Node && shape.dockers.length == 1 && selection.include( shape.dockers.first().getDockedShape() )){ - return false - } - - // Check if any of the parent shape is included in the selection - var s = shape.parent; - do{ - if(selection.include(s)){ - return false - } - }while(s = s.parent); - - // Otherwise, return true - return true; - - }); - - /* Edges must not be movable, if only edges are selected and at least - * one of them is docked. - */ - var edgesMovable = true; - var onlyEdgesSelected = selection.all(function(shape) { - if(shape instanceof ORYX.Core.Edge) { - if(shape.isDocked()) { - edgesMovable = false; - } - return true; - } - return false; - }); - - if(onlyEdgesSelected && !edgesMovable) { - /* Abort moving shapes */ - return; - } - - selection = selection.map(function(shape){ - if( shape instanceof ORYX.Core.Node ){ - /*if( shape.dockers.length == 1 ){ - return shape.dockers.first() - } else {*/ - return shape - //} - } else if( shape instanceof ORYX.Core.Edge ) { - - var dockers = shape.dockers; - - if( selection.include( shape.dockers.first().getDockedShape() ) ){ - dockers = dockers.without( shape.dockers.first() ) - } - - if( selection.include( shape.dockers.last().getDockedShape() ) ){ - dockers = dockers.without( shape.dockers.last() ) - } - - return dockers - - } else { - return null - } - - }).flatten().compact(); - - if (selection.size() > 0) { - - //Stop moving at canvas borders - var selectionBounds = [ this.facade.getCanvas().bounds.lowerRight().x, - this.facade.getCanvas().bounds.lowerRight().y, - 0, - 0 ]; - selection.each(function(s) { - selectionBounds[0] = Math.min(selectionBounds[0], s.bounds.upperLeft().x); - selectionBounds[1] = Math.min(selectionBounds[1], s.bounds.upperLeft().y); - selectionBounds[2] = Math.max(selectionBounds[2], s.bounds.lowerRight().x); - selectionBounds[3] = Math.max(selectionBounds[3], s.bounds.lowerRight().y); - }); - if(selectionBounds[0]+p.x < 0) - p.x = -selectionBounds[0]; - if(selectionBounds[1]+p.y < 0) - p.y = -selectionBounds[1]; - if(selectionBounds[2]+p.x > this.facade.getCanvas().bounds.lowerRight().x) - p.x = this.facade.getCanvas().bounds.lowerRight().x - selectionBounds[2]; - if(selectionBounds[3]+p.y > this.facade.getCanvas().bounds.lowerRight().y) - p.y = this.facade.getCanvas().bounds.lowerRight().y - selectionBounds[3]; - - if(p.x!=0 || p.y!=0) { - // Instantiate the moveCommand - var commands = [new ORYX.Core.Command.Move(selection, p, null, currentSelection, this)]; - // Execute the commands - this.facade.executeCommands(commands); - } - - } - }, - - getUndockedCommant: function(shapes){ - - var undockEdgeCommand = ORYX.Core.Command.extend({ - construct: function(moveShapes){ - this.dockers = moveShapes.collect(function(shape){ return shape instanceof ORYX.Core.Controls.Docker ? {docker:shape, dockedShape:shape.getDockedShape(), refPoint:shape.referencePoint} : undefined }).compact(); - }, - execute: function(){ - this.dockers.each(function(el){ - el.docker.setDockedShape(undefined); - }) - }, - rollback: function(){ - this.dockers.each(function(el){ - el.docker.setDockedShape(el.dockedShape); - el.docker.setReferencePoint(el.refPoint); - //el.docker.update(); - }) - } - }); - - command = new undockEdgeCommand( shapes ); - command.execute(); - return command; - }, - -// /** -// * The key handler for this plugin. Every action from the set of cut, copy, -// * paste and delete should be accessible trough simple keyboard shortcuts. -// * This method checks whether any event triggers one of those actions. -// * -// * @param {Object} event The keyboard event that should be analysed for -// * triggering of this plugin. -// */ -// keyHandler: function(event){ -// //TODO document what event.which is. -// -// ORYX.Log.debug("keysMove.js handles a keyEvent."); -// -// // assure we have the current event. -// if (!event) -// event = window.event; -// -// // get the currently pressed key and state of control key. -// var pressedKey = event.which || event.keyCode; -// var ctrlPressed = event.ctrlKey; -// -// // if the key is one of the arrow keys, forward to move and return. -// if ([ORYX.CONFIG.KEY_CODE_LEFT, ORYX.CONFIG.KEY_CODE_RIGHT, -// ORYX.CONFIG.KEY_CODE_UP, ORYX.CONFIG.KEY_CODE_DOWN].include(pressedKey)) { -// -// this.move(pressedKey, !ctrlPressed); -// return; -// } -// -// } - -}); -/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + var bothAreIncluded = children.include(from) && children.include(to); -if(!ORYX.Plugins) { ORYX.Plugins = {} } -if(!ORYX.Plugins.Layouter) { ORYX.Plugins.Layouter = {} } + if (!bothAreIncluded) { + var previousIsOver = index !== 0 ? abs.isIncluded(docker.parent.dockers[index - 1].bounds.center()) : false; + var nextIsOver = index !== size - 1 ? abs.isIncluded(docker.parent.dockers[index + 1].bounds.center()) : false; -new function(){ - - /** - * Edge layouter is an implementation to layout an edge - * @class ORYX.Plugins.Layouter.EdgeLayouter - * @author Willi Tscheschner - */ - ORYX.Plugins.Layouter.EdgeLayouter = ORYX.Plugins.AbstractLayouter.extend({ - - /** - * Layout only Edges - */ - layouted : [ "http://b3mn.org/stencilset/bpmn1.1#SequenceFlow", - "http://b3mn.org/stencilset/bpmn1.1#MessageFlow", - "http://b3mn.org/stencilset/timjpdl3#SequenceFlow", - "http://b3mn.org/stencilset/jbpm4#SequenceFlow", - "http://b3mn.org/stencilset/bpmn2.0#MessageFlow", - "http://b3mn.org/stencilset/bpmn2.0#SequenceFlow", - "http://b3mn.org/stencilset/bpmn2.0choreography#MessageFlow", - "http://b3mn.org/stencilset/bpmn2.0choreography#SequenceFlow", - "http://b3mn.org/stencilset/bpmn2.0conversation#ConversationLink", - "http://b3mn.org/stencilset/epc#ControlFlow", - "http://www.signavio.com/stencilsets/processmap#ProcessLink", - "http://www.signavio.com/stencilsets/organigram#connection"], - - /** - * Layout a set on edges - * @param {Object} edges - */ - layout: function(edges){ - edges.each(function(edge){ - this.doLayout(edge) - }.bind(this)) - }, - - /** - * Layout one edge - * @param {Object} edge - */ - doLayout: function(edge){ - // Get from and to node - var from = edge.getIncomingNodes()[0]; - var to = edge.getOutgoingNodes()[0]; - - // Return if one is null - if (!from || !to) { return } - - var positions = this.getPositions(from, to, edge); - - if (positions.length > 0){ - this.setDockers(edge, positions[0].a, positions[0].b); - } - - }, - - /** - * Returns a set on positions which are not containt either - * in the bounds in from or to. - * @param {Object} from Shape where the edge is come from - * @param {Object} to Shape where the edge is leading to - * @param {Object} edge Edge between from and to - */ - getPositions : function(from, to, edge){ - - // Get absolute bounds - var ab = from.absoluteBounds(); - var bb = to.absoluteBounds(); - - // Get center from and to - var a = ab.center(); - var b = bb.center(); - - var am = ab.midPoint(); - var bm = bb.midPoint(); - - // Get first and last reference point - var first = Object.clone(edge.dockers.first().referencePoint); - var last = Object.clone(edge.dockers.last().referencePoint); - // Get the absolute one - var aFirst = edge.dockers.first().getAbsoluteReferencePoint(); - var aLast = edge.dockers.last().getAbsoluteReferencePoint(); - - // IF ------> - // or | - // V - // Do nothing - if (Math.abs(aFirst.x-aLast.x) < 1 || Math.abs(aFirst.y-aLast.y) < 1) { - return [] - } - - // Calc center position, between a and b - // depending on there weight - var m = {} - m.x = a.x < b.x ? - (((b.x - bb.width()/2) - (a.x + ab.width()/2))/2) + (a.x + ab.width()/2): - (((a.x - ab.width()/2) - (b.x + bb.width()/2))/2) + (b.x + bb.width()/2); - - m.y = a.y < b.y ? - (((b.y - bb.height()/2) - (a.y + ab.height()/2))/2) + (a.y + ab.height()/2): - (((a.y - ab.height()/2) - (b.y + bb.height()/2))/2) + (b.y + bb.height()/2); - - - // Enlarge both bounds with 10 - ab.widen(5); // Wide the from less than - bb.widen(20);// the to because of the arrow from the edge - - var positions = []; - var off = this.getOffset.bind(this); - - // Checks ----+ - // | - // V - if (!ab.isIncluded(b.x, a.y)&&!bb.isIncluded(b.x, a.y)) { - positions.push({ - a : {x:b.x+off(last,bm,"x"),y:a.y+off(first,am,"y")}, - z : this.getWeight(from, a.x < b.x ? "r" : "l", to, a.y < b.y ? "t" : "b", edge) - }); - } - - // Checks | - // +---> - if (!ab.isIncluded(a.x, b.y)&&!bb.isIncluded(a.x, b.y)) { - positions.push({ - a : {x:a.x+off(first,am,"x"),y:b.y+off(last,bm,"y")}, - z : this.getWeight(from, a.y < b.y ? "b" : "t", to, a.x < b.x ? "l" : "r", edge) - }); - } - - // Checks --+ - // | - // +---> - if (!ab.isIncluded(m.x, a.y)&&!bb.isIncluded(m.x, b.y)) { - positions.push({ - a : {x:m.x,y:a.y+off(first,am,"y")}, - b : {x:m.x,y:b.y+off(last,bm,"y")}, - z : this.getWeight(from, "r", to, "l", edge, a.x > b.x) - }); - } - - // Checks | - // +---+ - // | - // V - if (!ab.isIncluded(a.x, m.y)&&!bb.isIncluded(b.x, m.y)) { - positions.push({ - a : {x:a.x+off(first,am,"x"),y:m.y}, - b : {x:b.x+off(last,bm,"x"),y:m.y}, - z : this.getWeight(from, "b", to, "t", edge, a.y > b.y) - }); - } - - // Sort DESC of weights - return positions.sort(function(a,b){ return a.z < b.z ? 1 : (a.z == b.z ? -1 : -1)}); - }, - - /** - * Returns a offset for the pos to the center of the bounds - * - * @param {Object} val - * @param {Object} pos2 - * @param {String} dir Direction x|y - */ - getOffset: function(pos, pos2, dir){ - return pos[dir] - pos2[dir]; - }, - - /** - * Returns a value which shows the weight for this configuration - * - * @param {Object} from Shape which is coming from - * @param {String} d1 Direction where is goes - * @param {Object} to Shape which goes to - * @param {String} d2 Direction where it comes to - * @param {Object} edge Edge between from and to - * @param {Boolean} reverse Reverse the direction (e.g. "r" -> "l") - */ - getWeight: function(from, d1, to, d2, edge, reverse){ - - d1 = (d1||"").toLowerCase(); - d2 = (d2||"").toLowerCase(); - - if (!["t","r","b","l"].include(d1)){ d1 = "r"} - if (!["t","r","b","l"].include(d2)){ d1 = "l"} - - // If reverse is set - if (reverse) { - // Reverse d1 and d2 - d1 = d1=="t"?"b":(d1=="r"?"l":(d1=="b"?"t":(d1=="l"?"r":"r"))) - d2 = d2=="t"?"b":(d2=="r"?"l":(d2=="b"?"t":(d2=="l"?"r":"r"))) - } - - - var weight = 0; - // Get rules for from "out" and to "in" - var dr1 = this.facade.getRules().getLayoutingRules(from, edge)["out"]; - var dr2 = this.facade.getRules().getLayoutingRules(to, edge)["in"]; - - var fromWeight = dr1[d1]; - var toWeight = dr2[d2]; - - - /** - * Return a true if the center 1 is in the same direction than center 2 - * @param {Object} direction - * @param {Object} center1 - * @param {Object} center2 - */ - var sameDirection = function(direction, center1, center2){ - switch(direction){ - case "t": return Math.abs(center1.x - center2.x) < 2 && center1.y < center2.y - case "r": return center1.x > center2.x && Math.abs(center1.y - center2.y) < 2 - case "b": return Math.abs(center1.x - center2.x) < 2 && center1.y > center2.y - case "l": return center1.x < center2.x && Math.abs(center1.y - center2.y) < 2 - default: return false; - } - } + if (!previousIsOver && !nextIsOver) { + return; + } - // Check if there are same incoming edges from 'from' - var sameIncomingFrom = from - .getIncomingShapes() - .findAll(function(a){ return a instanceof ORYX.Core.Edge}) - .any(function (e) { - return sameDirection(d1, e.dockers[e.dockers.length-2].bounds.center(), e.dockers.last().bounds.center()); - }); - - // Check if there are same outgoing edges from 'to' - var sameOutgoingTo = to - .getOutgoingShapes() - .findAll(function(a){ return a instanceof ORYX.Core.Edge}) - .any(function (e) { - return sameDirection(d2, e.dockers[1].bounds.center(), e.dockers.first().bounds.center()); - }); - - // If there are equivalent edges, set 0 - //fromWeight = sameIncomingFrom ? 0 : fromWeight; - //toWeight = sameOutgoingTo ? 0 : toWeight; - - // Get the sum of "out" and the direction plus "in" and the direction - return (sameIncomingFrom||sameOutgoingTo?0:fromWeight+toWeight); - }, - - /** - * Removes all current dockers from the node - * (except the start and end) and adds two new - * dockers, on the position a and b. - * @param {Object} edge - * @param {Object} a - * @param {Object} b - */ - setDockers: function(edge, a, b){ - if (!edge){ return } - - // Remove all dockers (implicit, - // start and end dockers will not removed) - edge.dockers.each(function(r){ - edge.removeDocker(r); - }); - - // For a and b (if exists), create - // a new docker and set position - [a, b].compact().each(function(pos){ - var docker = edge.createDocker(undefined, pos); - docker.bounds.centerMoveTo(pos); - }); - - // Update all dockers from the edge - edge.dockers.each(function(docker){ - docker.update() - }) - - // Update edge - //edge.refresh(); - edge._update(true); - - } - }); - - -}() -/* - * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. - * License rights for this program may be obtained from Alfresco Software, Ltd. - * pursuant to a written agreement and any use of this program without such an - * agreement is prohibited. - */ -/* - * All code Copyright 2013 KIS Consultancy all rights reserved - */ + var ref = docker.parent.dockers[previousIsOver ? index - 1 : index + 1]; + if (Math.abs(-Math.abs(ref.bounds.center().x - docker.bounds.center().x)) < 2) { + off.y = 0; + } else if (Math.abs(-Math.abs(ref.bounds.center().y - docker.bounds.center().y)) < 2) { + off.x = 0; + } else { + return; + } + } -if(!ORYX.Plugins) - ORYX.Plugins = new Object(); + } -new function(){ - - ORYX.Plugins.BPMN2_0 = { - - /** - * Constructor - * @param {Object} Facade: The Facade of the Editor - */ - construct: function(facade){ - this.facade = facade; - - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DRAGDOCKER_DOCKED, this.handleDockerDocked.bind(this)); - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_PROPWINDOW_PROP_CHANGED, this.handlePropertyChanged.bind(this)); - this.facade.registerOnEvent('layout.bpmn2_0.pool', this.handleLayoutPool.bind(this)); - this.facade.registerOnEvent('layout.bpmn2_0.subprocess', this.handleSubProcess.bind(this)); - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_SHAPEREMOVED, this.handleShapeRemove.bind(this)); - - this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADED, this.afterLoad.bind(this)); - - - this.namespace = undefined; - }, - - /** - * Force to update every pool + obj[docker.getId()] = { + docker: docker, + offset: off + } + }) + + // Set dockers + this.facade.executeCommands([new ORYX.Core.MoveDockersCommand(obj)]); + + }, + + /** + * DragDocker.Docked Handler + * */ - afterLoad: function(){ - this.facade.getCanvas().getChildNodes().each(function(shape){ - if (shape.getStencil().id().endsWith("Pool")) { - this.handleLayoutPool({ - shape: shape - }); - } - }.bind(this)) + handleDockerDocked: function (options) { + var namespace = this.getNamespace(); + + var edge = options.parent; + var edgeSource = options.target; + + if (edge.getStencil().id() === namespace + "SequenceFlow") { + var isGateway = edgeSource.getStencil().groups().find(function (group) { + if (group == "Gateways") + return group; + }); + if (!isGateway && (edge.properties["oryx-conditiontype"] == "Expression")) + // show diamond on edge source + edge.setProperty("oryx-showdiamondmarker", true); + else + // do not show diamond on edge source + edge.setProperty("oryx-showdiamondmarker", false); + + // update edge rendering + //edge.update(); + + this.facade.getCanvas().update(); + } }, - + /** - * If a pool is selected and contains no lane, - * a lane is created automagically + * PropertyWindow.PropertyChanged Handler */ - onSelectionChanged: function(event) { - var selection = event.elements; - - if(selection && selection.length === 1) { - var namespace = this.getNamespace(); - var shape = selection[0]; - if(shape.getStencil().idWithoutNs() === "Pool") { - if(shape.getChildNodes().length === 0) { - // create a lane inside the selected pool - var option = { - type:namespace + "Lane", - position:{x:0,y:0}, - namespace:shape.getStencil().namespace(), - parent:shape - }; - this.facade.createShape(option); - this.facade.getCanvas().update(); - this.facade.setSelection([shape]); - } + handlePropertyChanged: function (option) { + var namespace = this.getNamespace(); + + var shapes = option.elements; + var propertyKey = option.key; + var propertyValue = option.value; + + var changed = false; + shapes.each(function (shape) { + if ((shape.getStencil().id() === namespace + "SequenceFlow") && + (propertyKey === "oryx-conditiontype")) { + + if (propertyValue != "Expression") + // Do not show the Diamond + shape.setProperty("oryx-showdiamondmarker", false); + else { + var incomingShapes = shape.getIncomingShapes(); + + if (!incomingShapes) { + shape.setProperty("oryx-showdiamondmarker", true); } - } - - // Preventing selection of all lanes but not the pool - if(selection.any(function(s){ return s instanceof ORYX.Core.Node && s.getStencil().id().endsWith("Lane")})){ - var lanes = selection.findAll(function(s){ - return s instanceof ORYX.Core.Node && s.getStencil().id().endsWith("Lane") + + var incomingGateway = incomingShapes.find(function (aShape) { + var foundGateway = aShape.getStencil().groups().find(function (group) { + if (group == "Gateways") + return group; + }); + if (foundGateway) + return foundGateway; }); - - var pools = []; - var unselectLanes = []; - lanes.each(function(lane){ - pools.push(this.getParentPool(lane)) - }.bind(this)); - - pools = pools.uniq().findAll(function(pool){ - var childLanes = this.getLanes(pool, true); - if (childLanes.all(function(lane){ return lanes.include(lane)})){ - unselectLanes = unselectLanes.concat(childLanes); - return true; - } else if (selection.include(pool) && childLanes.any(function(lane){ return lanes.include(lane)})) { - unselectLanes = unselectLanes.concat(childLanes); - return true; - } else { - return false; - } - }.bind(this)) - - if (unselectLanes.length > 0 && pools.length > 0){ - selection = selection.without.apply(selection, unselectLanes); - selection = selection.concat(pools); - this.facade.setSelection(selection.uniq()); - } - } - }, - - handleShapeRemove: function(option) { - - var sh = option.shape; - var parent = option.parent; - - if (sh instanceof ORYX.Core.Node && sh.getStencil().idWithoutNs() === "Lane" && this.facade.isExecutingCommands()) { - - var pool = this.getParentPool(parent); - if (pool&&pool.parent){ - - var isLeafFn = function(leaf){ - return !leaf.getChildNodes().any(function(r){ return r.getStencil().idWithoutNs() === "Lane"}); - } - - var isLeaf = isLeafFn(sh); - var parentHasMoreLanes = parent.getChildNodes().any(function(r){ return r.getStencil().idWithoutNs() === "Lane"}); - - if (isLeaf && parentHasMoreLanes){ - - var command = new ResizeLanesCommand(sh, parent, pool, this); - this.facade.executeCommands([command]); - - } else if( !isLeaf && - !this.facade.getSelection().any(function(select){ // Find one of the selection, which is a lane and child of "sh" and is a leaf lane - return select instanceof ORYX.Core.Node && select.getStencil().idWithoutNs() === "Lane" && - select.isParent(sh) && isLeafFn(select);})) { - - var Command = ORYX.Core.Command.extend({ - construct: function(shape, facade) { - this.children = shape.getChildNodes(true); - this.facade = facade; - }, - execute: function() { - this.children.each(function(child){ - child.bounds.moveBy(30,0) - }); - //this.facade.getCanvas().update(); - }, - rollback: function() { - this.children.each(function(child){ - child.bounds.moveBy(-30,0) - }) - //this.facade.getCanvas().update(); - } - }); - this.facade.executeCommands([new Command(sh, this.facade)]); - - } else if (isLeaf&&!parentHasMoreLanes&&parent == pool){ - parent.add(sh); - } - } - + + if (!incomingGateway) + // show diamond on edge source + shape.setProperty("oryx-showdiamondmarker", true); + else + // do not show diamond + shape.setProperty("oryx-showdiamondmarker", false); + } + + changed = true; } - + }.bind(this)); + + if (changed) { + this.facade.getCanvas().update(); + } + }, - - hashedSubProcesses: {}, - - hashChildShapes: function(shape){ - var children = shape.getChildNodes(); - children.each(function(child){ - if (this.hashedSubProcesses[child.id]){ - this.hashedSubProcesses[child.id] = child.absoluteXY(); - this.hashedSubProcesses[child.id].width = child.bounds.width(); - this.hashedSubProcesses[child.id].height = child.bounds.height(); - this.hashChildShapes(child); - } - }.bind(this)); - }, - - /** - * Handle the layouting of a sub process. - * Mainly to adjust the child dockers of a sub process. - * - */ - handleSubProcess : function(option) { - - var sh = option.shape; - - if (!this.hashedSubProcesses[sh.id]) { - this.hashedSubProcesses[sh.id] = sh.absoluteXY(); - this.hashedSubProcesses[sh.id].width = sh.bounds.width(); - this.hashedSubProcesses[sh.id].height = sh.bounds.height(); - return; - } - - var offset = sh.absoluteXY(); - offset.x -= this.hashedSubProcesses[sh.id].x; - offset.y -= this.hashedSubProcesses[sh.id].y; - - var resized = this.hashedSubProcesses[sh.id].width !== sh.bounds.width() || this.hashedSubProcesses[sh.id].height !== sh.bounds.height(); - - this.hashedSubProcesses[sh.id] = sh.absoluteXY(); - this.hashedSubProcesses[sh.id].width = sh.bounds.width(); - this.hashedSubProcesses[sh.id].height = sh.bounds.height(); - this.hashChildShapes(sh); - - - // Move dockers only if currently is not resizing - if (this.facade.isExecutingCommands()&&!resized) { - this.moveChildDockers(sh, offset); - } - }, - - moveChildDockers: function(shape, offset){ - - if (!offset.x && !offset.y) { - return; - } - - var children = shape.getChildNodes(true); - - // Get all nodes - var dockers = children - // Get all incoming and outgoing edges - .map(function(node){ - return [].concat(node.getIncomingShapes()) - .concat(node.getOutgoingShapes()) - }) - // Flatten all including arrays into one - .flatten() - // Get every edge only once - .uniq() - // Get all dockers - .map(function(edge){ - return edge.dockers.length > 2 ? - edge.dockers.slice(1, edge.dockers.length-1) : - []; - }) - // Flatten the dockers lists - .flatten(); - - var abs = shape.absoluteBounds(); - abs.moveBy(-offset.x, -offset.y) - var obj = {}; - dockers.each(function(docker){ - - if (docker.isChanged){ - return; - } - - var off = Object.clone(offset); - - if (!abs.isIncluded(docker.bounds.center())){ - var index = docker.parent.dockers.indexOf(docker); - var size = docker.parent.dockers.length; - var from = docker.parent.getSource(); - var to = docker.parent.getTarget(); - - var bothAreIncluded = children.include(from) && children.include(to); - - if (!bothAreIncluded){ - var previousIsOver = index !== 0 ? abs.isIncluded(docker.parent.dockers[index-1].bounds.center()) : false; - var nextIsOver = index !== size-1 ? abs.isIncluded(docker.parent.dockers[index+1].bounds.center()) : false; - - if (!previousIsOver && !nextIsOver){ return; } - - var ref = docker.parent.dockers[previousIsOver ? index-1 : index+1]; - if (Math.abs(-Math.abs(ref.bounds.center().x-docker.bounds.center().x)) < 2){ - off.y = 0; - } else if(Math.abs(-Math.abs(ref.bounds.center().y-docker.bounds.center().y)) < 2){ - off.x = 0; - } else { - return; - } - } - - } - - obj[docker.getId()] = { - docker:docker, - offset:off - } - }) - - // Set dockers - this.facade.executeCommands([new ORYX.Core.MoveDockersCommand(obj)]); - - }, - - /** - * DragDocker.Docked Handler - * - */ - handleDockerDocked: function(options) { - var namespace = this.getNamespace(); - - var edge = options.parent; - var edgeSource = options.target; - - if(edge.getStencil().id() === namespace + "SequenceFlow") { - var isGateway = edgeSource.getStencil().groups().find(function(group) { - if(group == "Gateways") - return group; - }); - if(!isGateway && (edge.properties["oryx-conditiontype"] == "Expression")) - // show diamond on edge source - edge.setProperty("oryx-showdiamondmarker", true); - else - // do not show diamond on edge source - edge.setProperty("oryx-showdiamondmarker", false); - - // update edge rendering - //edge.update(); - - this.facade.getCanvas().update(); - } - }, - - /** - * PropertyWindow.PropertyChanged Handler - */ - handlePropertyChanged: function(option) { - var namespace = this.getNamespace(); - - var shapes = option.elements; - var propertyKey = option.key; - var propertyValue = option.value; - - var changed = false; - shapes.each(function(shape){ - if((shape.getStencil().id() === namespace + "SequenceFlow") && - (propertyKey === "oryx-conditiontype")) { - - if(propertyValue != "Expression") - // Do not show the Diamond - shape.setProperty("oryx-showdiamondmarker", false); - else { - var incomingShapes = shape.getIncomingShapes(); - - if(!incomingShapes) { - shape.setProperty("oryx-showdiamondmarker", true); - } - - var incomingGateway = incomingShapes.find(function(aShape) { - var foundGateway = aShape.getStencil().groups().find(function(group) { - if(group == "Gateways") - return group; - }); - if(foundGateway) - return foundGateway; - }); - - if(!incomingGateway) - // show diamond on edge source - shape.setProperty("oryx-showdiamondmarker", true); - else - // do not show diamond - shape.setProperty("oryx-showdiamondmarker", false); - } - - changed = true; - } - }.bind(this)); - - if(changed) {this.facade.getCanvas().update();} - - }, - - hashedPoolPositions : {}, - hashedLaneDepth : {}, - hashedBounds : {}, - hashedPositions: {}, - - /** + hashedPoolPositions: {}, + hashedLaneDepth: {}, + hashedBounds: {}, + hashedPositions: {}, + + /** * Handler for layouting event 'layout.bpmn2_0.pool' * @param {Object} event */ - handleLayoutPool: function(event){ - - - var pool = event.shape; - var selection = this.facade.getSelection(); - var currentShape = selection.include(pool) ? pool : selection.first(); - - currentShape = currentShape || pool; - - this.currentPool = pool; - - // Check if it is a pool or a lane - if (!(currentShape.getStencil().id().endsWith("Pool") || currentShape.getStencil().id().endsWith("Lane"))) { - return; - } - - // Check if the lane is within the pool and is not removed lately - if (currentShape !== pool && !currentShape.isParent(pool) && !this.hashedBounds[pool.id][currentShape.id]){ - return; - } - - - if (!this.hashedBounds[pool.id]) { - this.hashedBounds[pool.id] = {}; + handleLayoutPool: function (event) { + + + var pool = event.shape; + var selection = this.facade.getSelection(); + var currentShape = selection.include(pool) ? pool : selection.first(); + + currentShape = currentShape || pool; + + this.currentPool = pool; + + // Check if it is a pool or a lane + if (!(currentShape.getStencil().id().endsWith("Pool") || currentShape.getStencil().id().endsWith("Lane"))) { + return; + } + + // Check if the lane is within the pool and is not removed lately + if (currentShape !== pool && !currentShape.isParent(pool) && !this.hashedBounds[pool.id][currentShape.id]) { + return; + } + + + if (!this.hashedBounds[pool.id]) { + this.hashedBounds[pool.id] = {}; + } + + // Find all child lanes + var lanes = this.getLanes(pool); + + if (lanes.length <= 0) { + return + } + + var allLanes = this.getLanes(pool, true), hp; + var considerForDockers = allLanes.clone(); + + var hashedPositions = $H({}); + allLanes.each(function (lane) { + hashedPositions[lane.id] = lane.bounds.upperLeft(); + }) + + + // Show/hide caption regarding the number of lanes + if (lanes.length === 1 && this.getLanes(lanes.first()).length <= 0) { + // TRUE if there is a caption + lanes.first().setProperty("oryx-showcaption", lanes.first().properties["oryx-name"].trim().length > 0); + var rect = lanes.first().node.getElementsByTagName("rect"); + rect[0].setAttributeNS(null, "display", "none"); + } else { + allLanes.invoke("setProperty", "oryx-showcaption", true); + allLanes.each(function (lane) { + var rect = lane.node.getElementsByTagName("rect"); + rect[0].removeAttributeNS(null, "display"); + }) + } + + var deletedLanes = []; + var addedLanes = []; + + // Get all new lanes + var i = -1; + while (++i < allLanes.length) { + if (!this.hashedBounds[pool.id][allLanes[i].id]) { + addedLanes.push(allLanes[i]) } - - // Find all child lanes - var lanes = this.getLanes(pool); - - if (lanes.length <= 0) { - return + } + + if (addedLanes.length > 0) { + currentShape = addedLanes.first(); + } + + + // Get all deleted lanes + var resourceIds = $H(this.hashedBounds[pool.id]).keys(); + var i = -1; + while (++i < resourceIds.length) { + if (!allLanes.any(function (lane) { + return lane.id == resourceIds[i] + })) { + deletedLanes.push(this.hashedBounds[pool.id][resourceIds[i]]); + selection = selection.without(function (r) { + return r.id == resourceIds[i] + }); } - - var allLanes = this.getLanes(pool, true), hp; - var considerForDockers = allLanes.clone(); - - var hashedPositions = $H({}); - allLanes.each(function(lane){ - hashedPositions[lane.id] = lane.bounds.upperLeft(); - }) - - - - // Show/hide caption regarding the number of lanes - if (lanes.length === 1 && this.getLanes(lanes.first()).length <= 0) { - // TRUE if there is a caption - lanes.first().setProperty("oryx-showcaption", lanes.first().properties["oryx-name"].trim().length > 0); - var rect = lanes.first().node.getElementsByTagName("rect"); - rect[0].setAttributeNS(null, "display", "none"); + } + + var height, width, x, y; + + if (deletedLanes.length > 0 || addedLanes.length > 0) { + + if (addedLanes.length === 1 && this.getLanes(addedLanes[0].parent).length === 1) { + // Set height from the pool + height = this.adjustHeight(lanes, addedLanes[0].parent); } else { - allLanes.invoke("setProperty", "oryx-showcaption", true); - allLanes.each(function(lane){ - var rect = lane.node.getElementsByTagName("rect"); - rect[0].removeAttributeNS(null, "display"); - }) + // Set height from the pool + height = this.updateHeight(pool); } - - var deletedLanes = []; - var addedLanes = []; - - // Get all new lanes - var i=-1; - while (++i 0){ - currentShape = addedLanes.first(); + // Set width from the pool + width = this.adjustWidth(lanes, pool.bounds.width()); + + pool.update(); + } + + /** + * Set width/height depending on the pool + */ + else if (pool == currentShape) { + + if (selection.length === 1 && this.isResized(pool, this.hashedPoolPositions[pool.id])) { + var oldXY = this.hashedPoolPositions[pool.id].upperLeft(); + var xy = pool.bounds.upperLeft(); + var scale = 0; + if (this.shouldScale(pool)) { + var old = this.hashedPoolPositions[pool.id]; + scale = old.height() / pool.bounds.height(); + } + + this.adjustLanes(pool, allLanes, oldXY.x - xy.x, oldXY.y - xy.y, scale); } - - - // Get all deleted lanes - var resourceIds = $H(this.hashedBounds[pool.id]).keys(); - var i=-1; - while (++i 0 || addedLanes.length > 0) { - - if (addedLanes.length === 1 && this.getLanes(addedLanes[0].parent).length === 1){ - // Set height from the pool - height = this.adjustHeight(lanes, addedLanes[0].parent); + + // Set height from the pool + height = this.adjustHeight(lanes, undefined, pool.bounds.height()); + // Set width from the pool + width = this.adjustWidth(lanes, pool.bounds.width()); + } + + /**??? + * Set width/height depending on containing lanes + */ + else { + + // Reposition the pool if one shape is selected and the upperleft has changed + if (selection.length === 1 && this.isResized(currentShape, this.hashedBounds[pool.id][currentShape.id])) { + var oldXY = this.hashedBounds[pool.id][currentShape.id].upperLeft(); + var xy = currentShape.absoluteXY(); + x = oldXY.x - xy.x; + y = oldXY.y - xy.y; + + // Adjust all other lanes beneath this lane + if (x || y) { + considerForDockers = considerForDockers.without(currentShape); + this.adjustLanes(pool, this.getAllExcludedLanes(pool, currentShape), x, 0); + } + + // Adjust all child lanes + var childLanes = this.getLanes(currentShape, true); + if (childLanes.length > 0) { + if (this.shouldScale(currentShape)) { + var old = this.hashedBounds[pool.id][currentShape.id]; + var scale = old.height() / currentShape.bounds.height(); + this.adjustLanes(pool, childLanes, x, y, scale); } else { - // Set height from the pool - height = this.updateHeight(pool); - } - // Set width from the pool - width = this.adjustWidth(lanes, pool.bounds.width()); - - pool.update(); - } - - /** - * Set width/height depending on the pool - */ - else if (pool == currentShape) { - - if (selection.length === 1 && this.isResized(pool, this.hashedPoolPositions[pool.id])) { - var oldXY = this.hashedPoolPositions[pool.id].upperLeft(); - var xy = pool.bounds.upperLeft(); - var scale = 0; - if (this.shouldScale(pool)){ - var old = this.hashedPoolPositions[pool.id]; - scale = old.height()/pool.bounds.height(); - } - - this.adjustLanes(pool, allLanes, oldXY.x - xy.x, oldXY.y - xy.y, scale); - } - - // Set height from the pool - height = this.adjustHeight(lanes, undefined, pool.bounds.height()); - // Set width from the pool - width = this.adjustWidth(lanes, pool.bounds.width()); - } - - /**??? - * Set width/height depending on containing lanes - */ - else { - - // Reposition the pool if one shape is selected and the upperleft has changed - if (selection.length === 1 && this.isResized(currentShape, this.hashedBounds[pool.id][currentShape.id])){ - var oldXY = this.hashedBounds[pool.id][currentShape.id].upperLeft(); - var xy = currentShape.absoluteXY(); - x = oldXY.x - xy.x; - y = oldXY.y - xy.y; - - // Adjust all other lanes beneath this lane - if (x||y){ - considerForDockers = considerForDockers.without(currentShape); - this.adjustLanes(pool, this.getAllExcludedLanes(pool, currentShape), x, 0); - } - - // Adjust all child lanes - var childLanes = this.getLanes(currentShape, true); - if (childLanes.length > 0){ - if (this.shouldScale(currentShape)){ - var old = this.hashedBounds[pool.id][currentShape.id]; - var scale = old.height()/currentShape.bounds.height(); - this.adjustLanes(pool, childLanes, x, y, scale); - } else { - this.adjustLanes(pool, childLanes, x, y, 0); - } - } + this.adjustLanes(pool, childLanes, x, y, 0); } - - // Cache all bounds - var changes = allLanes.map(function(lane){ return { - shape: lane, - bounds: lane.bounds.clone() - } }); - - // Get height and adjust child heights - height = this.adjustHeight(lanes, currentShape); - // Check if something has changed and maybe create a command - this.checkForChanges(allLanes, changes); - - // Set width from the current shape - width = this.adjustWidth(lanes, currentShape.bounds.width()+(this.getDepth(currentShape,pool)*30)); + } } - - this.setDimensions(pool, width, height, x, y); - - - if (this.facade.isExecutingCommands() && (deletedLanes.length === 0 || addedLanes.length !== 0)){ - // Update all dockers - this.updateDockers(considerForDockers, pool); - - // Check if the order has changed - if (this.hashedPositions[pool.id] && this.hashedPositions[pool.id].keys().any(function(key, i){ - return (allLanes[i]||{}).id !== key; - })){ - - var LanesHasBeenReordered = ORYX.Core.Command.extend({ - construct: function(originPosition, newPosition, lanes, plugin, poolId) { - this.originPosition = Object.clone(originPosition); - this.newPosition = Object.clone(newPosition); - this.lanes = lanes; - this.plugin = plugin; - this.pool = poolId; - }, - execute: function(){ - if (!this.executed){ - this.executed = true; - this.lanes.each(function(lane){ - if (this.newPosition[lane.id]) - lane.bounds.moveTo(this.newPosition[lane.id]) - }.bind(this)); - this.plugin.hashedPositions[this.pool] = Object.clone(this.newPosition); - } - }, - rollback: function(){ - this.lanes.each(function(lane){ - if (this.originPosition[lane.id]) - lane.bounds.moveTo(this.originPosition[lane.id]) - }.bind(this)); - this.plugin.hashedPositions[this.pool] = Object.clone(this.originPosition); - } - }); - - var hp2 = $H({}); - allLanes.each(function(lane){ - hp2[lane.id] = lane.bounds.upperLeft(); - }) - - var command = new LanesHasBeenReordered(hashedPositions, hp2, allLanes, this, pool.id); - this.facade.executeCommands([command]); - + + // Cache all bounds + var changes = allLanes.map(function (lane) { + return { + shape: lane, + bounds: lane.bounds.clone() + } + }); + + // Get height and adjust child heights + height = this.adjustHeight(lanes, currentShape); + // Check if something has changed and maybe create a command + this.checkForChanges(allLanes, changes); + + // Set width from the current shape + width = this.adjustWidth(lanes, currentShape.bounds.width() + (this.getDepth(currentShape, pool) * 30)); + } + + this.setDimensions(pool, width, height, x, y); + + + if (this.facade.isExecutingCommands() && (deletedLanes.length === 0 || addedLanes.length !== 0)) { + // Update all dockers + this.updateDockers(considerForDockers, pool); + + // Check if the order has changed + if (this.hashedPositions[pool.id] && this.hashedPositions[pool.id].keys().any(function (key, i) { + return (allLanes[i] || {}).id !== key; + })) { + + var LanesHasBeenReordered = ORYX.Core.Command.extend({ + construct: function (originPosition, newPosition, lanes, plugin, poolId) { + this.originPosition = Object.clone(originPosition); + this.newPosition = Object.clone(newPosition); + this.lanes = lanes; + this.plugin = plugin; + this.pool = poolId; + }, + execute: function () { + if (!this.executed) { + this.executed = true; + this.lanes.each(function (lane) { + if (this.newPosition[lane.id]) + lane.bounds.moveTo(this.newPosition[lane.id]) + }.bind(this)); + this.plugin.hashedPositions[this.pool] = Object.clone(this.newPosition); + } + }, + rollback: function () { + this.lanes.each(function (lane) { + if (this.originPosition[lane.id]) + lane.bounds.moveTo(this.originPosition[lane.id]) + }.bind(this)); + this.plugin.hashedPositions[this.pool] = Object.clone(this.originPosition); } + }); + + var hp2 = $H({}); + allLanes.each(function (lane) { + hp2[lane.id] = lane.bounds.upperLeft(); + }) + + var command = new LanesHasBeenReordered(hashedPositions, hp2, allLanes, this, pool.id); + this.facade.executeCommands([command]); + } - - this.hashedBounds[pool.id] = {}; - this.hashedPositions[pool.id] = hashedPositions; - - var i=-1; - while (++i < allLanes.length) { - // Cache positions - this.hashedBounds[pool.id][allLanes[i].id] = allLanes[i].absoluteBounds(); - - // Cache also the bounds of child shapes, mainly for child subprocesses - this.hashChildShapes(allLanes[i]); - - this.hashedLaneDepth[allLanes[i].id] = this.getDepth(allLanes[i], pool); - - this.forceToUpdateLane(allLanes[i]); - } - - this.hashedPoolPositions[pool.id] = pool.bounds.clone(); - - - // Update selection - //this.facade.setSelection(selection); + } + + this.hashedBounds[pool.id] = {}; + this.hashedPositions[pool.id] = hashedPositions; + + var i = -1; + while (++i < allLanes.length) { + // Cache positions + this.hashedBounds[pool.id][allLanes[i].id] = allLanes[i].absoluteBounds(); + + // Cache also the bounds of child shapes, mainly for child subprocesses + this.hashChildShapes(allLanes[i]); + + this.hashedLaneDepth[allLanes[i].id] = this.getDepth(allLanes[i], pool); + + this.forceToUpdateLane(allLanes[i]); + } + + this.hashedPoolPositions[pool.id] = pool.bounds.clone(); + + + // Update selection + //this.facade.setSelection(selection); }, - - shouldScale: function(element){ - var childLanes = element.getChildNodes().findAll(function(shape){ return shape.getStencil().id().endsWith("Lane") }) - return childLanes.length > 1 || childLanes.any(function(lane){ return this.shouldScale(lane) }.bind(this)) + + shouldScale: function (element) { + var childLanes = element.getChildNodes().findAll(function (shape) { + return shape.getStencil().id().endsWith("Lane") + }) + return childLanes.length > 1 || childLanes.any(function (lane) { + return this.shouldScale(lane) + }.bind(this)) }, - + /** * Lookup if some bounds has changed * @param {Object} lanes * @param {Object} changes */ - checkForChanges: function(lanes, changes){ - // Check if something has changed - if (this.facade.isExecutingCommands() && changes.any(function(change){ - return change.shape.bounds.toString() !== change.bounds.toString(); - })){ - - var Command = ORYX.Core.Command.extend({ - construct: function(changes) { - this.oldState = changes; - this.newState = changes.map(function(s){ return {shape:s.shape, bounds:s.bounds.clone()}}); - }, - execute: function(){ - if (this.executed){ - this.applyState(this.newState); - } - this.executed = true; - }, - rollback: function(){ - this.applyState(this.oldState); - }, - applyState: function(state){ - state.each(function(s){ - s.shape.bounds.set(s.bounds.upperLeft(), s.bounds.lowerRight()); - }) - } - }); - - this.facade.executeCommands([new Command(changes)]); - } - }, - - isResized: function(shape, bounds){ - - if (!bounds||!shape){ - return false; - } - - var oldB = bounds; - //var oldXY = oldB.upperLeft(); - //var xy = shape.absoluteXY(); - return Math.round(oldB.width() - shape.bounds.width()) !== 0 || Math.round(oldB.height() - shape.bounds.height()) !== 0 - }, - - adjustLanes: function(pool, lanes, x, y, scale){ - - scale = scale || 0; - - // For every lane, adjust the child nodes with the offset - lanes.each(function(l){ - l.getChildNodes().each(function(child){ - if (!child.getStencil().id().endsWith("Lane")){ - var cy = scale ? child.bounds.center().y - (child.bounds.center().y/scale) : -y; - child.bounds.moveBy((x||0), -cy); - - if (scale&&child.getStencil().id().endsWith("Subprocess")) { - this.moveChildDockers(child, {x:(0), y:-cy}); - } - - } - }.bind(this)); - this.hashedBounds[pool.id][l.id].moveBy(-(x||0), !scale?-y:0); - if (scale) { - l.isScaled = true; + checkForChanges: function (lanes, changes) { + // Check if something has changed + if (this.facade.isExecutingCommands() && changes.any(function (change) { + return change.shape.bounds.toString() !== change.bounds.toString(); + })) { + + var Command = ORYX.Core.Command.extend({ + construct: function (changes) { + this.oldState = changes; + this.newState = changes.map(function (s) { + return {shape: s.shape, bounds: s.bounds.clone()} + }); + }, + execute: function () { + if (this.executed) { + this.applyState(this.newState); } - }.bind(this)) - + this.executed = true; + }, + rollback: function () { + this.applyState(this.oldState); + }, + applyState: function (state) { + state.each(function (s) { + s.shape.bounds.set(s.bounds.upperLeft(), s.bounds.lowerRight()); + }) + } + }); + + this.facade.executeCommands([new Command(changes)]); + } + }, + + isResized: function (shape, bounds) { + + if (!bounds || !shape) { + return false; + } + + var oldB = bounds; + //var oldXY = oldB.upperLeft(); + //var xy = shape.absoluteXY(); + return Math.round(oldB.width() - shape.bounds.width()) !== 0 || Math.round(oldB.height() - shape.bounds.height()) !== 0 }, - - getAllExcludedLanes: function(parent, lane){ - var lanes = []; - parent.getChildNodes().each(function(shape){ - if ((!lane || shape !== lane) && shape.getStencil().id().endsWith("Lane")){ - lanes.push(shape); - lanes = lanes.concat(this.getAllExcludedLanes(shape, lane)); + + adjustLanes: function (pool, lanes, x, y, scale) { + + scale = scale || 0; + + // For every lane, adjust the child nodes with the offset + lanes.each(function (l) { + l.getChildNodes().each(function (child) { + if (!child.getStencil().id().endsWith("Lane")) { + var cy = scale ? child.bounds.center().y - (child.bounds.center().y / scale) : -y; + child.bounds.moveBy((x || 0), -cy); + + if (scale && child.getStencil().id().endsWith("Subprocess")) { + this.moveChildDockers(child, {x: (0), y: -cy}); } + + } }.bind(this)); - return lanes; - }, - - - forceToUpdateLane: function(lane){ - - if (lane.bounds.height() !== lane._svgShapes[0].height) { - lane.isChanged = true; - lane.isResized = true; - lane._update(); + this.hashedBounds[pool.id][l.id].moveBy(-(x || 0), !scale ? -y : 0); + if (scale) { + l.isScaled = true; } + }.bind(this)) + }, - - getDepth: function(child, parent){ - - var i=0; - while(child && child.parent && child !== parent){ - child = child.parent; - ++i + + getAllExcludedLanes: function (parent, lane) { + var lanes = []; + parent.getChildNodes().each(function (shape) { + if ((!lane || shape !== lane) && shape.getStencil().id().endsWith("Lane")) { + lanes.push(shape); + lanes = lanes.concat(this.getAllExcludedLanes(shape, lane)); } - return i; + }.bind(this)); + return lanes; }, - - updateDepth: function(lane, fromDepth, toDepth){ - - var xOffset = (fromDepth - toDepth) * 30; - - lane.getChildNodes().each(function(shape){ - shape.bounds.moveBy(xOffset, 0); - - [].concat(children[j].getIncomingShapes()) - .concat(children[j].getOutgoingShapes()) - - }) - + + + forceToUpdateLane: function (lane) { + + if (lane.bounds.height() !== lane._svgShapes[0].height) { + lane.isChanged = true; + lane.isResized = true; + lane._update(); + } }, - - setDimensions: function(shape, width, height, x, y){ - var isLane = shape.getStencil().id().endsWith("Lane"); - // Set the bounds - shape.bounds.set( - isLane ? 30 : (shape.bounds.a.x - (x || 0)), - isLane ? shape.bounds.a.y : (shape.bounds.a.y - (y || 0)), - width ? shape.bounds.a.x + width - (isLane?30:(x||0)) : shape.bounds.b.x, - height ? shape.bounds.a.y + height - (isLane?0:(y||0)) : shape.bounds.b.y - ); + + getDepth: function (child, parent) { + + var i = 0; + while (child && child.parent && child !== parent) { + child = child.parent; + ++i + } + return i; + }, + + updateDepth: function (lane, fromDepth, toDepth) { + + var xOffset = (fromDepth - toDepth) * 30; + + lane.getChildNodes().each(function (shape) { + shape.bounds.moveBy(xOffset, 0); + + [].concat(children[j].getIncomingShapes()) + .concat(children[j].getOutgoingShapes()) + + }) + + }, + + setDimensions: function (shape, width, height, x, y) { + var isLane = shape.getStencil().id().endsWith("Lane"); + // Set the bounds + shape.bounds.set( + isLane ? 30 : (shape.bounds.a.x - (x || 0)), + isLane ? shape.bounds.a.y : (shape.bounds.a.y - (y || 0)), + width ? shape.bounds.a.x + width - (isLane ? 30 : (x || 0)) : shape.bounds.b.x, + height ? shape.bounds.a.y + height - (isLane ? 0 : (y || 0)) : shape.bounds.b.y + ); + }, + + setLanePosition: function (shape, y) { + + shape.bounds.moveTo(30, y); + + }, + + adjustWidth: function (lanes, width) { + + // Set width to each lane + (lanes || []).each(function (lane) { + this.setDimensions(lane, width); + this.adjustWidth(this.getLanes(lane), width - 30); + }.bind(this)); + + return width; }, - setLanePosition: function(shape, y){ - - shape.bounds.moveTo(30, y); - - }, - - adjustWidth: function(lanes, width) { - - // Set width to each lane - (lanes||[]).each(function(lane){ - this.setDimensions(lane, width); - this.adjustWidth(this.getLanes(lane), width-30); - }.bind(this)); - - return width; - }, - - - adjustHeight: function(lanes, changedLane, propagateHeight){ - - var oldHeight = 0; - if (!changedLane && propagateHeight){ - var i=-1; - while (++i2 && edges[k].dockers[l-1].isDocked()){ + + l = -1; + while (++l < edges[k].dockers.length) { + + docker = edges[k].dockers[l]; + + if (docker.getDockedShape() || docker.isChanged) { + continue; + } + + + pos = docker.bounds.center(); + + // Check if the modified center included the new position + var isOverLane = oldBounds.isIncluded(pos); + // Check if the original center is over the pool + var isOutSidePool = !oldPool.isIncluded(pos); + var previousIsOverLane = l == 0 ? isOverLane : oldBounds.isIncluded(edges[k].dockers[l - 1].bounds.center()); + var nextIsOverLane = l == edges[k].dockers.length - 1 ? isOverLane : oldBounds.isIncluded(edges[k].dockers[l + 1].bounds.center()); + var off = Object.clone(offset); + + // If the + if (isScaled && isOverLane && this.isResized(lanes[i], this.hashedBounds[pool.id][lanes[i].id])) { + var relY = (pos.y - absBounds.upperLeft().y + off.y); + off.y -= (relY - (relY * (absBounds.height() / oldBounds.height()))); + } + + // Check if the previous dockers docked shape is from this lane + // Otherwise, check if the docker is over the lane OR is outside the lane + // but the previous/next was over this lane + if (isOverLane) { + dockers[docker.id] = {docker: docker, offset: off}; + } + /*else if (l == 1 && edges[k].dockers.length>2 && edges[k].dockers[l-1].isDocked()){ var dockedLane = this.getNextLane(edges[k].dockers[l-1].getDockedShape()); if (dockedLane != lanes[i]) continue; @@ -24087,422 +24837,427 @@ new function(){ continue; dockers[docker.id] = {docker: docker, offset:offset}; } - + else if (isOutSidePool) { dockers[docker.id] = {docker: docker, offset:this.getOffset(lanes[i], true, pool)}; }*/ - - - } - } - + + } + } + } - - // Move the moved children - var MoveChildCommand = ORYX.Core.Command.extend({ - construct: function(state){ - this.state = state; - }, - execute: function(){ - if (this.executed){ - this.state.each(function(s){ - s.shape.bounds.moveBy(s.xOffset, 0); - }); - } - this.executed = true; - }, - rollback: function(){ - this.state.each(function(s){ - s.shape.bounds.moveBy(-s.xOffset, 0); - }); - } - }) - - - // Set dockers - this.facade.executeCommands([new ORYX.Core.MoveDockersCommand(dockers), new MoveChildCommand(movedShapes)]); + } + + // Move the moved children + var MoveChildCommand = ORYX.Core.Command.extend({ + construct: function (state) { + this.state = state; + }, + execute: function () { + if (this.executed) { + this.state.each(function (s) { + s.shape.bounds.moveBy(s.xOffset, 0); + }); + } + this.executed = true; + }, + rollback: function () { + this.state.each(function (s) { + s.shape.bounds.moveBy(-s.xOffset, 0); + }); + } + }) + + + // Set dockers + this.facade.executeCommands([new ORYX.Core.MoveDockersCommand(dockers), new MoveChildCommand(movedShapes)]); }, - - moveBy: function(pos, offset){ - pos.x += offset.x; - pos.y += offset.y; - return pos; + + moveBy: function (pos, offset) { + pos.x += offset.x; + pos.y += offset.y; + return pos; }, - - getHashedBounds: function(shape){ - return this.currentPool && this.hashedBounds[this.currentPool.id][shape.id] ? this.hashedBounds[this.currentPool.id][shape.id] : shape.absoluteBounds(); + + getHashedBounds: function (shape) { + return this.currentPool && this.hashedBounds[this.currentPool.id][shape.id] ? this.hashedBounds[this.currentPool.id][shape.id] : shape.absoluteBounds(); }, - + /** * Returns a set on all child lanes for the given Shape. If recursive is TRUE, also indirect children will be returned (default is FALSE) * The set is sorted with first child the lowest y-coordinate and the last one the highest. * @param {ORYX.Core.Shape} shape * @param {boolean} recursive */ - getLanes: function(shape, recursive){ - var namespace = this.getNamespace(); - - // Get all the child lanes - var lanes = shape.getChildNodes(recursive||false).findAll(function(node) { return (node.getStencil().id() === namespace + "Lane"); }); - - // Sort all lanes by there y coordinate - lanes = lanes.sort(function(a, b){ - - // Get y coordinates for upper left and lower right - var auy = Math.round(a.bounds.upperLeft().y); - var buy = Math.round(b.bounds.upperLeft().y); - var aly = Math.round(a.bounds.lowerRight().y); - var bly = Math.round(b.bounds.lowerRight().y); - - var ha = this.getHashedBounds(a); - var hb = this.getHashedBounds(b); - - // Get the old y coordinates - var oauy = Math.round(ha.upperLeft().y); - var obuy = Math.round(hb.upperLeft().y); - var oaly = Math.round(ha.lowerRight().y); - var obly = Math.round(hb.lowerRight().y); - - // If equal, than use the old one - if (auy == buy && aly == bly) { - auy = oauy; buy = obuy; aly = oaly; bly = obly; - } - - if (Math.round(a.bounds.height()-ha.height()) === 0 && Math.round(b.bounds.height()-hb.height()) === 0){ - return auy < buy ? -1 : (auy > buy ? 1: 0); - } - - // Check if upper left and lower right is completely above/below - var above = auy < buy && aly < bly; - var below = auy > buy && aly > bly; - // Check if a is above b including the old values - var slightlyAboveBottom = auy < buy && aly >= bly && oaly < obly; - var slightlyAboveTop = auy >= buy && aly < bly && oauy < obuy; - // Check if a is below b including the old values - var slightlyBelowBottom = auy > buy && aly <= bly && oaly > obly; - var slightlyBelowTop = auy <= buy && aly > bly && oauy > obuy; - - // Return -1 if a is above b, 1 if b is above a, or 0 otherwise - return (above || slightlyAboveBottom || slightlyAboveTop ? -1 : (below || slightlyBelowBottom || slightlyBelowTop ? 1 : 0)) - }.bind(this)); - - // Return lanes - return lanes; + getLanes: function (shape, recursive) { + var namespace = this.getNamespace(); + + // Get all the child lanes + var lanes = shape.getChildNodes(recursive || false).findAll(function (node) { + return (node.getStencil().id() === namespace + "Lane"); + }); + + // Sort all lanes by there y coordinate + lanes = lanes.sort(function (a, b) { + + // Get y coordinates for upper left and lower right + var auy = Math.round(a.bounds.upperLeft().y); + var buy = Math.round(b.bounds.upperLeft().y); + var aly = Math.round(a.bounds.lowerRight().y); + var bly = Math.round(b.bounds.lowerRight().y); + + var ha = this.getHashedBounds(a); + var hb = this.getHashedBounds(b); + + // Get the old y coordinates + var oauy = Math.round(ha.upperLeft().y); + var obuy = Math.round(hb.upperLeft().y); + var oaly = Math.round(ha.lowerRight().y); + var obly = Math.round(hb.lowerRight().y); + + // If equal, than use the old one + if (auy == buy && aly == bly) { + auy = oauy; + buy = obuy; + aly = oaly; + bly = obly; + } + + if (Math.round(a.bounds.height() - ha.height()) === 0 && Math.round(b.bounds.height() - hb.height()) === 0) { + return auy < buy ? -1 : (auy > buy ? 1 : 0); + } + + // Check if upper left and lower right is completely above/below + var above = auy < buy && aly < bly; + var below = auy > buy && aly > bly; + // Check if a is above b including the old values + var slightlyAboveBottom = auy < buy && aly >= bly && oaly < obly; + var slightlyAboveTop = auy >= buy && aly < bly && oauy < obuy; + // Check if a is below b including the old values + var slightlyBelowBottom = auy > buy && aly <= bly && oaly > obly; + var slightlyBelowTop = auy <= buy && aly > bly && oauy > obuy; + + // Return -1 if a is above b, 1 if b is above a, or 0 otherwise + return (above || slightlyAboveBottom || slightlyAboveTop ? -1 : (below || slightlyBelowBottom || slightlyBelowTop ? 1 : 0)) + }.bind(this)); + + // Return lanes + return lanes; }, - - getNamespace: function() { - if(!this.namespace) { - var stencilsets = this.facade.getStencilSets(); - if(stencilsets.keys()) { - this.namespace = stencilsets.keys()[0]; - } else { - return undefined; - } + + getNamespace: function () { + if (!this.namespace) { + var stencilsets = this.facade.getStencilSets(); + if (stencilsets.keys()) { + this.namespace = stencilsets.keys()[0]; + } else { + return undefined; } - return this.namespace; - } - }; - - var ResizeLanesCommand = ORYX.Core.Command.extend({ - - construct: function(shape, parent, pool, plugin) { - - this.facade = plugin.facade; - this.plugin = plugin; - this.shape = shape; - this.changes; - - this.pool = pool; - - this.parent = parent; - - - this.shapeChildren = []; - - /* + } + return this.namespace; + } + }; + + var ResizeLanesCommand = ORYX.Core.Command.extend({ + + construct: function (shape, parent, pool, plugin) { + + this.facade = plugin.facade; + this.plugin = plugin; + this.shape = shape; + this.changes; + + this.pool = pool; + + this.parent = parent; + + + this.shapeChildren = []; + + /* * The Bounds have to be stored * separate because they would * otherwise also be influenced */ - this.shape.getChildShapes().each(function(childShape) { - this.shapeChildren.push({ - shape: childShape, - bounds: { - a: { - x: childShape.bounds.a.x, - y: childShape.bounds.a.y - }, - b: { - x: childShape.bounds.b.x, - y: childShape.bounds.b.y - } - } - }); - }.bind(this)); + this.shape.getChildShapes().each(function (childShape) { + this.shapeChildren.push({ + shape: childShape, + bounds: { + a: { + x: childShape.bounds.a.x, + y: childShape.bounds.a.y + }, + b: { + x: childShape.bounds.b.x, + y: childShape.bounds.b.y + } + } + }); + }.bind(this)); + + this.shapeUpperLeft = this.shape.bounds.upperLeft(); - this.shapeUpperLeft = this.shape.bounds.upperLeft(); - - // If there is no parent, - // correct the abs position with the parents abs. - /*if (!this.shape.parent) { + // If there is no parent, + // correct the abs position with the parents abs. + /*if (!this.shape.parent) { var pAbs = parent.absoluteXY(); this.shapeUpperLeft.x += pAbs.x; this.shapeUpperLeft.y += pAbs.y; }*/ - this.parentHeight = this.parent.bounds.height(); + this.parentHeight = this.parent.bounds.height(); }, - - getLeafLanes: function(lane){ - var childLanes = this.plugin.getLanes(lane).map(function(child){ - return this.getLeafLanes(child); - }.bind(this)).flatten(); - return childLanes.length > 0 ? childLanes : [lane]; + + getLeafLanes: function (lane) { + var childLanes = this.plugin.getLanes(lane).map(function (child) { + return this.getLeafLanes(child); + }.bind(this)).flatten(); + return childLanes.length > 0 ? childLanes : [lane]; }, - - findNewLane: function(){ - - var lanes = this.plugin.getLanes(this.parent); - var leafLanes = this.getLeafLanes(this.parent); - /*leafLanes = leafLanes.sort(function(a,b){ + findNewLane: function () { + + var lanes = this.plugin.getLanes(this.parent); + + var leafLanes = this.getLeafLanes(this.parent); + /*leafLanes = leafLanes.sort(function(a,b){ var aupl = a.absoluteXY().y; var bupl = b.absoluteXY().y; return aupl < bupl ? -1 : (aupl > bupl ? 1 : 0) })*/ - this.lane = leafLanes.find(function(l){ return l.bounds.upperLeft().y >= this.shapeUpperLeft.y }.bind(this)) || leafLanes.last(); - this.laneUpperLeft = this.lane.bounds.upperLeft(); + this.lane = leafLanes.find(function (l) { + return l.bounds.upperLeft().y >= this.shapeUpperLeft.y + }.bind(this)) || leafLanes.last(); + this.laneUpperLeft = this.lane.bounds.upperLeft(); }, - - execute: function() { - - if(this.changes) { - this.executeAgain(); - return; - } - /* + execute: function () { + + if (this.changes) { + this.executeAgain(); + return; + } + + /* * Rescue all ChildShapes of the deleted * Shape into the lane that takes its * place */ - - if (!this.lane){ - this.findNewLane(); - } - - if(this.lane) { - - var laUpL = this.laneUpperLeft; - var shUpL = this.shapeUpperLeft; - - var depthChange = this.plugin.getDepth(this.lane, this.parent)-1; - - this.changes = $H({}); - - // Selected lane is BELOW the removed lane - if (laUpL.y >= shUpL.y) { - this.lane.getChildShapes().each(function(childShape) { - - /* + + if (!this.lane) { + this.findNewLane(); + } + + if (this.lane) { + + var laUpL = this.laneUpperLeft; + var shUpL = this.shapeUpperLeft; + + var depthChange = this.plugin.getDepth(this.lane, this.parent) - 1; + + this.changes = $H({}); + + // Selected lane is BELOW the removed lane + if (laUpL.y >= shUpL.y) { + this.lane.getChildShapes().each(function (childShape) { + + /* * Cache the changes for rollback */ - if(!this.changes[childShape.getId()]) { - this.changes[childShape.getId()] = this.computeChanges(childShape, this.lane, this.lane, this.shape.bounds.height()); - } - - childShape.bounds.moveBy(0, this.shape.bounds.height()); - }.bind(this)); - - this.plugin.hashChildShapes(this.lane); - - this.shapeChildren.each(function(shapeChild) { - shapeChild.shape.bounds.set(shapeChild.bounds); - shapeChild.shape.bounds.moveBy((shUpL.x-30)-(depthChange*30), 0); - - /* + if (!this.changes[childShape.getId()]) { + this.changes[childShape.getId()] = this.computeChanges(childShape, this.lane, this.lane, this.shape.bounds.height()); + } + + childShape.bounds.moveBy(0, this.shape.bounds.height()); + }.bind(this)); + + this.plugin.hashChildShapes(this.lane); + + this.shapeChildren.each(function (shapeChild) { + shapeChild.shape.bounds.set(shapeChild.bounds); + shapeChild.shape.bounds.moveBy((shUpL.x - 30) - (depthChange * 30), 0); + + /* * Cache the changes for rollback */ - if(!this.changes[shapeChild.shape.getId()]) { - this.changes[shapeChild.shape.getId()] = this.computeChanges(shapeChild.shape, this.shape, this.lane, 0); - } - - this.lane.add(shapeChild.shape); - - }.bind(this)); - - this.lane.bounds.moveBy(0, shUpL.y-laUpL.y); - - // Selected lane is ABOVE the removed lane - } else if(shUpL.y > laUpL.y){ - - this.shapeChildren.each(function(shapeChild) { - shapeChild.shape.bounds.set(shapeChild.bounds); - shapeChild.shape.bounds.moveBy((shUpL.x-30)-(depthChange*30), this.lane.bounds.height()); - - /* + if (!this.changes[shapeChild.shape.getId()]) { + this.changes[shapeChild.shape.getId()] = this.computeChanges(shapeChild.shape, this.shape, this.lane, 0); + } + + this.lane.add(shapeChild.shape); + + }.bind(this)); + + this.lane.bounds.moveBy(0, shUpL.y - laUpL.y); + + // Selected lane is ABOVE the removed lane + } else if (shUpL.y > laUpL.y) { + + this.shapeChildren.each(function (shapeChild) { + shapeChild.shape.bounds.set(shapeChild.bounds); + shapeChild.shape.bounds.moveBy((shUpL.x - 30) - (depthChange * 30), this.lane.bounds.height()); + + /* * Cache the changes for rollback */ - if(!this.changes[shapeChild.shape.getId()]) { - this.changes[shapeChild.shape.getId()] = this.computeChanges(shapeChild.shape, this.shape, this.lane, 0); - } - - this.lane.add(shapeChild.shape); - - }.bind(this)); + if (!this.changes[shapeChild.shape.getId()]) { + this.changes[shapeChild.shape.getId()] = this.computeChanges(shapeChild.shape, this.shape, this.lane, 0); } - - - + this.lane.add(shapeChild.shape); + + }.bind(this)); } - - /* + + + } + + /* * Adjust the height of the lanes */ - // Get the height values - var oldHeight = this.lane.bounds.height(); - var newHeight = this.lane.length === 1 ? this.parentHeight : this.lane.bounds.height() + this.shape.bounds.height(); - - // Set height - this.setHeight(newHeight, oldHeight, this.parent, this.parentHeight, true); - - // Cache all sibling lanes - //this.changes[this.shape.getId()] = this.computeChanges(this.shape, this.parent, this.parent, 0); - this.plugin.getLanes(this.parent).each(function(childLane){ - if(!this.changes[childLane.getId()] && childLane !== this.lane && childLane !== this.shape) { - this.changes[childLane.getId()] = this.computeChanges(childLane, this.parent, this.parent, 0); - } - }.bind(this)) - - // Update - this.update(); - }, - - setHeight: function(newHeight, oldHeight, parent, parentHeight, store){ - - // Set heigh of the lane - this.plugin.setDimensions(this.lane, this.lane.bounds.width(), newHeight); - this.plugin.hashedBounds[this.pool.id][this.lane.id] = this.lane.absoluteBounds(); - - // Adjust child lanes - this.plugin.adjustHeight(this.plugin.getLanes(parent), this.lane); - - if (store === true){ - // Store changes - this.changes[this.shape.getId()] = this.computeChanges(this.shape, parent, parent, 0, oldHeight, newHeight); - } - - // Set parents height - this.plugin.setDimensions(parent, parent.bounds.width(), parentHeight); - - if (parent !== this.pool){ - this.plugin.setDimensions(this.pool, this.pool.bounds.width(), this.pool.bounds.height() + (newHeight-oldHeight)); + // Get the height values + var oldHeight = this.lane.bounds.height(); + var newHeight = this.lane.length === 1 ? this.parentHeight : this.lane.bounds.height() + this.shape.bounds.height(); + + // Set height + this.setHeight(newHeight, oldHeight, this.parent, this.parentHeight, true); + + // Cache all sibling lanes + //this.changes[this.shape.getId()] = this.computeChanges(this.shape, this.parent, this.parent, 0); + this.plugin.getLanes(this.parent).each(function (childLane) { + if (!this.changes[childLane.getId()] && childLane !== this.lane && childLane !== this.shape) { + this.changes[childLane.getId()] = this.computeChanges(childLane, this.parent, this.parent, 0); } + }.bind(this)) + + // Update + this.update(); }, - - update: function(){ - - // Hack to prevent the updating of the dockers - this.plugin.hashedBounds[this.pool.id]["REMOVED"] = true; - // Update - //this.facade.getCanvas().update(); + + setHeight: function (newHeight, oldHeight, parent, parentHeight, store) { + + // Set heigh of the lane + this.plugin.setDimensions(this.lane, this.lane.bounds.width(), newHeight); + this.plugin.hashedBounds[this.pool.id][this.lane.id] = this.lane.absoluteBounds(); + + // Adjust child lanes + this.plugin.adjustHeight(this.plugin.getLanes(parent), this.lane); + + if (store === true) { + // Store changes + this.changes[this.shape.getId()] = this.computeChanges(this.shape, parent, parent, 0, oldHeight, newHeight); + } + + // Set parents height + this.plugin.setDimensions(parent, parent.bounds.width(), parentHeight); + + if (parent !== this.pool) { + this.plugin.setDimensions(this.pool, this.pool.bounds.width(), this.pool.bounds.height() + (newHeight - oldHeight)); + } }, - - rollback: function() { - - var laUpL = this.laneUpperLeft; - var shUpL = this.shapeUpperLeft; - - this.changes.each(function(pair) { - - var parent = pair.value.oldParent; - var shape = pair.value.shape; - var parentHeight = pair.value.parentHeight; - var oldHeight = pair.value.oldHeight; - var newHeight = pair.value.newHeight; - - // Move siblings - if (shape.getStencil().id().endsWith("Lane")){ - shape.bounds.moveTo(pair.value.oldPosition); - } - - // If lane - if(oldHeight) { - this.setHeight(oldHeight, newHeight, parent, parent.bounds.height() + (oldHeight - newHeight)); - if (laUpL.y >= shUpL.y) { - this.lane.bounds.moveBy(0, this.shape.bounds.height()-1); - } - } else { - parent.add(shape); - shape.bounds.moveTo(pair.value.oldPosition); - - } - - }.bind(this)); - - // Update - //this.update(); - + update: function () { + + // Hack to prevent the updating of the dockers + this.plugin.hashedBounds[this.pool.id]["REMOVED"] = true; + // Update + //this.facade.getCanvas().update(); }, - - executeAgain: function() { - - this.changes.each(function(pair) { - var parent = pair.value.newParent; - var shape = pair.value.shape; - var newHeight = pair.value.newHeight; - var oldHeight = pair.value.oldHeight; - - // If lane - if(newHeight) { - var laUpL = this.laneUpperLeft.y; - var shUpL = this.shapeUpperLeft.y; - - if (laUpL >= shUpL) { - this.lane.bounds.moveBy(0, shUpL - laUpL); - } - this.setHeight(newHeight, oldHeight, parent, parent.bounds.height() + (newHeight-oldHeight)); - } else { - parent.add(shape); - shape.bounds.moveTo(pair.value.newPosition); - } - - }.bind(this)); - - // Update - this.update(); + + rollback: function () { + + var laUpL = this.laneUpperLeft; + var shUpL = this.shapeUpperLeft; + + this.changes.each(function (pair) { + + var parent = pair.value.oldParent; + var shape = pair.value.shape; + var parentHeight = pair.value.parentHeight; + var oldHeight = pair.value.oldHeight; + var newHeight = pair.value.newHeight; + + // Move siblings + if (shape.getStencil().id().endsWith("Lane")) { + shape.bounds.moveTo(pair.value.oldPosition); + } + + // If lane + if (oldHeight) { + this.setHeight(oldHeight, newHeight, parent, parent.bounds.height() + (oldHeight - newHeight)); + if (laUpL.y >= shUpL.y) { + this.lane.bounds.moveBy(0, this.shape.bounds.height() - 1); + } + } else { + parent.add(shape); + shape.bounds.moveTo(pair.value.oldPosition); + + } + + + }.bind(this)); + + // Update + //this.update(); + }, - - computeChanges: function(shape, oldParent, parent, yOffset, oldHeight, newHeight) { - - oldParent = this.changes[shape.getId()] ? this.changes[shape.getId()].oldParent : oldParent; - var oldPosition = this.changes[shape.getId()] ? this.changes[shape.getId()].oldPosition : shape.bounds.upperLeft(); - - var sUl = shape.bounds.upperLeft(); - - var pos = {x: sUl.x, y: sUl.y + yOffset}; - - var changes = { - shape : shape, - parentHeight: oldParent.bounds.height(), - oldParent : oldParent, - oldPosition : oldPosition, - oldHeight : oldHeight, - newParent : parent, - newPosition : pos, - newHeight : newHeight - }; - - return changes; + + executeAgain: function () { + + this.changes.each(function (pair) { + var parent = pair.value.newParent; + var shape = pair.value.shape; + var newHeight = pair.value.newHeight; + var oldHeight = pair.value.oldHeight; + + // If lane + if (newHeight) { + var laUpL = this.laneUpperLeft.y; + var shUpL = this.shapeUpperLeft.y; + + if (laUpL >= shUpL) { + this.lane.bounds.moveBy(0, shUpL - laUpL); + } + this.setHeight(newHeight, oldHeight, parent, parent.bounds.height() + (newHeight - oldHeight)); + } else { + parent.add(shape); + shape.bounds.moveTo(pair.value.newPosition); + } + + }.bind(this)); + + // Update + this.update(); + }, + + computeChanges: function (shape, oldParent, parent, yOffset, oldHeight, newHeight) { + + oldParent = this.changes[shape.getId()] ? this.changes[shape.getId()].oldParent : oldParent; + var oldPosition = this.changes[shape.getId()] ? this.changes[shape.getId()].oldPosition : shape.bounds.upperLeft(); + + var sUl = shape.bounds.upperLeft(); + + var pos = {x: sUl.x, y: sUl.y + yOffset}; + + var changes = { + shape: shape, + parentHeight: oldParent.bounds.height(), + oldParent: oldParent, + oldPosition: oldPosition, + oldHeight: oldHeight, + newParent: parent, + newPosition: pos, + newHeight: newHeight + }; + + return changes; } - - }); - - ORYX.Plugins.BPMN2_0 = ORYX.Plugins.AbstractPlugin.extend(ORYX.Plugins.BPMN2_0); - + }); + + + ORYX.Plugins.BPMN2_0 = ORYX.Plugins.AbstractPlugin.extend(ORYX.Plugins.BPMN2_0); + }() \ No newline at end of file diff --git a/web/src/main/resources/static/editor-app/popups/save-model.html b/web/src/main/resources/static/editor-app/popups/save-model.html index 471daf44a97e8fa9c371de031ce346aed09c6705..b8f0340f4a74ed023e21d25a2ccef1cda8325c68 100644 --- a/web/src/main/resources/static/editor-app/popups/save-model.html +++ b/web/src/main/resources/static/editor-app/popups/save-model.html @@ -15,7 +15,7 @@ class="form-control" ng-model="saveDialog.name" ui-keypress="{13:'save()'}" - auto-focus /> + auto-focus readonly/>
diff --git a/web/src/main/resources/static/editor-app/stencil-controller.js b/web/src/main/resources/static/editor-app/stencil-controller.js index ca40b33a6bad0c33be87ae6fbf6fa268b42f9883..bcc7063cb61a4c32fb1b766cc101a04076bc740e 100644 --- a/web/src/main/resources/static/editor-app/stencil-controller.js +++ b/web/src/main/resources/static/editor-app/stencil-controller.js @@ -33,10 +33,10 @@ angular.module('activitiModeler') jQuery(window).trigger('resize'); }); }; - + // Code that is dependent on an initialised Editor is wrapped in a promise for the editor $scope.editorFactory.promise.then(function () { - + /* Build stencil item list */ // Build simple json representation of stencil set @@ -54,7 +54,7 @@ angular.module('activitiModeler') // Helper method: add a new group to an array of groups var addGroup = function (groupName, groupArray) { - var group = { name: groupName, items: [], paletteItems: [], groups: [], visible: true }; + var group = {name: groupName, items: [], paletteItems: [], groups: [], visible: true}; groupArray.push(group); return group; }; @@ -64,29 +64,27 @@ angular.module('activitiModeler') */ $http({method: 'GET', url: KISBPM.URL.getStencilSet()}).success(function (data, status, headers, config) { - var quickMenuDefinition = ['UserTask', 'EndNoneEvent', 'ExclusiveGateway', - 'CatchTimerEvent', 'ThrowNoneEvent', 'TextAnnotation', - 'SequenceFlow', 'Association']; - var ignoreForPaletteDefinition = ['SequenceFlow', 'MessageFlow', 'Association', 'DataAssociation', 'DataStore', 'SendTask']; - var quickMenuItems = []; - - var morphRoles = []; - for (var i = 0; i < data.rules.morphingRules.length; i++) - { + var quickMenuDefinition = ['UserTask', 'EndNoneEvent', 'ExclusiveGateway', + 'CatchTimerEvent', 'ThrowNoneEvent', 'TextAnnotation', + 'SequenceFlow', 'Association']; + var ignoreForPaletteDefinition = ['SequenceFlow', 'MessageFlow', 'Association', 'DataAssociation', 'DataStore', 'SendTask']; + var quickMenuItems = []; + + var morphRoles = []; + for (var i = 0; i < data.rules.morphingRules.length; i++) { var role = data.rules.morphingRules[i].role; var roleItem = {'role': role, 'morphOptions': []}; morphRoles.push(roleItem); } - + // Check all received items - for (var stencilIndex = 0; stencilIndex < data.stencils.length; stencilIndex++) - { - // Check if the root group is the 'diagram' group. If so, this item should not be shown. + for (var stencilIndex = 0; stencilIndex < data.stencils.length; stencilIndex++) { + // Check if the root group is the 'diagram' group. If so, this item should not be shown. var currentGroupName = data.stencils[stencilIndex].groups[0]; if (currentGroupName === 'Diagram' || currentGroupName === 'Form') { continue; // go to next item } - + var removed = false; if (data.stencils[stencilIndex].removed) { removed = true; @@ -119,9 +117,10 @@ angular.module('activitiModeler') } } - + // Construct the stencil item - var stencilItem = {'id': data.stencils[stencilIndex].id, + var stencilItem = { + 'id': data.stencils[stencilIndex].id, 'name': data.stencils[stencilIndex].title, 'description': data.stencils[stencilIndex].description, 'icon': data.stencils[stencilIndex].icon, @@ -131,48 +130,49 @@ angular.module('activitiModeler') 'customIcon': false, 'canConnect': false, 'canConnectTo': false, - 'canConnectAssociation': false}; - + 'canConnectAssociation': false + }; + if (data.stencils[stencilIndex].customIconId && data.stencils[stencilIndex].customIconId > 0) { stencilItem.customIcon = true; stencilItem.icon = data.stencils[stencilIndex].customIconId; } - + if (!removed) { if (quickMenuDefinition.indexOf(stencilItem.id) >= 0) { - quickMenuItems[quickMenuDefinition.indexOf(stencilItem.id)] = stencilItem; + quickMenuItems[quickMenuDefinition.indexOf(stencilItem.id)] = stencilItem; } } - + if (stencilItem.id === 'TextAnnotation' || stencilItem.id === 'BoundaryCompensationEvent') { - stencilItem.canConnectAssociation = true; + stencilItem.canConnectAssociation = true; } - + for (var i = 0; i < data.stencils[stencilIndex].roles.length; i++) { - var stencilRole = data.stencils[stencilIndex].roles[i]; - if (stencilRole === 'sequence_start') { - stencilItem.canConnect = true; - } else if (stencilRole === 'sequence_end') { - stencilItem.canConnectTo = true; - } - - for (var j = 0; j < morphRoles.length; j++) { - if (stencilRole === morphRoles[j].role) { - if (!removed) { - morphRoles[j].morphOptions.push(stencilItem); - } - stencilItem.morphRole = morphRoles[j].role; - break; - } - } + var stencilRole = data.stencils[stencilIndex].roles[i]; + if (stencilRole === 'sequence_start') { + stencilItem.canConnect = true; + } else if (stencilRole === 'sequence_end') { + stencilItem.canConnectTo = true; + } + + for (var j = 0; j < morphRoles.length; j++) { + if (stencilRole === morphRoles[j].role) { + if (!removed) { + morphRoles[j].morphOptions.push(stencilItem); + } + stencilItem.morphRole = morphRoles[j].role; + break; + } + } } if (currentGroup) { - // Add the stencil item to the correct group - currentGroup.items.push(stencilItem); - if (ignoreForPaletteDefinition.indexOf(stencilItem.id) < 0) { - currentGroup.paletteItems.push(stencilItem); - } + // Add the stencil item to the correct group + currentGroup.items.push(stencilItem); + if (ignoreForPaletteDefinition.indexOf(stencilItem.id) < 0) { + currentGroup.paletteItems.push(stencilItem); + } } else { // It's a root stencil element @@ -181,39 +181,33 @@ angular.module('activitiModeler') } } } - - for (var i = 0; i < stencilItemGroups.length; i++) - { - if (stencilItemGroups[i].paletteItems && stencilItemGroups[i].paletteItems.length == 0) - { - stencilItemGroups[i].visible = false; - } + + for (var i = 0; i < stencilItemGroups.length; i++) { + if (stencilItemGroups[i].paletteItems && stencilItemGroups[i].paletteItems.length == 0) { + stencilItemGroups[i].visible = false; + } } - + $scope.stencilItemGroups = stencilItemGroups; var containmentRules = []; - for (var i = 0; i < data.rules.containmentRules.length; i++) - { + for (var i = 0; i < data.rules.containmentRules.length; i++) { var rule = data.rules.containmentRules[i]; containmentRules.push(rule); } $scope.containmentRules = containmentRules; - + // remove quick menu items which are not available anymore due to custom pallette var availableQuickMenuItems = []; - for (var i = 0; i < quickMenuItems.length; i++) - { + for (var i = 0; i < quickMenuItems.length; i++) { if (quickMenuItems[i]) { availableQuickMenuItems[availableQuickMenuItems.length] = quickMenuItems[i]; } } - + $scope.quickMenuItems = availableQuickMenuItems; $scope.morphRoles = morphRoles; - }). - - error(function (data, status, headers, config) { + }).error(function (data, status, headers, config) { console.log('Something went wrong when fetching stencil items:' + JSON.stringify(data)); }); @@ -231,22 +225,20 @@ angular.module('activitiModeler') var selectedShape = shapes.first(); var stencil = selectedShape.getStencil(); - - if ($rootScope.selectedElementBeforeScrolling && stencil.id().indexOf('BPMNDiagram') !== -1) - { - // ignore canvas event because of empty selection when scrolling stops - return; + + if ($rootScope.selectedElementBeforeScrolling && stencil.id().indexOf('BPMNDiagram') !== -1) { + // ignore canvas event because of empty selection when scrolling stops + return; } - - if ($rootScope.selectedElementBeforeScrolling && $rootScope.selectedElementBeforeScrolling.getId() === selectedShape.getId()) - { - $rootScope.selectedElementBeforeScrolling = null; - return; + + if ($rootScope.selectedElementBeforeScrolling && $rootScope.selectedElementBeforeScrolling.getId() === selectedShape.getId()) { + $rootScope.selectedElementBeforeScrolling = null; + return; } // Store previous selection $scope.previousSelectedShape = $scope.selectedShape; - + // Only do something if another element is selected (Oryx fires this event multiple times) if ($scope.selectedShape !== undefined && $scope.selectedShape.getId() === selectedShape.getId()) { if ($rootScope.forceSelectionRefresh) { @@ -287,17 +279,14 @@ angular.module('activitiModeler') if (propertyConfig === undefined || propertyConfig === null) { console.log('WARNING: no property configuration defined for ' + key + ' of type ' + property.type()); } else { - if (selectedShape.properties[key] === 'true') { selectedShape.properties[key] = true; } - - if (KISBPM.CONFIG.showRemovedProperties == false && property.isHidden()) - { - continue; + if (KISBPM.CONFIG.showRemovedProperties == false && property.isHidden()) { + continue; } - - //右侧属性栏对象 + + // 右侧属性栏对象 var currentProperty = { 'key': key, 'title': property.title(), @@ -305,9 +294,10 @@ angular.module('activitiModeler') 'mode': 'read', 'hidden': property.isHidden(), 'description': property.description(), + 'readOnly': isNull(property.readOnly()) ? false : property.readOnly(), 'value': selectedShape.properties[key] }; - + if ((currentProperty.type === 'complex' || currentProperty.type === 'multiplecomplex') && currentProperty.value && currentProperty.value.length > 0) { try { currentProperty.value = JSON.parse(currentProperty.value); @@ -320,14 +310,13 @@ angular.module('activitiModeler') currentProperty.readModeTemplateUrl = propertyConfig.readModeTemplateUrl + '?version=' + $rootScope.staticIncludeVersion; } if (propertyConfig.writeModeTemplateUrl !== null && propertyConfig.writeModeTemplateUrl !== null) { - currentProperty.writeModeTemplateUrl = propertyConfig.writeModeTemplateUrl + '?version=' + $rootScope.staticIncludeVersion; + currentProperty.writeModeTemplateUrl = propertyConfig.writeModeTemplateUrl + '?version=' + $rootScope.staticIncludeVersion; } if (propertyConfig.templateUrl !== undefined && propertyConfig.templateUrl !== null) { currentProperty.templateUrl = propertyConfig.templateUrl + '?version=' + $rootScope.staticIncludeVersion; currentProperty.hasReadWriteMode = false; - } - else { + } else { currentProperty.hasReadWriteMode = true; } @@ -354,25 +343,25 @@ angular.module('activitiModeler') }); } }); - + $scope.editor.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, function (event) { - - KISBPM.eventBus.dispatch(KISBPM.eventBus.EVENT_TYPE_HIDE_SHAPE_BUTTONS); - var shapes = event.elements; - + + KISBPM.eventBus.dispatch(KISBPM.eventBus.EVENT_TYPE_HIDE_SHAPE_BUTTONS); + var shapes = event.elements; + if (shapes && shapes.length == 1) { var selectedShape = shapes.first(); - + var a = $scope.editor.getCanvas().node.getScreenCTM(); - - var absoluteXY = selectedShape.absoluteXY(); - - absoluteXY.x *= a.a; - absoluteXY.y *= a.d; - - var additionalIEZoom = 1; - if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + + var absoluteXY = selectedShape.absoluteXY(); + + absoluteXY.x *= a.a; + absoluteXY.y *= a.d; + + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { var ua = navigator.userAgent; if (ua.indexOf('MSIE') >= 0) { //IE 10 and below @@ -382,131 +371,124 @@ angular.module('activitiModeler') } } } - - if (additionalIEZoom === 1) { - absoluteXY.y = absoluteXY.y - jQuery("#canvasSection").offset().top + 5; - absoluteXY.x = absoluteXY.x - jQuery("#canvasSection").offset().left; - - } else { - var canvasOffsetLeft = jQuery("#canvasSection").offset().left; - var canvasScrollLeft = jQuery("#canvasSection").scrollLeft(); - var canvasScrollTop = jQuery("#canvasSection").scrollTop(); - - var offset = a.e - (canvasOffsetLeft * additionalIEZoom); - var additionaloffset = 0; - if (offset > 10) { - additionaloffset = (offset / additionalIEZoom) - offset; - } - absoluteXY.y = absoluteXY.y - (jQuery("#canvasSection").offset().top * additionalIEZoom) + 5 + ((canvasScrollTop * additionalIEZoom) - canvasScrollTop); - absoluteXY.x = absoluteXY.x - (canvasOffsetLeft * additionalIEZoom) + additionaloffset + ((canvasScrollLeft * additionalIEZoom) - canvasScrollLeft); + + if (additionalIEZoom === 1) { + absoluteXY.y = absoluteXY.y - jQuery("#canvasSection").offset().top + 5; + absoluteXY.x = absoluteXY.x - jQuery("#canvasSection").offset().left; + + } else { + var canvasOffsetLeft = jQuery("#canvasSection").offset().left; + var canvasScrollLeft = jQuery("#canvasSection").scrollLeft(); + var canvasScrollTop = jQuery("#canvasSection").scrollTop(); + + var offset = a.e - (canvasOffsetLeft * additionalIEZoom); + var additionaloffset = 0; + if (offset > 10) { + additionaloffset = (offset / additionalIEZoom) - offset; + } + absoluteXY.y = absoluteXY.y - (jQuery("#canvasSection").offset().top * additionalIEZoom) + 5 + ((canvasScrollTop * additionalIEZoom) - canvasScrollTop); + absoluteXY.x = absoluteXY.x - (canvasOffsetLeft * additionalIEZoom) + additionaloffset + ((canvasScrollLeft * additionalIEZoom) - canvasScrollLeft); + } + + var bounds = new ORYX.Core.Bounds(a.e + absoluteXY.x, a.f + absoluteXY.y, a.e + absoluteXY.x + a.a * selectedShape.bounds.width(), a.f + absoluteXY.y + a.d * selectedShape.bounds.height()); + var shapeXY = bounds.upperLeft(); + + var stencilItem = $scope.getStencilItemById(selectedShape.getStencil().idWithoutNs()); + var morphShapes = []; + if (stencilItem && stencilItem.morphRole) { + for (var i = 0; i < $scope.morphRoles.length; i++) { + if ($scope.morphRoles[i].role === stencilItem.morphRole) { + morphShapes = $scope.morphRoles[i].morphOptions; + } + } + } + + var x = shapeXY.x; + if (bounds.width() < 48) { + x -= 24; + } + + if (morphShapes && morphShapes.length > 0) { + // In case the element is not wide enough, start the 2 bottom-buttons more to the left + // to prevent overflow in the right-menu + var morphButton = document.getElementById('morph-button'); + morphButton.style.display = "block"; + morphButton.style.left = x + 24 + 'px'; + morphButton.style.top = (shapeXY.y + bounds.height() + 2) + 'px'; + } + + var deleteButton = document.getElementById('delete-button'); + deleteButton.style.display = "block"; + deleteButton.style.left = x + 'px'; + deleteButton.style.top = (shapeXY.y + bounds.height() + 2) + 'px'; + + if (stencilItem && (stencilItem.canConnect || stencilItem.canConnectAssociation)) { + var quickButtonCounter = 0; + var quickButtonX = shapeXY.x + bounds.width() + 5; + var quickButtonY = shapeXY.y; + jQuery('.Oryx_button').each(function (i, obj) { + if (obj.id !== 'morph-button' && obj.id != 'delete-button') { + quickButtonCounter++; + if (quickButtonCounter > 3) { + quickButtonX = shapeXY.x + bounds.width() + 5; + quickButtonY += 24; + quickButtonCounter = 1; + + } else if (quickButtonCounter > 1) { + quickButtonX += 24; + } + obj.style.display = "block"; + obj.style.left = quickButtonX + 'px'; + obj.style.top = quickButtonY + 'px'; + } + }); } - - var bounds = new ORYX.Core.Bounds(a.e + absoluteXY.x, a.f + absoluteXY.y, a.e + absoluteXY.x + a.a*selectedShape.bounds.width(), a.f + absoluteXY.y + a.d*selectedShape.bounds.height()); - var shapeXY = bounds.upperLeft(); - - var stencilItem = $scope.getStencilItemById(selectedShape.getStencil().idWithoutNs()); - var morphShapes = []; - if (stencilItem && stencilItem.morphRole) - { - for (var i = 0; i < $scope.morphRoles.length; i++) - { - if ($scope.morphRoles[i].role === stencilItem.morphRole) - { - morphShapes = $scope.morphRoles[i].morphOptions; - } - } - } - - var x = shapeXY.x; - if (bounds.width() < 48) { - x -= 24; - } - - if (morphShapes && morphShapes.length > 0) { - // In case the element is not wide enough, start the 2 bottom-buttons more to the left - // to prevent overflow in the right-menu - var morphButton = document.getElementById('morph-button'); - morphButton.style.display = "block"; - morphButton.style.left = x + 24 +'px'; - morphButton.style.top = (shapeXY.y+bounds.height() + 2) + 'px'; - } - - var deleteButton = document.getElementById('delete-button'); - deleteButton.style.display = "block"; - deleteButton.style.left = x + 'px'; - deleteButton.style.top = (shapeXY.y+bounds.height() + 2) + 'px'; - - if (stencilItem && (stencilItem.canConnect || stencilItem.canConnectAssociation)) { - var quickButtonCounter = 0; - var quickButtonX = shapeXY.x+bounds.width() + 5; - var quickButtonY = shapeXY.y; - jQuery('.Oryx_button').each(function(i, obj) { - if (obj.id !== 'morph-button' && obj.id != 'delete-button') { - quickButtonCounter++; - if (quickButtonCounter > 3) { - quickButtonX = shapeXY.x+bounds.width() + 5; - quickButtonY += 24; - quickButtonCounter = 1; - - } else if (quickButtonCounter > 1) { - quickButtonX += 24; - } - obj.style.display = "block"; - obj.style.left = quickButtonX + 'px'; - obj.style.top = quickButtonY + 'px'; - } - }); - } } }); - + if (!$rootScope.stencilInitialized) { - KISBPM.eventBus.addListener(KISBPM.eventBus.EVENT_TYPE_HIDE_SHAPE_BUTTONS, function (event) { - jQuery('.Oryx_button').each(function(i, obj) { - obj.style.display = "none"; - }); - }); - - /* - * Listen to property updates and act upon them - */ - KISBPM.eventBus.addListener(KISBPM.eventBus.EVENT_TYPE_PROPERTY_VALUE_CHANGED, function (event) { - if (event.property && event.property.key) { - // If the name property is been updated, we also need to change the title of the currently selected item - if (event.property.key === 'oryx-name' && $scope.selectedItem !== undefined && $scope.selectedItem !== null) { - $scope.selectedItem.title = event.newValue; - } - - // Update "no value" flag - event.property.noValue = (event.property.value === undefined - || event.property.value === null - || event.property.value.length == 0); - } - }); - - $rootScope.stencilInitialized = true; + KISBPM.eventBus.addListener(KISBPM.eventBus.EVENT_TYPE_HIDE_SHAPE_BUTTONS, function (event) { + jQuery('.Oryx_button').each(function (i, obj) { + obj.style.display = "none"; + }); + }); + + /* + * Listen to property updates and act upon them + */ + KISBPM.eventBus.addListener(KISBPM.eventBus.EVENT_TYPE_PROPERTY_VALUE_CHANGED, function (event) { + if (event.property && event.property.key) { + // If the name property is been updated, we also need to change the title of the currently selected item + if (event.property.key === 'oryx-name' && $scope.selectedItem !== undefined && $scope.selectedItem !== null) { + $scope.selectedItem.title = event.newValue; + } + + // Update "no value" flag + event.property.noValue = (event.property.value === undefined + || event.property.value === null + || event.property.value.length == 0); + } + }); + + $rootScope.stencilInitialized = true; } - - $scope.morphShape = function() { - $scope.safeApply(function () { - - var shapes = $rootScope.editor.getSelection(); - if (shapes && shapes.length == 1) - { - $rootScope.currentSelectedShape = shapes.first(); - var stencilItem = $scope.getStencilItemById($rootScope.currentSelectedShape.getStencil().idWithoutNs()); - var morphShapes = []; - for (var i = 0; i < $scope.morphRoles.length; i++) - { - if ($scope.morphRoles[i].role === stencilItem.morphRole) - { - morphShapes = $scope.morphRoles[i].morphOptions.slice(); - } - } - - // Method to open shape select dialog (used later on) - var showSelectShapeDialog = function() - { + + $scope.morphShape = function () { + $scope.safeApply(function () { + + var shapes = $rootScope.editor.getSelection(); + if (shapes && shapes.length == 1) { + $rootScope.currentSelectedShape = shapes.first(); + var stencilItem = $scope.getStencilItemById($rootScope.currentSelectedShape.getStencil().idWithoutNs()); + var morphShapes = []; + for (var i = 0; i < $scope.morphRoles.length; i++) { + if ($scope.morphRoles[i].role === stencilItem.morphRole) { + morphShapes = $scope.morphRoles[i].morphOptions.slice(); + } + } + + // Method to open shape select dialog (used later on) + var showSelectShapeDialog = function () { $rootScope.morphShapes = morphShapes; $modal({ backdrop: false, @@ -516,61 +498,65 @@ angular.module('activitiModeler') }; showSelectShapeDialog(); - } - }); + } + }); }; - - $scope.deleteShape = function() { - KISBPM.TOOLBAR.ACTIONS.deleteItem({'$scope': $scope}); + + $scope.deleteShape = function () { + KISBPM.TOOLBAR.ACTIONS.deleteItem({'$scope': $scope}); }; - - $scope.quickAddItem = function(newItemId) { - $scope.safeApply(function () { - - var shapes = $rootScope.editor.getSelection(); - if (shapes && shapes.length == 1) - { - $rootScope.currentSelectedShape = shapes.first(); - - var containedStencil = undefined; - var stencilSets = $scope.editor.getStencilSets().values(); - for (var i = 0; i < stencilSets.length; i++) - { - var stencilSet = stencilSets[i]; - var nodes = stencilSet.nodes(); - for (var j = 0; j < nodes.length; j++) - { - if (nodes[j].idWithoutNs() === newItemId) - { - containedStencil = nodes[j]; - break; - } - } - } - - if (!containedStencil) return; - - var option = {type: $scope.currentSelectedShape.getStencil().namespace() + newItemId, namespace: $scope.currentSelectedShape.getStencil().namespace()}; - option['connectedShape'] = $rootScope.currentSelectedShape; - option['parent'] = $rootScope.currentSelectedShape.parent; - option['containedStencil'] = containedStencil; - - var args = { sourceShape: $rootScope.currentSelectedShape, targetStencil: containedStencil }; - var targetStencil = $scope.editor.getRules().connectMorph(args); - if (!targetStencil){ return; }// Check if there can be a target shape - option['connectingType'] = targetStencil.id(); - - var command = new KISBPM.CreateCommand(option, undefined, undefined, $scope.editor); - - $scope.editor.executeCommands([command]); - } - }); + + $scope.quickAddItem = function (newItemId) { + $scope.safeApply(function () { + + var shapes = $rootScope.editor.getSelection(); + if (shapes && shapes.length == 1) { + $rootScope.currentSelectedShape = shapes.first(); + + var containedStencil = undefined; + var stencilSets = $scope.editor.getStencilSets().values(); + for (var i = 0; i < stencilSets.length; i++) { + var stencilSet = stencilSets[i]; + var nodes = stencilSet.nodes(); + for (var j = 0; j < nodes.length; j++) { + if (nodes[j].idWithoutNs() === newItemId) { + containedStencil = nodes[j]; + break; + } + } + } + + if (!containedStencil) return; + + var option = { + type: $scope.currentSelectedShape.getStencil().namespace() + newItemId, + namespace: $scope.currentSelectedShape.getStencil().namespace() + }; + option['connectedShape'] = $rootScope.currentSelectedShape; + option['parent'] = $rootScope.currentSelectedShape.parent; + option['containedStencil'] = containedStencil; + + var args = {sourceShape: $rootScope.currentSelectedShape, targetStencil: containedStencil}; + var targetStencil = $scope.editor.getRules().connectMorph(args); + if (!targetStencil) { + return; + }// Check if there can be a target shape + option['connectingType'] = targetStencil.id(); + + var command = new KISBPM.CreateCommand(option, undefined, undefined, $scope.editor); + + $scope.editor.executeCommands([command]); + } + }); }; }); // end of $scope.editorFactory.promise block /* Click handler for clicking a property */ $scope.propertyClicked = function (index) { + if ($scope.selectedItem.properties[index].readOnly) { + return; + } if (!$scope.selectedItem.properties[index].hidden) { $scope.selectedItem.properties[index].mode = "write"; } @@ -716,7 +702,7 @@ angular.module('activitiModeler') */ $scope.dropCallback = function (event, ui) { - + $scope.editor.handleEvents({ type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId: "shapeRepo.attached" @@ -725,21 +711,21 @@ angular.module('activitiModeler') type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId: "shapeRepo.added" }); - + $scope.editor.handleEvents({ type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId: "shapeMenu" }); - + KISBPM.eventBus.dispatch(KISBPM.eventBus.EVENT_TYPE_HIDE_SHAPE_BUTTONS); if ($scope.dragCanContain) { - var item = $scope.getStencilItemById(ui.draggable[0].id); - - var pos = {x: event.pageX, y: event.pageY}; - - var additionalIEZoom = 1; + var item = $scope.getStencilItemById(ui.draggable[0].id); + + var pos = {x: event.pageX, y: event.pageY}; + + var additionalIEZoom = 1; if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { var ua = navigator.userAgent; if (ua.indexOf('MSIE') >= 0) { @@ -750,7 +736,7 @@ angular.module('activitiModeler') } } } - + var screenCTM = $scope.editor.getCanvas().node.getScreenCTM(); // Correcting the UpperLeft-Offset @@ -759,37 +745,31 @@ angular.module('activitiModeler') // Correcting the Zoom-Factor pos.x /= screenCTM.a; pos.y /= screenCTM.d; - + // Correcting the ScrollOffset pos.x -= document.documentElement.scrollLeft; pos.y -= document.documentElement.scrollTop; - + var parentAbs = $scope.dragCurrentParent.absoluteXY(); pos.x -= parentAbs.x; pos.y -= parentAbs.y; var containedStencil = undefined; var stencilSets = $scope.editor.getStencilSets().values(); - for (var i = 0; i < stencilSets.length; i++) - { + for (var i = 0; i < stencilSets.length; i++) { var stencilSet = stencilSets[i]; var nodes = stencilSet.nodes(); - for (var j = 0; j < nodes.length; j++) - { - if (nodes[j].idWithoutNs() === ui.draggable[0].id) - { + for (var j = 0; j < nodes.length; j++) { + if (nodes[j].idWithoutNs() === ui.draggable[0].id) { containedStencil = nodes[j]; break; } } - if (!containedStencil) - { + if (!containedStencil) { var edges = stencilSet.edges(); - for (var j = 0; j < edges.length; j++) - { - if (edges[j].idWithoutNs() === ui.draggable[0].id) - { + for (var j = 0; j < edges.length; j++) { + if (edges[j].idWithoutNs() === ui.draggable[0].id) { containedStencil = edges[j]; break; } @@ -799,60 +779,57 @@ angular.module('activitiModeler') if (!containedStencil) return; - if ($scope.quickMenu) - { - var shapes = $scope.editor.getSelection(); - if (shapes && shapes.length == 1) - { - var currentSelectedShape = shapes.first(); - - var option = {}; - option.type = currentSelectedShape.getStencil().namespace() + ui.draggable[0].id; - option.namespace = currentSelectedShape.getStencil().namespace(); - option.connectedShape = currentSelectedShape; - option.parent = $scope.dragCurrentParent; - option.containedStencil = containedStencil; - - // If the ctrl key is not pressed, - // snapp the new shape to the center - // if it is near to the center of the other shape - if (!event.ctrlKey){ - // Get the center of the shape - var cShape = currentSelectedShape.bounds.center(); - // Snapp +-20 Pixel horizontal to the center - if (20 > Math.abs(cShape.x - pos.x)){ - pos.x = cShape.x; - } - // Snapp +-20 Pixel vertical to the center - if (20 > Math.abs(cShape.y - pos.y)){ - pos.y = cShape.y; - } - } - - option.position = pos; - - if (containedStencil.idWithoutNs() !== 'SequenceFlow' && containedStencil.idWithoutNs() !== 'Association' && - containedStencil.idWithoutNs() !== 'MessageFlow' && containedStencil.idWithoutNs() !== 'DataAssociation') - { - var args = { sourceShape: currentSelectedShape, targetStencil: containedStencil }; - var targetStencil = $scope.editor.getRules().connectMorph(args); - if (!targetStencil){ return; }// Check if there can be a target shape - option.connectingType = targetStencil.id(); - } - - var command = new KISBPM.CreateCommand(option, $scope.dropTargetElement, pos, $scope.editor); - - $scope.editor.executeCommands([command]); - } - } - else - { + if ($scope.quickMenu) { + var shapes = $scope.editor.getSelection(); + if (shapes && shapes.length == 1) { + var currentSelectedShape = shapes.first(); + + var option = {}; + option.type = currentSelectedShape.getStencil().namespace() + ui.draggable[0].id; + option.namespace = currentSelectedShape.getStencil().namespace(); + option.connectedShape = currentSelectedShape; + option.parent = $scope.dragCurrentParent; + option.containedStencil = containedStencil; + + // If the ctrl key is not pressed, + // snapp the new shape to the center + // if it is near to the center of the other shape + if (!event.ctrlKey) { + // Get the center of the shape + var cShape = currentSelectedShape.bounds.center(); + // Snapp +-20 Pixel horizontal to the center + if (20 > Math.abs(cShape.x - pos.x)) { + pos.x = cShape.x; + } + // Snapp +-20 Pixel vertical to the center + if (20 > Math.abs(cShape.y - pos.y)) { + pos.y = cShape.y; + } + } + + option.position = pos; + + if (containedStencil.idWithoutNs() !== 'SequenceFlow' && containedStencil.idWithoutNs() !== 'Association' && + containedStencil.idWithoutNs() !== 'MessageFlow' && containedStencil.idWithoutNs() !== 'DataAssociation') { + var args = {sourceShape: currentSelectedShape, targetStencil: containedStencil}; + var targetStencil = $scope.editor.getRules().connectMorph(args); + if (!targetStencil) { + return; + }// Check if there can be a target shape + option.connectingType = targetStencil.id(); + } + + var command = new KISBPM.CreateCommand(option, $scope.dropTargetElement, pos, $scope.editor); + + $scope.editor.executeCommands([command]); + } + } else { var canAttach = false; if (containedStencil.idWithoutNs() === 'BoundaryErrorEvent' || containedStencil.idWithoutNs() === 'BoundaryTimerEvent' || containedStencil.idWithoutNs() === 'BoundarySignalEvent' || containedStencil.idWithoutNs() === 'BoundaryMessageEvent' || containedStencil.idWithoutNs() === 'BoundaryCancelEvent' || containedStencil.idWithoutNs() === 'BoundaryCompensationEvent') { // Modify position, otherwise boundary event will get position related to left corner of the canvas instead of the container - pos = $scope.editor.eventCoordinates( event ); + pos = $scope.editor.eventCoordinates(event); canAttach = true; } @@ -863,19 +840,19 @@ angular.module('activitiModeler') option['parent'] = $scope.dragCurrentParent; var commandClass = ORYX.Core.Command.extend({ - construct: function(option, dockedShape, canAttach, position, facade){ + construct: function (option, dockedShape, canAttach, position, facade) { this.option = option; this.docker = null; this.dockedShape = dockedShape; this.dockedShapeParent = dockedShape.parent || facade.getCanvas(); this.position = position; - this.facade = facade; + this.facade = facade; this.selection = this.facade.getSelection(); this.shape = null; this.parent = null; this.canAttach = canAttach; }, - execute: function(){ + execute: function () { if (!this.shape) { this.shape = this.facade.createShape(option); this.parent = this.shape.parent; @@ -894,14 +871,14 @@ angular.module('activitiModeler') if (this.dockedShape !== this.facade.getCanvas()) { this.docker.setDockedShape(this.dockedShape); } - this.facade.setSelection( [this.docker.parent] ); + this.facade.setSelection([this.docker.parent]); } this.facade.getCanvas().update(); this.facade.updateSelection(); }, - rollback: function(){ + rollback: function () { if (this.shape) { this.facade.setSelection(this.selection.without(this.shape)); this.facade.deleteShape(this.shape); @@ -953,18 +930,18 @@ angular.module('activitiModeler') ui.helper.addClass('stencil-item-dragged'); } }; - + $scope.startDragCallbackQuickMenu = function (event, ui) { $scope.dragModeOver = false; $scope.quickMenu = true; }; - + $scope.dragCallback = function (event, ui) { - + if ($scope.dragModeOver != false) { - + var coord = $scope.editor.eventCoordinatesXY(event.pageX, event.pageY); - + var additionalIEZoom = 1; if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { var ua = navigator.userAgent; @@ -976,14 +953,14 @@ angular.module('activitiModeler') } } } - + if (additionalIEZoom !== 1) { - coord.x = coord.x / additionalIEZoom; - coord.y = coord.y / additionalIEZoom; + coord.x = coord.x / additionalIEZoom; + coord.y = coord.y / additionalIEZoom; } - + var aShapes = $scope.editor.getCanvas().getAbstractShapesAtPosition(coord); - + if (aShapes.length <= 0) { if (event.helper) { $scope.dragCanContain = false; @@ -995,8 +972,7 @@ angular.module('activitiModeler') $scope.editor.getCanvas().setHightlightStateBasedOnX(coord.x); } - if (aShapes.length == 1 && aShapes[0] instanceof ORYX.Core.Canvas) - { + if (aShapes.length == 1 && aShapes[0] instanceof ORYX.Core.Canvas) { var parentCandidate = aShapes[0]; $scope.dragCanContain = true; @@ -1012,24 +988,22 @@ angular.module('activitiModeler') highlightId: "shapeRepo.added" }); return false; - } - else - { + } else { var item = $scope.getStencilItemById(event.target.id); - + var parentCandidate = aShapes.reverse().find(function (candidate) { return (candidate instanceof ORYX.Core.Canvas || candidate instanceof ORYX.Core.Node || candidate instanceof ORYX.Core.Edge); }); - + if (!parentCandidate) { $scope.dragCanContain = false; return false; } - + if (item.type === "node") { - + // check if the draggable is a boundary event and the parent an Activity var _canContain = false; var parentStencilId = parentCandidate.getStencil().id(); @@ -1043,18 +1017,14 @@ angular.module('activitiModeler') if (item.roles.indexOf("IntermediateEventOnActivityBoundary") > -1) { _canContain = true; } + } else if (parentCandidate.getStencil().idWithoutNs() === 'Pool') { + if (item.id === 'Lane') { + _canContain = true; + } } - else if (parentCandidate.getStencil().idWithoutNs() === 'Pool') - { - if (item.id === 'Lane') - { - _canContain = true; - } - } - - if (_canContain) - { - $scope.editor.handleEvents({ + + if (_canContain) { + $scope.editor.handleEvents({ type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, highlightId: "shapeRepo.attached", elements: [parentCandidate], @@ -1066,9 +1036,7 @@ angular.module('activitiModeler') type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId: "shapeRepo.added" }); - } - else - { + } else { for (var i = 0; i < $scope.containmentRules.length; i++) { var rule = $scope.containmentRules[i]; if (rule.role === parentItem.id) { @@ -1103,32 +1071,32 @@ angular.module('activitiModeler') $scope.dragCurrentParentId = parentCandidate.id; $scope.dragCurrentParentStencil = parentStencilId; $scope.dragCanContain = _canContain; - - } else { - var canvasCandidate = $scope.editor.getCanvas(); - var canConnect = false; - - var targetStencil = $scope.getStencilItemById(parentCandidate.getStencil().idWithoutNs()); - if (targetStencil) { - var associationConnect = false; - if (stencil.idWithoutNs() === 'Association' && (curCan.getStencil().idWithoutNs() === 'TextAnnotation' || curCan.getStencil().idWithoutNs() === 'BoundaryCompensationEvent')) { - associationConnect = true; - } else if (stencil.idWithoutNs() === 'DataAssociation' && curCan.getStencil().idWithoutNs() === 'DataStore') { + + } else { + var canvasCandidate = $scope.editor.getCanvas(); + var canConnect = false; + + var targetStencil = $scope.getStencilItemById(parentCandidate.getStencil().idWithoutNs()); + if (targetStencil) { + var associationConnect = false; + if (stencil.idWithoutNs() === 'Association' && (curCan.getStencil().idWithoutNs() === 'TextAnnotation' || curCan.getStencil().idWithoutNs() === 'BoundaryCompensationEvent')) { associationConnect = true; + } else if (stencil.idWithoutNs() === 'DataAssociation' && curCan.getStencil().idWithoutNs() === 'DataStore') { + associationConnect = true; + } + + if (targetStencil.canConnectTo || associationConnect) { + canConnect = true; } - - if (targetStencil.canConnectTo || associationConnect) { - canConnect = true; - } - } - - //Edge - $scope.dragCurrentParent = canvasCandidate; - $scope.dragCurrentParentId = canvasCandidate.id; + } + + //Edge + $scope.dragCurrentParent = canvasCandidate; + $scope.dragCurrentParentId = canvasCandidate.id; $scope.dragCurrentParentStencil = canvasCandidate.getStencil().id(); $scope.dragCanContain = canConnect; - - // Show Highlight + + // Show Highlight $scope.editor.handleEvents({ type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, highlightId: 'shapeRepo.added', @@ -1140,16 +1108,16 @@ angular.module('activitiModeler') type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId: "shapeRepo.attached" }); - } + } } } }; - + $scope.dragCallbackQuickMenu = function (event, ui) { - + if ($scope.dragModeOver != false) { var coord = $scope.editor.eventCoordinatesXY(event.pageX, event.pageY); - + var additionalIEZoom = 1; if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { var ua = navigator.userAgent; @@ -1161,14 +1129,14 @@ angular.module('activitiModeler') } } } - + if (additionalIEZoom !== 1) { - coord.x = coord.x / additionalIEZoom; - coord.y = coord.y / additionalIEZoom; + coord.x = coord.x / additionalIEZoom; + coord.y = coord.y / additionalIEZoom; } - + var aShapes = $scope.editor.getCanvas().getAbstractShapesAtPosition(coord); - + if (aShapes.length <= 0) { if (event.helper) { $scope.dragCanContain = false; @@ -1179,45 +1147,41 @@ angular.module('activitiModeler') if (aShapes[0] instanceof ORYX.Core.Canvas) { $scope.editor.getCanvas().setHightlightStateBasedOnX(coord.x); } - - var stencil = undefined; - var stencilSets = $scope.editor.getStencilSets().values(); - for (var i = 0; i < stencilSets.length; i++) - { - var stencilSet = stencilSets[i]; - var nodes = stencilSet.nodes(); - for (var j = 0; j < nodes.length; j++) - { - if (nodes[j].idWithoutNs() === event.target.id) - { - stencil = nodes[j]; - break; - } - } - - if (!stencil) - { - var edges = stencilSet.edges(); - for (var j = 0; j < edges.length; j++) - { - if (edges[j].idWithoutNs() === event.target.id) - { - stencil = edges[j]; - break; - } - } - } - } - + + var stencil = undefined; + var stencilSets = $scope.editor.getStencilSets().values(); + for (var i = 0; i < stencilSets.length; i++) { + var stencilSet = stencilSets[i]; + var nodes = stencilSet.nodes(); + for (var j = 0; j < nodes.length; j++) { + if (nodes[j].idWithoutNs() === event.target.id) { + stencil = nodes[j]; + break; + } + } + + if (!stencil) { + var edges = stencilSet.edges(); + for (var j = 0; j < edges.length; j++) { + if (edges[j].idWithoutNs() === event.target.id) { + stencil = edges[j]; + break; + } + } + } + } + var candidate = aShapes.last(); - + var isValid = false; - if (stencil.type() === "node") - { - //check containment rules - var canContain = $scope.editor.getRules().canContain({containingShape:candidate, containedStencil:stencil}); - - var parentCandidate = aShapes.reverse().find(function (candidate) { + if (stencil.type() === "node") { + //check containment rules + var canContain = $scope.editor.getRules().canContain({ + containingShape: candidate, + containedStencil: stencil + }); + + var parentCandidate = aShapes.reverse().find(function (candidate) { return (candidate instanceof ORYX.Core.Canvas || candidate instanceof ORYX.Core.Node || candidate instanceof ORYX.Core.Edge); @@ -1227,69 +1191,62 @@ angular.module('activitiModeler') $scope.dragCanContain = false; return false; } - - $scope.dragCurrentParent = parentCandidate; + + $scope.dragCurrentParent = parentCandidate; $scope.dragCurrentParentId = parentCandidate.id; $scope.dragCurrentParentStencil = parentCandidate.getStencil().id(); $scope.dragCanContain = canContain; $scope.dropTargetElement = parentCandidate; isValid = canContain; - - } else { //Edge - - var shapes = $scope.editor.getSelection(); - if (shapes && shapes.length == 1) - { - var currentSelectedShape = shapes.first(); - var curCan = candidate; - var canConnect = false; - - var targetStencil = $scope.getStencilItemById(curCan.getStencil().idWithoutNs()); - if (targetStencil) - { - var associationConnect = false; - if (stencil.idWithoutNs() === 'Association' && (curCan.getStencil().idWithoutNs() === 'TextAnnotation' || curCan.getStencil().idWithoutNs() === 'BoundaryCompensationEvent')) - { - associationConnect = true; - } - else if (stencil.idWithoutNs() === 'DataAssociation' && curCan.getStencil().idWithoutNs() === 'DataStore') - { - associationConnect = true; - } - - if (targetStencil.canConnectTo || associationConnect) - { - while (!canConnect && curCan && !(curCan instanceof ORYX.Core.Canvas)) - { - candidate = curCan; - //check connection rules - canConnect = $scope.editor.getRules().canConnect({ - sourceShape: currentSelectedShape, - edgeStencil: stencil, - targetShape: curCan - }); - curCan = curCan.parent; - } - } - } - var parentCandidate = $scope.editor.getCanvas(); - - isValid = canConnect; - $scope.dragCurrentParent = parentCandidate; + + } else { //Edge + + var shapes = $scope.editor.getSelection(); + if (shapes && shapes.length == 1) { + var currentSelectedShape = shapes.first(); + var curCan = candidate; + var canConnect = false; + + var targetStencil = $scope.getStencilItemById(curCan.getStencil().idWithoutNs()); + if (targetStencil) { + var associationConnect = false; + if (stencil.idWithoutNs() === 'Association' && (curCan.getStencil().idWithoutNs() === 'TextAnnotation' || curCan.getStencil().idWithoutNs() === 'BoundaryCompensationEvent')) { + associationConnect = true; + } else if (stencil.idWithoutNs() === 'DataAssociation' && curCan.getStencil().idWithoutNs() === 'DataStore') { + associationConnect = true; + } + + if (targetStencil.canConnectTo || associationConnect) { + while (!canConnect && curCan && !(curCan instanceof ORYX.Core.Canvas)) { + candidate = curCan; + //check connection rules + canConnect = $scope.editor.getRules().canConnect({ + sourceShape: currentSelectedShape, + edgeStencil: stencil, + targetShape: curCan + }); + curCan = curCan.parent; + } + } + } + var parentCandidate = $scope.editor.getCanvas(); + + isValid = canConnect; + $scope.dragCurrentParent = parentCandidate; $scope.dragCurrentParentId = parentCandidate.id; $scope.dragCurrentParentStencil = parentCandidate.getStencil().id(); - $scope.dragCanContain = canConnect; - $scope.dropTargetElement = candidate; - } - - } + $scope.dragCanContain = canConnect; + $scope.dropTargetElement = candidate; + } + + } $scope.editor.handleEvents({ - type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, - highlightId:'shapeMenu', - elements: [candidate], - color: isValid ? ORYX.CONFIG.SELECTION_VALID_COLOR : ORYX.CONFIG.SELECTION_INVALID_COLOR - }); + type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, + highlightId: 'shapeMenu', + elements: [candidate], + color: isValid ? ORYX.CONFIG.SELECTION_VALID_COLOR : ORYX.CONFIG.SELECTION_INVALID_COLOR + }); } }; @@ -1298,18 +1255,18 @@ angular.module('activitiModeler') var KISBPM = KISBPM || {}; //create command for undo/redo KISBPM.CreateCommand = ORYX.Core.Command.extend({ - construct: function(option, currentReference, position, facade){ - this.option = option; - this.currentReference = currentReference; - this.position = position; - this.facade = facade; - this.shape; - this.edge; - this.targetRefPos; - this.sourceRefPos; - /* - * clone options parameters - */ + construct: function (option, currentReference, position, facade) { + this.option = option; + this.currentReference = currentReference; + this.position = position; + this.facade = facade; + this.shape; + this.edge; + this.targetRefPos; + this.sourceRefPos; + /* + * clone options parameters + */ this.connectedShape = option.connectedShape; this.connectingType = option.connectingType; this.namespace = option.namespace; @@ -1318,120 +1275,115 @@ KISBPM.CreateCommand = ORYX.Core.Command.extend({ this.parent = option.parent; this.currentReference = currentReference; this.shapeOptions = option.shapeOptions; - }, - execute: function(){ - - if (this.shape) { - if (this.shape instanceof ORYX.Core.Node) { - this.parent.add(this.shape); - if (this.edge) { - this.facade.getCanvas().add(this.edge); - this.edge.dockers.first().setDockedShape(this.connectedShape); - this.edge.dockers.first().setReferencePoint(this.sourceRefPos); - this.edge.dockers.last().setDockedShape(this.shape); - this.edge.dockers.last().setReferencePoint(this.targetRefPos); - } - - this.facade.setSelection([this.shape]); - - } else if (this.shape instanceof ORYX.Core.Edge) { - this.facade.getCanvas().add(this.shape); - this.shape.dockers.first().setDockedShape(this.connectedShape); - this.shape.dockers.first().setReferencePoint(this.sourceRefPos); - } - } - else { - this.shape = this.facade.createShape(this.option); - this.edge = (!(this.shape instanceof ORYX.Core.Edge)) ? this.shape.getIncomingShapes().first() : undefined; - } - - if (this.currentReference && this.position) { - - if (this.shape instanceof ORYX.Core.Edge) { - - if (!(this.currentReference instanceof ORYX.Core.Canvas)) { - this.shape.dockers.last().setDockedShape(this.currentReference); - - if (this.currentReference.getStencil().idWithoutNs() === 'TextAnnotation') - { - var midpoint = {}; - midpoint.x = 0; - midpoint.y = this.currentReference.bounds.height() / 2; - this.shape.dockers.last().setReferencePoint(midpoint); - } - else - { - this.shape.dockers.last().setReferencePoint(this.currentReference.bounds.midPoint()); - } - } - else { - this.shape.dockers.last().bounds.centerMoveTo(this.position); - } - this.sourceRefPos = this.shape.dockers.first().referencePoint; - this.targetRefPos = this.shape.dockers.last().referencePoint; - - } else if (this.edge){ - this.sourceRefPos = this.edge.dockers.first().referencePoint; - this.targetRefPos = this.edge.dockers.last().referencePoint; - } - } else { - var containedStencil = this.containedStencil; - var connectedShape = this.connectedShape; - var bc = connectedShape.bounds; - var bs = this.shape.bounds; - - var pos = bc.center(); - if(containedStencil.defaultAlign()==="north") { - pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.height()/2); - } else if(containedStencil.defaultAlign()==="northeast") { - pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2); - pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2); - } else if(containedStencil.defaultAlign()==="southeast") { - pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2); - pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2); - } else if(containedStencil.defaultAlign()==="south") { - pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.height()/2); - } else if(containedStencil.defaultAlign()==="southwest") { - pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2); - pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2); - } else if(containedStencil.defaultAlign()==="west") { - pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.width()/2); - } else if(containedStencil.defaultAlign()==="northwest") { - pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2); - pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2); - } else { - pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.width()/2); - } - - // Move shape to the new position - this.shape.bounds.centerMoveTo(pos); - - // Move all dockers of a node to the position - if (this.shape instanceof ORYX.Core.Node){ - (this.shape.dockers||[]).each(function(docker){ - docker.bounds.centerMoveTo(pos); - }); - } - - //this.shape.update(); - this.position = pos; - - if (this.edge){ - this.sourceRefPos = this.edge.dockers.first().referencePoint; - this.targetRefPos = this.edge.dockers.last().referencePoint; - } - } - - this.facade.getCanvas().update(); - this.facade.updateSelection(); - - }, - rollback: function(){ - this.facade.deleteShape(this.shape); - if(this.edge) { - this.facade.deleteShape(this.edge); - } - //this.currentParent.update(); - this.facade.setSelection(this.facade.getSelection().without(this.shape, this.edge)); - } + }, + execute: function () { + + if (this.shape) { + if (this.shape instanceof ORYX.Core.Node) { + this.parent.add(this.shape); + if (this.edge) { + this.facade.getCanvas().add(this.edge); + this.edge.dockers.first().setDockedShape(this.connectedShape); + this.edge.dockers.first().setReferencePoint(this.sourceRefPos); + this.edge.dockers.last().setDockedShape(this.shape); + this.edge.dockers.last().setReferencePoint(this.targetRefPos); + } + + this.facade.setSelection([this.shape]); + + } else if (this.shape instanceof ORYX.Core.Edge) { + this.facade.getCanvas().add(this.shape); + this.shape.dockers.first().setDockedShape(this.connectedShape); + this.shape.dockers.first().setReferencePoint(this.sourceRefPos); + } + } else { + this.shape = this.facade.createShape(this.option); + this.edge = (!(this.shape instanceof ORYX.Core.Edge)) ? this.shape.getIncomingShapes().first() : undefined; + } + + if (this.currentReference && this.position) { + + if (this.shape instanceof ORYX.Core.Edge) { + + if (!(this.currentReference instanceof ORYX.Core.Canvas)) { + this.shape.dockers.last().setDockedShape(this.currentReference); + + if (this.currentReference.getStencil().idWithoutNs() === 'TextAnnotation') { + var midpoint = {}; + midpoint.x = 0; + midpoint.y = this.currentReference.bounds.height() / 2; + this.shape.dockers.last().setReferencePoint(midpoint); + } else { + this.shape.dockers.last().setReferencePoint(this.currentReference.bounds.midPoint()); + } + } else { + this.shape.dockers.last().bounds.centerMoveTo(this.position); + } + this.sourceRefPos = this.shape.dockers.first().referencePoint; + this.targetRefPos = this.shape.dockers.last().referencePoint; + + } else if (this.edge) { + this.sourceRefPos = this.edge.dockers.first().referencePoint; + this.targetRefPos = this.edge.dockers.last().referencePoint; + } + } else { + var containedStencil = this.containedStencil; + var connectedShape = this.connectedShape; + var bc = connectedShape.bounds; + var bs = this.shape.bounds; + + var pos = bc.center(); + if (containedStencil.defaultAlign() === "north") { + pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.height() / 2); + } else if (containedStencil.defaultAlign() === "northeast") { + pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width() / 2); + pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height() / 2); + } else if (containedStencil.defaultAlign() === "southeast") { + pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width() / 2); + pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height() / 2); + } else if (containedStencil.defaultAlign() === "south") { + pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.height() / 2); + } else if (containedStencil.defaultAlign() === "southwest") { + pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width() / 2); + pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height() / 2); + } else if (containedStencil.defaultAlign() === "west") { + pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.width() / 2); + } else if (containedStencil.defaultAlign() === "northwest") { + pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width() / 2); + pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height() / 2); + } else { + pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.width() / 2); + } + + // Move shape to the new position + this.shape.bounds.centerMoveTo(pos); + + // Move all dockers of a node to the position + if (this.shape instanceof ORYX.Core.Node) { + (this.shape.dockers || []).each(function (docker) { + docker.bounds.centerMoveTo(pos); + }); + } + + //this.shape.update(); + this.position = pos; + + if (this.edge) { + this.sourceRefPos = this.edge.dockers.first().referencePoint; + this.targetRefPos = this.edge.dockers.last().referencePoint; + } + } + + this.facade.getCanvas().update(); + this.facade.updateSelection(); + + }, + rollback: function () { + this.facade.deleteShape(this.shape); + if (this.edge) { + this.facade.deleteShape(this.edge); + } + //this.currentParent.update(); + this.facade.setSelection(this.facade.getSelection().without(this.shape, this.edge)); + } });