Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Q
quantum-blocks
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ui
quantum-blocks
Commits
9ebd2881
Commit
9ebd2881
authored
Dec 25, 2020
by
郝聪敏
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: 修改文件名
parent
de4a374e
Pipeline
#773
failed with stages
Changes
11
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
1193 additions
and
3 deletions
+1193
-3
index.ts
app/web/component/layout/editor/index.ts
+1
-1
api.ts
app/web/lib/Form/api/api.ts
+53
-0
index.vue
app/web/lib/Form/index.vue
+2
-2
jy.ts
app/web/lib/Form/jy/jy.ts
+276
-0
DOM.ts
app/web/page/activity/component/helpers/DOM.ts
+47
-0
draggableUtils.ts
app/web/page/activity/component/helpers/draggableUtils.ts
+44
-0
responsiveUtils.ts
app/web/page/activity/component/helpers/responsiveUtils.ts
+108
-0
utils.ts
app/web/page/activity/component/helpers/utils.ts
+585
-0
constant.ts
app/web/page/editor/component/Contextmenu/constant.ts
+5
-0
index.ts
app/web/page/editor/component/Contextmenu/index.ts
+43
-0
util.ts
app/web/page/editor/component/Contextmenu/util.ts
+29
-0
No files found.
app/web/component/layout/editor/index.ts
View file @
9ebd2881
import
{
Vue
,
Component
,
Prop
,
Watch
}
from
'
vue-property-decorator
'
;
import
iView
from
'
iview
'
;
import
cherryUi
from
'
@qg/cherry-ui
'
;
import
VueContextMenu
from
'
@editor/component/Contextmenu
'
;
import
VueContextMenu
from
'
@editor/component/Contextmenu
/index
'
;
import
'
iview/dist/styles/iview.css
'
;
import
'
@qg/cherry-ui/dist/cherry.css
'
;
...
...
app/web/lib/Form/api/api.ts
0 → 100644
View file @
9ebd2881
import
Http
from
'
@/service/http.service.ts
'
;
import
Cookies
from
'
@/service/cookieStorage.service.ts
'
;
import
localStorage
from
'
@/service/localStorage.service.ts
'
;
import
{
getParameterByName
}
from
'
@/service/utils.service.ts
'
;
const
qs
=
require
(
'
qs
'
);
const
ApiBaseUrl
=
'
http://passportapi.q-gp.com
'
;
const
qApi
=
'
http://qapi.q-gp.com
'
;
export
default
{
getCaptcha
()
{
return
Http
.
post
(
ApiBaseUrl
+
'
/api/captcha
'
);
},
sendVcode
(
phone
,
captcha
,
captchaId
,
flowFrom
)
{
const
params
=
{
phoneNo
:
phone
,
captchaId
,
captchaValue
:
captcha
,
};
if
(
flowFrom
)
{
params
.
smsMerchant
=
flowFrom
;
}
return
Http
.
post
(
ApiBaseUrl
+
'
/api/sms/send_login_code_new_forH5
'
,
qs
.
stringify
(
params
));
},
sendGtVcode
(
gt
)
{
return
Http
.
post
(
ApiBaseUrl
+
'
/api/sms/send_login_code_new_forH5
'
,
qs
.
stringify
(
gt
));
},
fastLogin
(
phone
,
vcode
,
clickId
,
uniqueKey
)
{
const
headers
=
{
Authorization
:
'
Verification
'
+
btoa
(
phone
+
'
:
'
+
vcode
),
};
const
params
=
{
channelId
:
1
,
createdFrom
:
getParameterByName
(
'
registerFrom
'
)
||
1
,
key
:
'
xyqb
'
,
btRegisterChannelId
:
''
,
dimension
:
''
,
click_id
:
clickId
,
uniqueKey
,
};
return
Http
.
post
(
ApiBaseUrl
+
'
/user/login/fastV1
'
,
qs
.
stringify
(
params
),
{
headers
,
});
},
// 判断极验还是qg
verifyMode
(
clientType
,
phoneNo
)
{
return
Http
.
post
(
ApiBaseUrl
+
'
/api/captcha/new
'
,
{
clientType
,
phoneNo
});
},
goNext
(
params
)
{
return
Http
.
post
(
ApiBaseUrl
+
'
/platform/api/page/next
'
,
qs
.
stringify
(
params
));
}
};
app/web/lib/Form/index.vue
View file @
9ebd2881
...
...
@@ -59,7 +59,7 @@
import
Storage
from
'
@/service/localStorage.service.ts
'
;
import
Cookies
from
'
@/service/cookieStorage.service.ts
'
;
import
{
isPhone
}
from
'
@/service/utils.service.ts
'
;
import
Api
from
'
./api/api.
j
s
'
;
import
Api
from
'
./api/api.
t
s
'
;
import
{
getParameterByName
}
from
'
@/service/utils.service.ts
'
;
// import './jy/jy.js';
...
...
@@ -121,7 +121,7 @@ export default {
},
mounted
()
{
console
.
log
(
'
mounted
'
);
require
(
'
./jy/jy.
j
s
'
);
require
(
'
./jy/jy.
t
s
'
);
sa
=
()
=>
import
(
'
sa-sdk-javascript
'
);
this
.
verifyMode
();
},
...
...
app/web/lib/Form/jy/jy.ts
0 → 100644
View file @
9ebd2881
/* initGeetest 1.0.0
* 用于加载id对应的验证码库,并支持宕机模式
* 暴露 initGeetest 进行验证码的初始化
* 一般不需要用户进行修改
*/
(
function
(
global
,
factory
)
{
'
use strict
'
;
if
(
typeof
module
===
'
object
'
&&
typeof
module
.
exports
===
'
object
'
)
{
// CommonJS
module
.
exports
=
global
.
document
?
factory
(
global
,
true
)
:
function
(
w
)
{
if
(
!
w
.
document
)
{
throw
new
Error
(
'
Geetest requires a window with a document
'
);
}
return
factory
(
w
);
};
}
else
{
factory
(
global
);
}
})(
typeof
window
!==
'
undefined
'
?
window
:
this
,
function
(
window
,
noGlobal
)
{
'
use strict
'
;
if
(
typeof
window
===
'
undefined
'
)
{
throw
new
Error
(
'
Geetest requires browser environment
'
);
}
const
document
=
window
.
document
;
const
Math
=
window
.
Math
;
const
head
=
document
.
getElementsByTagName
(
'
head
'
)[
0
];
function
_Object
(
obj
)
{
this
.
_obj
=
obj
;
}
_Object
.
prototype
=
{
_each
(
process
)
{
const
_obj
=
this
.
_obj
;
for
(
const
k
in
_obj
)
{
if
(
_obj
.
hasOwnProperty
(
k
))
{
process
(
k
,
_obj
[
k
]);
}
}
return
this
;
}
};
function
Config
(
config
)
{
const
self
=
this
;
new
_Object
(
config
).
_each
(
function
(
key
,
value
)
{
self
[
key
]
=
value
;
});
}
Config
.
prototype
=
{
api_server
:
'
api.geetest.com
'
,
protocol
:
'
http://
'
,
type_path
:
'
/gettype.php
'
,
fallback_config
:
{
slide
:
{
static_servers
:
[
'
static.geetest.com
'
,
'
dn-staticdown.qbox.me
'
],
type
:
'
slide
'
,
slide
:
'
/static/js/geetest.0.0.0.js
'
},
fullpage
:
{
static_servers
:
[
'
static.geetest.com
'
,
'
dn-staticdown.qbox.me
'
],
type
:
'
fullpage
'
,
fullpage
:
'
/static/js/fullpage.0.0.0.js
'
}
},
_get_fallback_config
()
{
const
self
=
this
;
if
(
isString
(
self
.
type
))
{
return
self
.
fallback_config
[
self
.
type
];
}
else
if
(
self
.
new_captcha
)
{
return
self
.
fallback_config
.
fullpage
;
}
else
{
return
self
.
fallback_config
.
slide
;
}
},
_extend
(
obj
)
{
const
self
=
this
;
new
_Object
(
obj
).
_each
(
function
(
key
,
value
)
{
self
[
key
]
=
value
;
});
}
};
const
isNumber
=
function
(
value
)
{
return
(
typeof
value
===
'
number
'
);
};
const
isString
=
function
(
value
)
{
return
(
typeof
value
===
'
string
'
);
};
const
isBoolean
=
function
(
value
)
{
return
(
typeof
value
===
'
boolean
'
);
};
const
isObject
=
function
(
value
)
{
return
(
typeof
value
===
'
object
'
&&
value
!==
null
);
};
const
isFunction
=
function
(
value
)
{
return
(
typeof
value
===
'
function
'
);
};
const
callbacks
=
{};
const
status
=
{};
const
random
=
function
()
{
return
parseInt
(
Math
.
random
()
*
10000
)
+
(
new
Date
()).
valueOf
();
};
const
loadScript
=
function
(
url
,
cb
)
{
const
script
=
document
.
createElement
(
'
script
'
);
script
.
charset
=
'
UTF-8
'
;
script
.
async
=
true
;
script
.
onerror
=
function
()
{
cb
(
true
);
};
let
loaded
=
false
;
script
.
onload
=
script
.
onreadystatechange
=
function
()
{
if
(
!
loaded
&&
(
!
script
.
readyState
||
'
loaded
'
===
script
.
readyState
||
'
complete
'
===
script
.
readyState
))
{
loaded
=
true
;
setTimeout
(
function
()
{
cb
(
false
);
},
0
);
}
};
script
.
src
=
url
;
head
.
appendChild
(
script
);
};
const
normalizeDomain
=
function
(
domain
)
{
return
domain
.
replace
(
/^https
?
:
\/\/
|
\/
$/g
,
''
);
};
const
normalizePath
=
function
(
path
)
{
path
=
path
.
replace
(
/
\/
+/g
,
'
/
'
);
if
(
path
.
indexOf
(
'
/
'
)
!==
0
)
{
path
=
'
/
'
+
path
;
}
return
path
;
};
const
normalizeQuery
=
function
(
query
)
{
if
(
!
query
)
{
return
''
;
}
let
q
=
'
?
'
;
new
_Object
(
query
).
_each
(
function
(
key
,
value
)
{
if
(
isString
(
value
)
||
isNumber
(
value
)
||
isBoolean
(
value
))
{
q
=
q
+
encodeURIComponent
(
key
)
+
'
=
'
+
encodeURIComponent
(
value
)
+
'
&
'
;
}
});
if
(
q
===
'
?
'
)
{
q
=
''
;
}
return
q
.
replace
(
/&$/
,
''
);
};
const
makeURL
=
function
(
protocol
,
domain
,
path
,
query
)
{
domain
=
normalizeDomain
(
domain
);
let
url
=
normalizePath
(
path
)
+
normalizeQuery
(
query
);
if
(
domain
)
{
url
=
protocol
+
domain
+
url
;
}
return
url
;
};
const
load
=
function
(
protocol
,
domains
,
path
,
query
,
cb
)
{
const
tryRequest
=
function
(
at
)
{
const
url
=
makeURL
(
protocol
,
domains
[
at
],
path
,
query
);
loadScript
(
url
,
function
(
err
)
{
if
(
err
)
{
if
(
at
>=
domains
.
length
-
1
)
{
cb
(
true
);
}
else
{
tryRequest
(
at
+
1
);
}
}
else
{
cb
(
false
);
}
});
};
tryRequest
(
0
);
};
const
jsonp
=
function
(
domains
,
path
,
config
,
callback
)
{
if
(
isObject
(
config
.
getLib
))
{
config
.
_extend
(
config
.
getLib
);
callback
(
config
);
return
;
}
if
(
config
.
offline
)
{
callback
(
config
.
_get_fallback_config
());
return
;
}
const
cb
=
'
geetest_
'
+
random
();
window
[
cb
]
=
function
(
data
)
{
if
(
data
.
status
===
'
success
'
)
{
callback
(
data
.
data
);
}
else
if
(
!
data
.
status
)
{
callback
(
data
);
}
else
{
callback
(
config
.
_get_fallback_config
());
}
window
[
cb
]
=
undefined
;
try
{
delete
window
[
cb
];
}
catch
(
e
)
{
}
};
load
(
config
.
protocol
,
domains
,
path
,
{
gt
:
config
.
gt
,
callback
:
cb
},
function
(
err
)
{
if
(
err
)
{
callback
(
config
.
_get_fallback_config
());
}
});
};
const
throwError
=
function
(
errorType
,
config
)
{
const
errors
=
{
networkError
:
'
网络错误
'
};
if
(
typeof
config
.
onError
===
'
function
'
)
{
config
.
onError
(
errors
[
errorType
]);
}
else
{
throw
new
Error
(
errors
[
errorType
]);
}
};
const
detect
=
function
()
{
return
!!
window
.
Geetest
;
};
if
(
detect
())
{
status
.
slide
=
'
loaded
'
;
}
const
initGeetest
=
function
(
userConfig
,
callback
)
{
const
config
=
new
Config
(
userConfig
);
if
(
userConfig
.
https
)
{
config
.
protocol
=
'
https://
'
;
}
else
if
(
!
userConfig
.
protocol
)
{
config
.
protocol
=
window
.
location
.
protocol
+
'
//
'
;
}
jsonp
([
config
.
api_server
||
config
.
apiserver
],
config
.
type_path
,
config
,
function
(
newConfig
)
{
const
type
=
newConfig
.
type
;
const
init
=
function
()
{
config
.
_extend
(
newConfig
);
callback
(
new
window
.
Geetest
(
config
));
};
callbacks
[
type
]
=
callbacks
[
type
]
||
[];
const
s
=
status
[
type
]
||
'
init
'
;
if
(
s
===
'
init
'
)
{
status
[
type
]
=
'
loading
'
;
callbacks
[
type
].
push
(
init
);
load
(
config
.
protocol
,
newConfig
.
static_servers
||
newConfig
.
domains
,
newConfig
[
type
]
||
newConfig
.
path
,
null
,
function
(
err
)
{
if
(
err
)
{
status
[
type
]
=
'
fail
'
;
throwError
(
'
networkError
'
,
config
);
}
else
{
status
[
type
]
=
'
loaded
'
;
const
cbs
=
callbacks
[
type
];
for
(
let
i
=
0
,
len
=
cbs
.
length
;
i
<
len
;
i
=
i
+
1
)
{
const
cb
=
cbs
[
i
];
if
(
isFunction
(
cb
))
{
cb
();
}
}
callbacks
[
type
]
=
[];
}
});
}
else
if
(
s
===
'
loaded
'
)
{
init
();
}
else
if
(
s
===
'
fail
'
)
{
throwError
(
'
networkError
'
,
config
);
}
else
if
(
s
===
'
loading
'
)
{
callbacks
[
type
].
push
(
init
);
}
});
};
window
.
initGeetest
=
initGeetest
;
return
initGeetest
;
});
app/web/page/activity/component/helpers/DOM.ts
0 → 100644
View file @
9ebd2881
let
currentDir
=
'
auto
'
;
// let currentDir = "auto";
function
hasDocument
()
{
return
(
typeof
document
!==
'
undefined
'
);
}
function
hasWindow
()
{
return
(
typeof
window
!==
'
undefined
'
);
}
export
function
getDocumentDir
()
{
if
(
!
hasDocument
())
{
return
currentDir
;
}
const
direction
=
(
typeof
document
.
dir
!==
'
undefined
'
)
?
document
.
dir
:
document
.
getElementsByTagName
(
'
html
'
)[
0
].
getAttribute
(
'
dir
'
);
return
direction
;
}
export
function
setDocumentDir
(
dir
)
{
// export function setDocumentDir(dir){
if
(
!
hasDocument
)
{
currentDir
=
dir
;
return
;
}
const
html
=
document
.
getElementsByTagName
(
'
html
'
)[
0
];
html
.
setAttribute
(
'
dir
'
,
dir
);
}
export
function
addWindowEventListener
(
event
,
callback
)
{
if
(
!
hasWindow
)
{
callback
();
return
;
}
window
.
addEventListener
(
event
,
callback
);
}
export
function
removeWindowEventListener
(
event
,
callback
)
{
if
(
!
hasWindow
)
{
return
;
}
window
.
removeEventListener
(
event
,
callback
);
}
app/web/page/activity/component/helpers/draggableUtils.ts
0 → 100644
View file @
9ebd2881
// Get {x, y} positions from event.
export
function
getControlPosition
(
e
)
{
return
offsetXYFromParentOf
(
e
);
}
// Get from offsetParent
export
function
offsetXYFromParentOf
(
evt
)
{
const
offsetParent
=
evt
.
target
.
offsetParent
||
document
.
body
;
const
offsetParentRect
=
evt
.
offsetParent
===
document
.
body
?
{
left
:
0
,
top
:
0
}
:
offsetParent
.
getBoundingClientRect
();
const
x
=
evt
.
clientX
+
offsetParent
.
scrollLeft
-
offsetParentRect
.
left
;
const
y
=
evt
.
clientY
+
offsetParent
.
scrollTop
-
offsetParentRect
.
top
;
/*const x = Math.round(evt.clientX + offsetParent.scrollLeft - offsetParentRect.left);
const y = Math.round(evt.clientY + offsetParent.scrollTop - offsetParentRect.top);*/
return
{
x
,
y
};
}
// Create an data object exposed by <DraggableCore>'s events
export
function
createCoreData
(
lastX
,
lastY
,
x
,
y
)
{
// State changes are often (but not always!) async. We want the latest value.
const
isStart
=
!
isNum
(
lastX
);
if
(
isStart
)
{
// If this is our first move, use the x and y as last coords.
return
{
deltaX
:
0
,
deltaY
:
0
,
lastX
:
x
,
lastY
:
y
,
x
,
y
};
}
else
{
// Otherwise calculate proper values.
return
{
deltaX
:
x
-
lastX
,
deltaY
:
y
-
lastY
,
lastX
,
lastY
,
x
,
y
};
}
}
function
isNum
(
num
)
{
return
typeof
num
===
'
number
'
&&
!
isNaN
(
num
);
}
app/web/page/activity/component/helpers/responsiveUtils.ts
0 → 100644
View file @
9ebd2881
// @flow
import
{
cloneLayout
,
compact
,
correctBounds
}
from
'
./utils
'
;
// import type {Layout} from './utils';
// export type ResponsiveLayout = {lg, md, sm, xs, xxs};
// type Breakpoint = string;
// type Breakpoints = {lg, md, sm, xs, xxs};
/**
* Given a width, find the highest breakpoint that matches is valid for it (width > breakpoint).
*
* @param {Object} breakpoints Breakpoints object (e.g. {lg: 1200, md: 960, ...})
* @param {Number} width Screen width.
* @return {String} Highest breakpoint that is less than width.
*/
export
function
getBreakpointFromWidth
(
breakpoints
,
width
)
{
const
sorted
=
sortBreakpoints
(
breakpoints
);
let
matching
=
sorted
[
0
];
for
(
let
i
=
1
,
len
=
sorted
.
length
;
i
<
len
;
i
++
)
{
const
breakpointName
=
sorted
[
i
];
if
(
width
>
breakpoints
[
breakpointName
])
{
matching
=
breakpointName
;
}
}
return
matching
;
}
/**
* Given a breakpoint, get the # of cols set for it.
* @param {String} breakpoint Breakpoint name.
* @param {Object} cols Map of breakpoints to cols.
* @return {Number} Number of cols.
*/
export
function
getColsFromBreakpoint
(
breakpoint
,
cols
)
{
if
(
!
cols
[
breakpoint
])
{
throw
new
Error
(
'
ResponsiveGridLayout: `cols` entry for breakpoint
'
+
breakpoint
+
'
is missing!
'
);
}
return
cols
[
breakpoint
];
}
/**
* Given existing layouts and a new breakpoint, find or generate a new layout.
*
* This finds the layout above the new one and generates from it, if it exists.
*
* @param {Array} orgLayout Original layout.
* @param {Object} layouts Existing layouts.
* @param {Array} breakpoints All breakpoints.
* @param {String} breakpoint New breakpoint.
* @param {String} breakpoint Last breakpoint (for fallback).
* @param {Number} cols Column count at new breakpoint.
* @param {Boolean} verticalCompact Whether or not to compact the layout
* vertically.
* @return {Array} New layout.
*/
export
function
findOrGenerateResponsiveLayout
(
orgLayout
,
layouts
,
breakpoints
,
breakpoint
,
lastBreakpoint
,
cols
,
verticalCompact
)
{
// If it already exists, just return it.
if
(
layouts
[
breakpoint
])
{
return
cloneLayout
(
layouts
[
breakpoint
]);
}
// Find or generate the next layout
let
layout
=
orgLayout
;
const
breakpointsSorted
=
sortBreakpoints
(
breakpoints
);
const
breakpointsAbove
=
breakpointsSorted
.
slice
(
breakpointsSorted
.
indexOf
(
breakpoint
));
for
(
let
i
=
0
,
len
=
breakpointsAbove
.
length
;
i
<
len
;
i
++
)
{
const
b
=
breakpointsAbove
[
i
];
if
(
layouts
[
b
])
{
layout
=
layouts
[
b
];
break
;
}
}
layout
=
cloneLayout
(
layout
||
[]);
// clone layout so we don't modify existing items
return
compact
(
correctBounds
(
layout
,
{
cols
}),
verticalCompact
);
}
export
function
generateResponsiveLayout
(
layout
,
breakpoints
,
breakpoint
,
lastBreakpoint
,
cols
,
verticalCompact
)
{
// If it already exists, just return it.
/*if (layouts[breakpoint]) return cloneLayout(layouts[breakpoint]);
// Find or generate the next layout
let layout = layouts[lastBreakpoint];*/
/*const breakpointsSorted = sortBreakpoints(breakpoints);
const breakpointsAbove = breakpointsSorted.slice(breakpointsSorted.indexOf(breakpoint));
for (let i = 0, len = breakpointsAbove.length; i < len; i++) {
const b = breakpointsAbove[i];
if (layouts[b]) {
layout = layouts[b];
break;
}
}*/
layout
=
cloneLayout
(
layout
||
[]);
// clone layout so we don't modify existing items
return
compact
(
correctBounds
(
layout
,
{
cols
}),
verticalCompact
);
}
/**
* Given breakpoints, return an array of breakpoints sorted by width. This is usually
* e.g. ['xxs', 'xs', 'sm', ...]
*
* @param {Object} breakpoints Key/value pair of breakpoint names to widths.
* @return {Array} Sorted breakpoints.
*/
export
function
sortBreakpoints
(
breakpoints
)
{
const
keys
=
Object
.
keys
(
breakpoints
);
return
keys
.
sort
(
function
(
a
,
b
)
{
return
breakpoints
[
a
]
-
breakpoints
[
b
];
});
}
app/web/page/activity/component/helpers/utils.ts
0 → 100644
View file @
9ebd2881
// @flow
// export type LayoutItemRequired = {w, h, x, y, i};
// export type LayoutItem = LayoutItemRequired &
// {minW?, minH?, maxW?, maxH?,
// moved?, static?,
// isDraggable?, isResizable?};
// export type Layout = Array<LayoutItem>;
// export type Position = {left, top, width, height};
/*
export type DragCallbackData = {
node: HTMLElement,
x, y,
deltaX, deltaY,
lastX, lastY
};
*/
// export type DragEvent = {e: Event} & DragCallbackData;
// export type Size = {width, height};
// export type ResizeEvent = {e: Event, node: HTMLElement, size: Size};
// const isProduction = process.env.NODE_ENV === 'production';
/**
* Return the bottom coordinate of the layout.
*
* @param {Array} layout Layout array.
* @return {Number} Bottom coordinate.
*/
export
function
bottom
(
layout
)
{
let
max
=
0
,
bottomY
;
for
(
let
i
=
0
,
len
=
layout
.
length
;
i
<
len
;
i
++
)
{
bottomY
=
layout
[
i
].
y
+
layout
[
i
].
h
;
if
(
bottomY
>
max
)
{
max
=
bottomY
;
}
}
return
max
;
}
export
function
cloneLayout
(
layout
)
{
const
newLayout
=
Array
(
layout
.
length
);
for
(
let
i
=
0
,
len
=
layout
.
length
;
i
<
len
;
i
++
)
{
newLayout
[
i
]
=
cloneLayoutItem
(
layout
[
i
]);
}
return
newLayout
;
}
// Fast path to cloning, since this is monomorphic
export
function
cloneLayoutItem
(
layoutItem
)
{
/*return {
w.w, h.h, x.x, y.y, i.i,
minW.minW, maxW.maxW, minH.minH, maxH.maxH,
moved(layoutItem.moved), static(layoutItem.static),
// These can be null
isDraggable.isDraggable, isResizable.isResizable
};*/
return
JSON
.
parse
(
JSON
.
stringify
(
layoutItem
));
}
/**
* Given two layoutitems, check if they collide.
*
* @return {Boolean} True if colliding.
*/
export
function
collides
(
l1
,
l2
)
{
if
(
l1
===
l2
)
{
return
false
;
}
// same element
if
(
l1
.
x
+
l1
.
w
<=
l2
.
x
)
{
return
false
;
}
// l1 is left of l2
if
(
l1
.
x
>=
l2
.
x
+
l2
.
w
)
{
return
false
;
}
// l1 is right of l2
if
(
l1
.
y
+
l1
.
h
<=
l2
.
y
)
{
return
false
;
}
// l1 is above l2
if
(
l1
.
y
>=
l2
.
y
+
l2
.
h
)
{
return
false
;
}
// l1 is below l2
return
true
;
// boxes overlap
}
/**
* Given a layout, compact it. This involves going down each y coordinate and removing gaps
* between items.
*
* @param {Array} layout Layout.
* @param {Boolean} verticalCompact Whether or not to compact the layout
* vertically.
* @return {Array} Compacted Layout.
*/
export
function
compact
(
layout
,
verticalCompact
)
{
// Statics go in the compareWith array right away so items flow around them.
const
compareWith
=
getStatics
(
layout
);
// We go through the items by row and column.
const
sorted
=
sortLayoutItemsByRowCol
(
layout
);
// Holding for new items.
const
out
=
Array
(
layout
.
length
);
for
(
let
i
=
0
,
len
=
sorted
.
length
;
i
<
len
;
i
++
)
{
let
l
=
sorted
[
i
];
// Don't move static elements
if
(
!
l
.
static
)
{
l
=
compactItem
(
compareWith
,
l
,
verticalCompact
);
// Add to comparison array. We only collide with items before this one.
// Statics are already in this array.
compareWith
.
push
(
l
);
}
// Add to output array to make sure they still come out in the right order.
out
[
layout
.
indexOf
(
l
)]
=
l
;
// Clear moved flag, if it exists.
l
.
moved
=
false
;
}
return
out
;
}
/**
* Compact an item in the layout.
*/
export
function
compactItem
(
compareWith
,
l
,
verticalCompact
)
{
if
(
verticalCompact
)
{
// Move the element up as far as it can go without colliding.
while
(
l
.
y
>
0
&&
!
getFirstCollision
(
compareWith
,
l
))
{
l
.
y
--
;
}
}
// Move it down, and keep moving it down if it's colliding.
let
collides
;
while
((
collides
=
getFirstCollision
(
compareWith
,
l
)))
{
l
.
y
=
collides
.
y
+
collides
.
h
;
}
return
l
;
}
/**
* Given a layout, make sure all elements fit within its bounds.
*
* @param {Array} layout Layout array.
* @param {Number} bounds Number of columns.
*/
export
function
correctBounds
(
layout
,
bounds
)
{
const
collidesWith
=
getStatics
(
layout
);
for
(
let
i
=
0
,
len
=
layout
.
length
;
i
<
len
;
i
++
)
{
const
l
=
layout
[
i
];
// Overflows right
if
(
l
.
x
+
l
.
w
>
bounds
.
cols
)
{
l
.
x
=
bounds
.
cols
-
l
.
w
;
}
// Overflows left
if
(
l
.
x
<
0
)
{
l
.
x
=
0
;
l
.
w
=
bounds
.
cols
;
}
if
(
!
l
.
static
)
{
collidesWith
.
push
(
l
);
}
else
{
// If this is static and collides with other statics, we must move it down.
// We have to do something nicer than just letting them overlap.
while
(
getFirstCollision
(
collidesWith
,
l
))
{
l
.
y
++
;
}
}
}
return
layout
;
}
/**
* Get a layout item by ID. Used so we can override later on if necessary.
*
* @param {Array} layout Layout array.
* @param {String} id ID
* @return {LayoutItem} Item at ID.
*/
export
function
getLayoutItem
(
layout
,
id
)
{
for
(
let
i
=
0
,
len
=
layout
.
length
;
i
<
len
;
i
++
)
{
if
(
layout
[
i
].
i
===
id
)
{
return
layout
[
i
];
}
}
}
/**
* Returns the first item this layout collides with.
* It doesn't appear to matter which order we approach this from, although
* perhaps that is the wrong thing to do.
*
* @param {Object} layoutItem Layout item.
* @return {Object|undefined} A colliding layout item, or undefined.
*/
export
function
getFirstCollision
(
layout
,
layoutItem
)
{
for
(
let
i
=
0
,
len
=
layout
.
length
;
i
<
len
;
i
++
)
{
if
(
collides
(
layout
[
i
],
layoutItem
))
{
return
layout
[
i
];
}
}
}
export
function
getAllCollisions
(
layout
,
layoutItem
)
{
return
layout
.
filter
((
l
)
=>
collides
(
l
,
layoutItem
));
}
/**
* Get all static elements.
* @param {Array} layout Array of layout objects.
* @return {Array} Array of static layout items..
*/
export
function
getStatics
(
layout
)
{
// return [];
return
layout
.
filter
((
l
)
=>
l
.
static
);
}
/**
* Move an element. Responsible for doing cascading movements of other elements.
*
* @param {Array} layout Full layout to modify.
* @param {LayoutItem} l element to move.
* @param {Number} [x] X position in grid units.
* @param {Number} [y] Y position in grid units.
* @param {Boolean} [isUserAction] If true, designates that the item we're moving is
* being dragged/resized by th euser.
*/
export
function
moveElement
(
layout
,
l
,
x
,
y
,
isUserAction
,
preventCollision
)
{
if
(
l
.
static
)
{
return
layout
;
}
// Short-circuit if nothing to do.
// if (l.y === y && l.x === x) return layout;
const
oldX
=
l
.
x
;
const
oldY
=
l
.
y
;
const
movingUp
=
y
&&
l
.
y
>
y
;
// This is quite a bit faster than extending the object
if
(
typeof
x
===
'
number
'
)
{
l
.
x
=
x
;
}
if
(
typeof
y
===
'
number
'
)
{
l
.
y
=
y
;
}
l
.
moved
=
true
;
// If this collides with anything, move it.
// When doing this comparison, we have to sort the items we compare with
// to ensure, in the case of multiple collisions, that we're getting the
// nearest collision.
let
sorted
=
sortLayoutItemsByRowCol
(
layout
);
if
(
movingUp
)
{
sorted
=
sorted
.
reverse
();
}
const
collisions
=
getAllCollisions
(
sorted
,
l
);
if
(
preventCollision
&&
collisions
.
length
)
{
l
.
x
=
oldX
;
l
.
y
=
oldY
;
l
.
moved
=
false
;
return
layout
;
}
// Move each item that collides away from this element.
for
(
let
i
=
0
,
len
=
collisions
.
length
;
i
<
len
;
i
++
)
{
const
collision
=
collisions
[
i
];
// console.log('resolving collision between', l.i, 'at', l.y, 'and', collision.i, 'at', collision.y);
// Short circuit so we can't infinite loop
if
(
collision
.
moved
)
{
continue
;
}
// This makes it feel a bit more precise by waiting to swap for just a bit when moving up.
if
(
l
.
y
>
collision
.
y
&&
l
.
y
-
collision
.
y
>
collision
.
h
/
4
)
{
continue
;
}
// Don't move static items - we have to move *this* element away
if
(
collision
.
static
)
{
layout
=
moveElementAwayFromCollision
(
layout
,
collision
,
l
,
isUserAction
);
}
else
{
layout
=
moveElementAwayFromCollision
(
layout
,
l
,
collision
,
isUserAction
);
}
}
return
layout
;
}
/**
* This is where the magic needs to happen - given a collision, move an element away from the collision.
* We attempt to move it up if there's room, otherwise it goes below.
*
* @param {Array} layout Full layout to modify.
* @param {LayoutItem} collidesWith Layout item we're colliding with.
* @param {LayoutItem} itemToMove Layout item we're moving.
* @param {Boolean} [isUserAction] If true, designates that the item we're moving is being dragged/resized
* by the user.
*/
export
function
moveElementAwayFromCollision
(
layout
,
collidesWith
,
itemToMove
,
isUserAction
)
{
const
preventCollision
=
false
;
// we're already colliding
// If there is enough space above the collision to put this element, move it there.
// We only do this on the main collision as this can get funky in cascades and cause
// unwanted swapping behavior.
if
(
isUserAction
)
{
// Make a mock item so we don't modify the item here, only modify in moveElement.
const
fakeItem
=
{
x
:
itemToMove
.
x
,
y
:
itemToMove
.
y
,
w
:
itemToMove
.
w
,
h
:
itemToMove
.
h
,
i
:
'
-1
'
};
fakeItem
.
y
=
Math
.
max
(
collidesWith
.
y
-
itemToMove
.
h
,
0
);
if
(
!
getFirstCollision
(
layout
,
fakeItem
))
{
return
moveElement
(
layout
,
itemToMove
,
undefined
,
fakeItem
.
y
,
preventCollision
);
}
}
// Previously this was optimized to move below the collision directly, but this can cause problems
// with cascading moves, as an item may actually leapflog a collision and cause a reversal in order.
return
moveElement
(
layout
,
itemToMove
,
undefined
,
itemToMove
.
y
+
1
,
preventCollision
);
}
/**
* Helper to convert a number to a percentage string.
*
* @param {Number} num Any number
* @return {String} That number as a percentage.
*/
export
function
perc
(
num
)
{
return
num
*
100
+
'
%
'
;
}
export
function
setTransform
(
top
,
left
,
width
,
height
)
{
// Replace unitless items with px
const
translate
=
'
translate3d(
'
+
left
+
'
px,
'
+
top
+
'
px, 0)
'
;
return
{
transform
:
translate
,
WebkitTransform
:
translate
,
MozTransform
:
translate
,
msTransform
:
translate
,
OTransform
:
translate
,
width
:
width
+
'
px
'
,
height
:
height
+
'
px
'
,
position
:
'
absolute
'
};
}
/**
* Just like the setTransform method, but instead it will return a negative value of right.
*
* @param top
* @param right
* @param width
* @param height
* @returns {{transform, WebkitTransform, MozTransform, msTransform, OTransform, width, height, position}}
*/
export
function
setTransformRtl
(
top
,
right
,
width
,
height
)
{
// Replace unitless items with px
const
translate
=
'
translate3d(
'
+
right
*
-
1
+
'
px,
'
+
top
+
'
px, 0)
'
;
return
{
transform
:
translate
,
WebkitTransform
:
translate
,
MozTransform
:
translate
,
msTransform
:
translate
,
OTransform
:
translate
,
width
:
width
+
'
px
'
,
height
:
height
+
'
px
'
,
position
:
'
absolute
'
};
}
export
function
setTopLeft
(
top
,
left
,
width
,
height
)
{
return
{
top
:
top
+
'
px
'
,
left
:
left
+
'
px
'
,
width
:
width
+
'
px
'
,
height
:
height
+
'
px
'
,
position
:
'
absolute
'
};
}
/**
* Just like the setTopLeft method, but instead, it will return a right property instead of left.
*
* @param top
* @param right
* @param width
* @param height
* @returns {{top, right, width, height, position}}
*/
export
function
setTopRight
(
top
,
right
,
width
,
height
)
{
return
{
top
:
top
+
'
px
'
,
right
:
right
+
'
px
'
,
width
:
width
+
'
px
'
,
height
:
height
+
'
px
'
,
position
:
'
absolute
'
};
}
/**
* Get layout items sorted from top left to right and down.
*
* @return {Array} Array of layout objects.
* @return {Array} Layout, sorted static items first.
*/
export
function
sortLayoutItemsByRowCol
(
layout
)
{
return
[].
concat
(
layout
).
sort
(
function
(
a
,
b
)
{
if
(
a
.
y
===
b
.
y
&&
a
.
x
===
b
.
x
)
{
return
0
;
}
if
(
a
.
y
>
b
.
y
||
(
a
.
y
===
b
.
y
&&
a
.
x
>
b
.
x
))
{
return
1
;
}
return
-
1
;
});
}
/**
* Generate a layout using the initialLayout and children as a template.
* Missing entries will be added, extraneous ones will be truncated.
*
* @param {Array} initialLayout Layout passed in through props.
* @param {String} breakpoint Current responsive breakpoint.
* @param {Boolean} verticalCompact Whether or not to compact the layout vertically.
* @return {Array} Working layout.
*/
/*
export function synchronizeLayoutWithChildren(initialLayout, children: Array<React.Element>|React.Element,
cols, verticalCompact) {
// ensure 'children' is always an array
if (!Array.isArray(children)) {
children = [children];
}
initialLayout = initialLayout || [];
// Generate one layout item per child.
let layout = [];
for (let i = 0, len = children.length; i < len; i++) {
let newItem;
const child = children[i];
// Don't overwrite if it already exists.
const exists = getLayoutItem(initialLayout, child.key || "1" /!* FIXME satisfies Flow *!/);
if (exists) {
newItem = exists;
} else {
const g = child.props._grid;
// Hey, this item has a _grid property, use it.
if (g) {
if (!isProduction) {
validateLayout([g], 'ReactGridLayout.children');
}
// Validated; add it to the layout. Bottom 'y' possible is the bottom of the layout.
// This allows you to do nice stuff like specify {y: Infinity}
if (verticalCompact) {
newItem = cloneLayoutItem({...g, y: Math.min(bottom(layout), g.y), i: child.key});
} else {
newItem = cloneLayoutItem({...g, y: g.y, i: child.key});
}
}
// Nothing provided: ensure this is added to the bottom
else {
newItem = cloneLayoutItem({w: 1, h: 1, x: 0, y: bottom(layout), i: child.key || "1"});
}
}
layout[i] = newItem;
}
// Correct the layout.
layout = correctBounds(layout, {cols: cols});
layout = compact(layout, verticalCompact);
return layout;
}
*/
/**
* Validate a layout. Throws errors.
*
* @param {Array} layout Array of layout items.
* @param {String} [contextName] Context name for errors.
* @throw {Error} Validation error.
*/
export
function
validateLayout
(
layout
,
contextName
)
{
contextName
=
contextName
||
'
Layout
'
;
const
subProps
=
[
'
x
'
,
'
y
'
,
'
w
'
,
'
h
'
];
if
(
!
Array
.
isArray
(
layout
))
{
throw
new
Error
(
contextName
+
'
must be an array!
'
);
}
for
(
let
i
=
0
,
len
=
layout
.
length
;
i
<
len
;
i
++
)
{
const
item
=
layout
[
i
];
for
(
let
j
=
0
;
j
<
subProps
.
length
;
j
++
)
{
if
(
typeof
item
[
subProps
[
j
]]
!==
'
number
'
)
{
throw
new
Error
(
'
VueGridLayout:
'
+
contextName
+
'
[
'
+
i
+
'
].
'
+
subProps
[
j
]
+
'
must be a number!
'
);
}
}
if
(
item
.
i
&&
typeof
item
.
i
!==
'
string
'
)
{
// number is also ok, so comment the error
// TODO confirm if commenting the line below doesn't cause unexpected problems
// throw new Error('VueGridLayout: ' + contextName + '[' + i + '].i must be a string!');
}
if
(
item
.
static
!==
undefined
&&
typeof
item
.
static
!==
'
boolean
'
)
{
throw
new
Error
(
'
VueGridLayout:
'
+
contextName
+
'
[
'
+
i
+
'
].static must be a boolean!
'
);
}
}
}
// Flow can't really figure this out, so we just use Object
export
function
autoBindHandlers
(
el
,
fns
)
{
fns
.
forEach
((
key
)
=>
el
[
key
]
=
el
[
key
].
bind
(
el
));
}
/**
* Convert a JS object to CSS string. Similar to React's output of CSS.
* @param obj
* @returns {string}
*/
export
function
createMarkup
(
obj
)
{
const
keys
=
Object
.
keys
(
obj
);
if
(
!
keys
.
length
)
{
return
''
;
}
let
i
,
len
=
keys
.
length
;
let
result
=
''
;
for
(
i
=
0
;
i
<
len
;
i
++
)
{
const
key
=
keys
[
i
];
const
val
=
obj
[
key
];
result
+=
hyphenate
(
key
)
+
'
:
'
+
addPx
(
key
,
val
)
+
'
;
'
;
}
return
result
;
}
/* The following list is defined in React's core */
export
let
IS_UNITLESS
=
{
animationIterationCount
:
true
,
boxFlex
:
true
,
boxFlexGroup
:
true
,
boxOrdinalGroup
:
true
,
columnCount
:
true
,
flex
:
true
,
flexGrow
:
true
,
flexPositive
:
true
,
flexShrink
:
true
,
flexNegative
:
true
,
flexOrder
:
true
,
gridRow
:
true
,
gridColumn
:
true
,
fontWeight
:
true
,
lineClamp
:
true
,
lineHeight
:
true
,
opacity
:
true
,
order
:
true
,
orphans
:
true
,
tabSize
:
true
,
widows
:
true
,
zIndex
:
true
,
zoom
:
true
,
// SVG-related properties
fillOpacity
:
true
,
stopOpacity
:
true
,
strokeDashoffset
:
true
,
strokeOpacity
:
true
,
strokeWidth
:
true
};
/**
* Will add px to the end of style values which are Numbers.
* @param name
* @param value
* @returns {*}
*/
export
function
addPx
(
name
,
value
)
{
if
(
typeof
value
===
'
number
'
&&
!
IS_UNITLESS
[
name
])
{
return
value
+
'
px
'
;
}
else
{
return
value
;
}
}
/**
* Hyphenate a camelCase string.
*
* @param {String} str
* @return {String}
*/
export
let
hyphenateRE
=
/
([
a-z
\d])([
A-Z
])
/g
;
export
function
hyphenate
(
str
)
{
return
str
.
replace
(
hyphenateRE
,
'
$1-$2
'
).
toLowerCase
();
}
export
function
findItemInArray
(
array
,
property
,
value
)
{
for
(
let
i
=
0
;
i
<
array
.
length
;
i
++
)
{
if
(
array
[
i
][
property
]
==
value
)
{
return
true
;
}
}
return
false
;
}
export
function
findAndRemove
(
array
,
property
,
value
)
{
array
.
forEach
(
function
(
result
,
index
)
{
if
(
result
[
property
]
===
value
)
{
// Remove from array
array
.
splice
(
index
,
1
);
}
});
}
app/web/page/editor/component/Contextmenu/constant.ts
0 → 100644
View file @
9ebd2881
export
const
SUBMENU_X_OFFSET
=
3
;
export
const
SUBMENU_Y_OFFSET
=
-
8
;
export
const
SUBMENU_OPEN_TREND_LEFT
=
'
left
'
;
export
const
SUBMENU_OPEN_TREND_RIGHT
=
'
right
'
;
export
const
COMPONENT_NAME
=
'
contextmenu-submenu
'
;
app/web/page/editor/component/Contextmenu/index.ts
0 → 100644
View file @
9ebd2881
import
Vue
from
'
vue
'
;
import
Contextmenu
from
'
./components/Contextmenu
'
;
import
Submenu
from
'
./components/Submenu
'
;
import
{
COMPONENT_NAME
}
from
'
./constant
'
;
const
ContextmenuConstructor
=
Vue
.
extend
(
Contextmenu
);
Vue
.
component
(
COMPONENT_NAME
,
Submenu
);
function
install
(
Vue
)
{
let
lastInstance
=
null
;
const
ContextmenuProxy
=
function
(
options
)
{
const
instance
=
new
ContextmenuConstructor
();
instance
.
items
=
options
.
items
;
instance
.
position
.
x
=
options
.
x
||
0
;
instance
.
position
.
y
=
options
.
y
||
0
;
if
(
options
.
event
)
{
instance
.
position
.
x
=
options
.
event
.
clientX
;
instance
.
position
.
y
=
options
.
event
.
clientY
;
}
instance
.
customClass
=
options
.
customClass
;
options
.
minWidth
&&
(
instance
.
style
.
minWidth
=
options
.
minWidth
);
options
.
zIndex
&&
(
instance
.
style
.
zIndex
=
options
.
zIndex
);
ContextmenuProxy
.
destroy
();
lastInstance
=
instance
;
instance
.
$mount
();
};
ContextmenuProxy
.
destroy
=
function
()
{
if
(
lastInstance
)
{
lastInstance
.
$destroy
();
lastInstance
=
null
;
}
};
Vue
.
prototype
.
$contextmenu
=
ContextmenuProxy
;
}
if
(
window
&&
window
.
Vue
)
{
install
(
window
.
Vue
);
}
export
default
{
install
};
app/web/page/editor/component/Contextmenu/util.ts
0 → 100644
View file @
9ebd2881
export
function
hasClass
(
el
,
className
)
{
if
(
!
className
)
{
return
true
;
}
if
(
!
el
||
!
el
.
className
||
typeof
el
.
className
!==
'
string
'
)
{
return
false
;
}
for
(
const
cn
of
el
.
className
.
split
(
/
\s
+/
))
{
if
(
cn
===
className
)
{
return
true
;
}
}
return
false
;
}
export
function
getElementsByClassName
(
className
)
{
const
els
=
[];
for
(
const
el
of
document
.
getElementsByClassName
(
className
)
||
[])
{
els
.
push
(
el
);
}
return
els
;
}
export
function
uuid
()
{
return
'
xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
'
.
replace
(
/
[
xy
]
/g
,
function
(
c
)
{
const
r
=
Math
.
random
()
*
16
|
0
,
v
=
c
==
'
x
'
?
r
:
(
r
&
0x3
|
0x8
);
return
v
.
toString
(
16
);
});
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment