webapps added
This commit is contained in:
parent
a4bf803b7c
commit
741b10515d
21
.hgignore
Normal file
21
.hgignore
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
syntax: glob
|
||||
|
||||
.idea
|
||||
Thumbs.db
|
||||
.DS_Store
|
||||
deploy
|
||||
build/node_modules
|
||||
apps/documenteditor/embed/resources/less/node_modules
|
||||
apps/presentationeditor/embed/resources/less/node_modules
|
||||
apps/spreadsheeteditor/embed/resources/less/node_modules
|
||||
apps/documenteditor/mobile/resources/sass/.sass-cache
|
||||
apps/spreadsheeteditor/mobile/resources/sass/.sass-cache
|
||||
|
||||
|
||||
# test documents
|
||||
apps/presentationeditor/embed/document
|
||||
apps/presentationeditor/main/document
|
||||
apps/presentationeditor/mobile/document
|
||||
apps/spreadsheeteditor/embed/offlinedocs
|
||||
apps/spreadsheeteditor/main/offlinedocs
|
||||
apps/spreadsheeteditor/mobile/offlinedocs
|
||||
679
apps/api/documents/api.js
Normal file
679
apps/api/documents/api.js
Normal file
|
|
@ -0,0 +1,679 @@
|
|||
/**
|
||||
* Copyright (c) Ascensio System SIA 2013. All rights reserved
|
||||
*
|
||||
* http://www.onlyoffice.com
|
||||
*/
|
||||
|
||||
;(function(DocsAPI, window, document, undefined) {
|
||||
|
||||
/*
|
||||
|
||||
# Full #
|
||||
|
||||
config = {
|
||||
type: 'desktop or mobile',
|
||||
width: '100% by default',
|
||||
height: '100% by default',
|
||||
documentType: 'text' | 'spreadsheet' | 'presentation',
|
||||
document: {
|
||||
title: 'document title',
|
||||
url: 'document url'
|
||||
fileType: 'document file type',
|
||||
options: <advanced options>,
|
||||
key: 'key',
|
||||
vkey: 'vkey',
|
||||
info: {
|
||||
author: 'author name',
|
||||
folder: 'path to document',
|
||||
created: '<creation date>',
|
||||
sharingSettings: [
|
||||
{
|
||||
user: 'user name',
|
||||
permissions: '<permissions>',
|
||||
isLink: false
|
||||
},
|
||||
...
|
||||
]
|
||||
},
|
||||
permissions: {
|
||||
edit: <can edit>, // default = true
|
||||
download: <can download>,
|
||||
reader: <can view in readable mode>
|
||||
review: <can review> // default = edit,
|
||||
print: <can print> // default = true
|
||||
}
|
||||
},
|
||||
editorConfig: {
|
||||
mode: 'view or edit',
|
||||
lang: <language code>,
|
||||
canCoAuthoring: <can coauthoring documents>,
|
||||
canAutosave: <can autosave documents>,
|
||||
canBackToFolder: <can return to folder> - deprecated. use "customization.goback" parameter,
|
||||
createUrl: 'create document url',
|
||||
sharingSettingsUrl: 'document sharing settings url',
|
||||
fileChoiceUrl: 'mail merge sources url',
|
||||
callbackUrl: <url for connection between sdk and portal>,
|
||||
mergeFolderUrl: 'folder for saving merged file',
|
||||
licenseUrl: <url for license>,
|
||||
customerId: <customer id>,
|
||||
|
||||
user: {
|
||||
id: 'user id',
|
||||
firstname: 'user first name',
|
||||
lastname: 'user last name'
|
||||
},
|
||||
recent: [
|
||||
{
|
||||
title: 'document title',
|
||||
url: 'document url',
|
||||
folder: 'path to document'
|
||||
},
|
||||
...
|
||||
],
|
||||
templates: [
|
||||
{
|
||||
name: 'template name',
|
||||
icon: 'template icon url',
|
||||
url: 'http://...'
|
||||
},
|
||||
...
|
||||
],
|
||||
customization: {
|
||||
logo: {
|
||||
image: url,
|
||||
imageEmbedded: url,
|
||||
url: http://...
|
||||
},
|
||||
backgroundColor: 'header background color',
|
||||
textColor: 'header text color',
|
||||
customer: {
|
||||
name: 'SuperPuper',
|
||||
address: 'New-York, 125f-25',
|
||||
mail: 'support@gmail.com',
|
||||
www: 'www.superpuper.com',
|
||||
info: 'Some info',
|
||||
logo: ''
|
||||
},
|
||||
about: false,
|
||||
feedback: {
|
||||
visible: false,
|
||||
url: http://...
|
||||
},
|
||||
goback: {
|
||||
url: 'http://...',
|
||||
text: 'Go to London'
|
||||
},
|
||||
chat: false,
|
||||
comments: false
|
||||
}
|
||||
},
|
||||
events: {
|
||||
'onReady': <document ready callback>,
|
||||
'onBack': <back to folder callback>,
|
||||
'onDocumentStateChange': <document state changed callback>,
|
||||
'onSave': <save request callback>
|
||||
}
|
||||
}
|
||||
|
||||
# Embedded #
|
||||
|
||||
config = {
|
||||
type: 'embedded',
|
||||
width: '100% by default',
|
||||
height: '100% by default',
|
||||
documentType: 'text' | 'spreadsheet' | 'presentation',
|
||||
document: {
|
||||
title: 'document title',
|
||||
url: 'document url',
|
||||
fileType: 'document file type',
|
||||
key: 'key',
|
||||
vkey: 'vkey'
|
||||
},
|
||||
editorConfig: {
|
||||
licenseUrl: <url for license>,
|
||||
customerId: <customer id>,
|
||||
embedded: {
|
||||
embedUrl: 'url',
|
||||
fullscreenUrl: 'url',
|
||||
saveUrl: 'url',
|
||||
shareUrl: 'url',
|
||||
toolbarDocked: 'top or bottom'
|
||||
}
|
||||
},
|
||||
events: {
|
||||
'onReady': <document ready callback>,
|
||||
'onBack': <back to folder callback>,
|
||||
'onError': <error callback>,
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// TODO: allow several instances on one page simultaneously
|
||||
|
||||
DocsAPI.DocEditor = function(placeholderId, config) {
|
||||
var _self = this,
|
||||
_config = config || {};
|
||||
|
||||
extend(_config, DocsAPI.DocEditor.defaultConfig);
|
||||
_config.editorConfig.canUseHistory = _config.events && !!_config.events.onRequestHistory;
|
||||
_config.editorConfig.canHistoryClose = _config.events && !!_config.events.onRequestHistoryClose;
|
||||
_config.editorConfig.canSendEmailAddresses = _config.events && !!_config.events.onRequestEmailAddresses;
|
||||
_config.editorConfig.canRequestEditRights = _config.events && !!_config.events.onRequestEditRights;
|
||||
|
||||
var onMouseUp = function (evt) {
|
||||
_processMouse(evt);
|
||||
};
|
||||
|
||||
var _attachMouseEvents = function() {
|
||||
if (window.addEventListener) {
|
||||
window.addEventListener("mouseup", onMouseUp, false)
|
||||
} else if (window.attachEvent) {
|
||||
window.attachEvent("onmouseup", onMouseUp);
|
||||
}
|
||||
};
|
||||
|
||||
var _detachMouseEvents = function() {
|
||||
if (window.removeEventListener) {
|
||||
window.removeEventListener("mouseup", onMouseUp, false)
|
||||
} else if (window.detachEvent) {
|
||||
window.detachEvent("onmouseup", onMouseUp);
|
||||
}
|
||||
};
|
||||
|
||||
var _onReady = function() {
|
||||
if (_config.type === 'mobile') {
|
||||
document.body.onfocus = function(e) {
|
||||
setTimeout(function(){
|
||||
iframe.contentWindow.focus();
|
||||
|
||||
_sendCommand({
|
||||
command: 'resetFocus',
|
||||
data: {}
|
||||
})
|
||||
}, 10);
|
||||
};
|
||||
}
|
||||
|
||||
_attachMouseEvents();
|
||||
|
||||
if (_config.editorConfig) {
|
||||
_init(_config.editorConfig);
|
||||
}
|
||||
|
||||
if (_config.document) {
|
||||
_openDocument(_config.document);
|
||||
}
|
||||
};
|
||||
|
||||
var _callLocalStorage = function(data) {
|
||||
if (data.cmd == 'get') {
|
||||
if (data.keys && data.keys.length) {
|
||||
var af = data.keys.split(','), re = af[0];
|
||||
for (i = 0; ++i < af.length;)
|
||||
re += '|' + af[i];
|
||||
|
||||
re = new RegExp(re); k = {};
|
||||
for (i in localStorage)
|
||||
if (re.test(i)) k[i] = localStorage[i];
|
||||
} else {
|
||||
k = localStorage;
|
||||
}
|
||||
|
||||
_sendCommand({
|
||||
command: 'internalCommand',
|
||||
data: {
|
||||
type: 'localstorage',
|
||||
keys: k
|
||||
}
|
||||
});
|
||||
} else
|
||||
if (data.cmd == 'set') {
|
||||
var k = data.keys, i;
|
||||
for (i in k) {
|
||||
localStorage.setItem(i, k[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var _onMessage = function(msg) {
|
||||
if (msg) {
|
||||
var events = _config.events || {},
|
||||
handler = events[msg.event],
|
||||
res;
|
||||
|
||||
if (msg.event === 'onRequestEditRights' && !handler) {
|
||||
_applyEditRights(false, 'handler is\'n defined');
|
||||
} else
|
||||
if (msg.event === 'onInternalMessage' && msg.data && msg.data.type == 'localstorage') {
|
||||
_callLocalStorage(msg.data.data);
|
||||
} else {
|
||||
if (msg.event === 'onReady') {
|
||||
_onReady();
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
res = handler.call(_self, { target: _self, data: msg.data });
|
||||
if (msg.event === 'onSave' && res !== false) {
|
||||
_processSaveResult(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var _checkConfigParams = function() {
|
||||
if (_config.document) {
|
||||
if (!_config.document.url || ((typeof _config.document.fileType !== 'string' || _config.document.fileType=='') &&
|
||||
(typeof _config.documentType !== 'string' || _config.documentType==''))) {
|
||||
window.alert("One or more required parameter for the config object is not set");
|
||||
return false;
|
||||
}
|
||||
|
||||
var appMap = {
|
||||
'text': 'docx',
|
||||
'text-pdf': 'pdf',
|
||||
'spreadsheet': 'xlsx',
|
||||
'presentation': 'pptx'
|
||||
}, app;
|
||||
|
||||
if (typeof _config.documentType === 'string' && _config.documentType != '') {
|
||||
app = appMap[_config.documentType.toLowerCase()];
|
||||
if (!app) {
|
||||
window.alert("The \"documentType\" parameter for the config object is invalid. Please correct it.");
|
||||
return false;
|
||||
} else if (typeof _config.document.fileType !== 'string' || _config.document.fileType == '') {
|
||||
_config.document.fileType = app;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof _config.document.fileType === 'string' && _config.document.fileType != '') {
|
||||
var type = /^(?:(xls|xlsx|ods|csv|xlst|xlsy|gsheet)|(pps|ppsx|ppt|pptx|odp|pptt|ppty|gslides)|(doc|docx|doct|odt|gdoc|txt|rtf|pdf|mht|htm|html|epub|djvu|xps))$/
|
||||
.exec(_config.document.fileType);
|
||||
if (!type) {
|
||||
window.alert("The \"document.fileType\" parameter for the config object is invalid. Please correct it.");
|
||||
return false;
|
||||
} else if (typeof _config.documentType !== 'string' || _config.documentType == ''){
|
||||
if (typeof type[1] === 'string') _config.documentType = 'spreadsheet'; else
|
||||
if (typeof type[2] === 'string') _config.documentType = 'presentation'; else
|
||||
if (typeof type[3] === 'string') _config.documentType = 'text';
|
||||
}
|
||||
}
|
||||
|
||||
var type = /^(?:(pdf|djvu|xps))$/.exec(_config.document.fileType);
|
||||
if (type && typeof type[1] === 'string') {
|
||||
if (!_config.document.permissions)
|
||||
_config.document.permissions = {};
|
||||
_config.document.permissions.edit = false;
|
||||
}
|
||||
|
||||
if (!_config.document.title || _config.document.title=='')
|
||||
_config.document.title = 'Unnamed.' + _config.document.fileType;
|
||||
|
||||
if (!_config.document.key) {
|
||||
_config.document.key = 'xxxxxxxxxxxxxxxxxxxx'.replace(/[x]/g, function (c) {var r = Math.random() * 16 | 0; return r.toString(16);});
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
(function() {
|
||||
var result = /[\?\&]placement=(\w+)&?/.exec(window.location.search);
|
||||
if (!!result && result.length) {
|
||||
if (result[1] == 'desktop') {
|
||||
_config.editorConfig.targetApp = result[1];
|
||||
_config.editorConfig.canBackToFolder = false;
|
||||
_config.editorConfig.canUseHistory = false;
|
||||
if (!_config.editorConfig.customization) _config.editorConfig.customization = {};
|
||||
_config.editorConfig.customization.about = false;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
var target = document.getElementById(placeholderId),
|
||||
iframe;
|
||||
|
||||
if (target && _checkConfigParams()) {
|
||||
iframe = createIframe(_config);
|
||||
target.parentNode && target.parentNode.replaceChild(iframe, target);
|
||||
this._msgDispatcher = new MessageDispatcher(_onMessage, this);
|
||||
}
|
||||
|
||||
/*
|
||||
cmd = {
|
||||
command: 'commandName',
|
||||
data: <command specific data>
|
||||
}
|
||||
*/
|
||||
var _sendCommand = function(cmd) {
|
||||
if (iframe && iframe.contentWindow)
|
||||
postMessage(iframe.contentWindow, cmd);
|
||||
};
|
||||
|
||||
var _init = function(editorConfig) {
|
||||
_sendCommand({
|
||||
command: 'init',
|
||||
data: {
|
||||
config: editorConfig
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var _openDocument = function(doc) {
|
||||
_sendCommand({
|
||||
command: 'openDocument',
|
||||
data: {
|
||||
doc: doc
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var _showError = function(title, msg) {
|
||||
_showMessage(title, msg, "error");
|
||||
};
|
||||
|
||||
// severity could be one of: "error", "info" or "warning"
|
||||
var _showMessage = function(title, msg, severity) {
|
||||
if (typeof severity !== 'string') {
|
||||
severity = "info";
|
||||
}
|
||||
_sendCommand({
|
||||
command: 'showMessage',
|
||||
data: {
|
||||
title: title,
|
||||
msg: msg,
|
||||
severity: severity
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var _applyEditRights = function(allowed, message) {
|
||||
_sendCommand({
|
||||
command: 'applyEditRights',
|
||||
data: {
|
||||
allowed: allowed,
|
||||
message: message
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var _processSaveResult = function(result, message) {
|
||||
_sendCommand({
|
||||
command: 'processSaveResult',
|
||||
data: {
|
||||
result: result,
|
||||
message: message
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: remove processRightsChange, use denyEditingRights
|
||||
var _processRightsChange = function(enabled, message) {
|
||||
_sendCommand({
|
||||
command: 'processRightsChange',
|
||||
data: {
|
||||
enabled: enabled,
|
||||
message: message
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var _denyEditingRights = function(message) {
|
||||
_sendCommand({
|
||||
command: 'processRightsChange',
|
||||
data: {
|
||||
enabled: false,
|
||||
message: message
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var _refreshHistory = function(data, message) {
|
||||
_sendCommand({
|
||||
command: 'refreshHistory',
|
||||
data: {
|
||||
data: data,
|
||||
message: message
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var _setHistoryData = function(data, message) {
|
||||
_sendCommand({
|
||||
command: 'setHistoryData',
|
||||
data: {
|
||||
data: data,
|
||||
message: message
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var _setEmailAddresses = function(data) {
|
||||
_sendCommand({
|
||||
command: 'setEmailAddresses',
|
||||
data: {
|
||||
data: data
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var _processMailMerge = function(enabled, message) {
|
||||
_sendCommand({
|
||||
command: 'processMailMerge',
|
||||
data: {
|
||||
enabled: enabled,
|
||||
message: message
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var _downloadAs = function() {
|
||||
_sendCommand({
|
||||
command: 'downloadAs'
|
||||
});
|
||||
};
|
||||
|
||||
var _processMouse = function(evt) {
|
||||
var r = iframe.getBoundingClientRect();
|
||||
var data = {
|
||||
type: evt.type,
|
||||
x: evt.x - r.left,
|
||||
y: evt.y - r.top
|
||||
};
|
||||
|
||||
_sendCommand({
|
||||
command: 'processMouse',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
var _serviceCommand = function(command, data) {
|
||||
_sendCommand({
|
||||
command: 'internalCommand',
|
||||
data: {
|
||||
command: command,
|
||||
data: data
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
showError : _showError,
|
||||
showMessage : _showMessage,
|
||||
applyEditRights : _applyEditRights,
|
||||
processSaveResult : _processSaveResult,
|
||||
processRightsChange : _processRightsChange,
|
||||
denyEditingRights : _denyEditingRights,
|
||||
refreshHistory : _refreshHistory,
|
||||
setHistoryData : _setHistoryData,
|
||||
setEmailAddresses : _setEmailAddresses,
|
||||
processMailMerge : _processMailMerge,
|
||||
downloadAs : _downloadAs,
|
||||
serviceCommand : _serviceCommand,
|
||||
attachMouseEvents : _attachMouseEvents,
|
||||
detachMouseEvents : _detachMouseEvents
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
DocsAPI.DocEditor.defaultConfig = {
|
||||
type: 'desktop',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
editorConfig: {
|
||||
lang: 'en',
|
||||
canCoAuthoring: true,
|
||||
customization: {
|
||||
about: false,
|
||||
feedback: false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
DocsAPI.DocEditor.version = function() {
|
||||
return '3.0b##BN#';
|
||||
};
|
||||
|
||||
MessageDispatcher = function(fn, scope) {
|
||||
var _fn = fn,
|
||||
_scope = scope || window;
|
||||
|
||||
var _bindEvents = function() {
|
||||
if (window.addEventListener) {
|
||||
window.addEventListener("message", function(msg) {
|
||||
_onMessage(msg);
|
||||
}, false)
|
||||
}
|
||||
else if (window.attachEvent) {
|
||||
window.attachEvent("onmessage", function(msg) {
|
||||
_onMessage(msg);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var _onMessage = function(msg) {
|
||||
// TODO: check message origin
|
||||
if (msg && window.JSON) {
|
||||
|
||||
try {
|
||||
var msg = window.JSON.parse(msg.data);
|
||||
if (_fn) {
|
||||
_fn.call(_scope, msg);
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
};
|
||||
|
||||
_bindEvents.call(this);
|
||||
};
|
||||
|
||||
function getBasePath() {
|
||||
var scripts = document.getElementsByTagName('script'),
|
||||
match;
|
||||
|
||||
for (var i = scripts.length - 1; i >= 0; i--) {
|
||||
match = scripts[i].src.match(/(.*)api\/documents\/api.js/i);
|
||||
if (match) {
|
||||
return match[1];
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function getExtensionPath() {
|
||||
if ("undefined" == typeof(extensionParams) || null == extensionParams["url"])
|
||||
return null;
|
||||
return extensionParams["url"] + "apps/";
|
||||
}
|
||||
|
||||
function getAppPath(config) {
|
||||
var extensionPath = getExtensionPath(),
|
||||
path = extensionPath ? extensionPath : getBasePath(),
|
||||
appMap = {
|
||||
'text': 'documenteditor',
|
||||
'text-pdf': 'documenteditor',
|
||||
'spreadsheet': 'spreadsheeteditor',
|
||||
'presentation': 'presentationeditor'
|
||||
},
|
||||
app = appMap['text'];
|
||||
|
||||
if (typeof config.documentType === 'string') {
|
||||
app = appMap[config.documentType.toLowerCase()];
|
||||
} else
|
||||
if (!!config.document && typeof config.document.fileType === 'string') {
|
||||
var type = /^(?:(xls|xlsx|ods|csv|xlst|xlsy|gsheet)|(pps|ppsx|ppt|pptx|odp|pptt|ppty|gslides))$/
|
||||
.exec(config.document.fileType);
|
||||
if (type) {
|
||||
if (typeof type[1] === 'string') app = appMap['spreadsheet']; else
|
||||
if (typeof type[2] === 'string') app = appMap['presentation'];
|
||||
}
|
||||
}
|
||||
|
||||
path += app + "/";
|
||||
path += config.type === "mobile"
|
||||
? "mobile"
|
||||
: config.type === "embedded"
|
||||
? "embed"
|
||||
: "main";
|
||||
path += "/index.html";
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
function getAppParameters(config) {
|
||||
var params = "?_dc=0";
|
||||
|
||||
if (config.editorConfig && config.editorConfig.lang)
|
||||
params += "&lang=" + config.editorConfig.lang;
|
||||
|
||||
if (config.editorConfig && config.editorConfig.targetApp!=='desktop') {
|
||||
if ( (typeof(config.editorConfig.customization) == 'object') && config.editorConfig.customization.loaderName) {
|
||||
if (config.editorConfig.customization.loaderName !== 'none') params += "&customer=" + config.editorConfig.customization.loaderName;
|
||||
} else
|
||||
params += "&customer=ONLYOFFICE";
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
function createIframe(config) {
|
||||
var iframe = document.createElement("iframe");
|
||||
|
||||
iframe.src = getAppPath(config) + getAppParameters(config);
|
||||
iframe.width = config.width;
|
||||
iframe.height = config.height;
|
||||
iframe.align = "top";
|
||||
iframe.frameBorder = 0;
|
||||
iframe.name = "frameEditor";
|
||||
iframe.allowFullscreen = true;
|
||||
iframe.setAttribute("allowfullscreen",""); // for IE11
|
||||
iframe.setAttribute("onmousewheel",""); // for Safari on Mac
|
||||
return iframe;
|
||||
}
|
||||
|
||||
function postMessage(wnd, msg) {
|
||||
if (wnd && wnd.postMessage && window.JSON) {
|
||||
// TODO: specify explicit origin
|
||||
wnd.postMessage(window.JSON.stringify(msg), "*");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function extend(dest, src) {
|
||||
for (var prop in src) {
|
||||
if (src.hasOwnProperty(prop)) {
|
||||
if (typeof dest[prop] === 'undefined') {
|
||||
dest[prop] = src[prop];
|
||||
} else
|
||||
if (typeof dest[prop] === 'object' &&
|
||||
typeof src[prop] === 'object') {
|
||||
extend(dest[prop], src[prop])
|
||||
}
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
})(window.DocsAPI = window.DocsAPI || {}, window, document);
|
||||
|
||||
25
apps/api/documents/cache-scripts.html
Normal file
25
apps/api/documents/cache-scripts.html
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>ONLYOFFICE Documents</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||
<meta name="description" content="" />
|
||||
<meta name="keywords" content="" />
|
||||
<style type="text/css"></style>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript" src="../../../vendor/jquery/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../../../vendor/requirejs/require.js"></script>
|
||||
<script type="text/javascript" src="../../../vendor/sockjs/sockjs.min.js"></script>
|
||||
<script type="text/javascript" src="../../../vendor/xregexp/xregexp-all-min.js"></script>
|
||||
<script type="text/javascript" src="../../../sdk/Common/AllFonts.js"></script>
|
||||
<script type="text/javascript" src="../../../sdk/Word/sdk-all.js"></script>
|
||||
<div id="editor_sdk">
|
||||
<script type="text/javascript">
|
||||
var editor = new asc_docs_api("editor_sdk");
|
||||
editor.asc_SetFontsPath("../../../sdk/Fonts/");
|
||||
editor.LoadFontsFromServer();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
352
apps/api/documents/index.html
Normal file
352
apps/api/documents/index.html
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>ONLYOFFICE Documents</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=IE8"/>
|
||||
<meta name="description" content="" />
|
||||
<meta name="keywords" content="" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-touch-fullscreen" content="yes">
|
||||
|
||||
<style type="text/css">
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#wrap {
|
||||
position:absolute;
|
||||
left:0;
|
||||
top:0;
|
||||
right:0;
|
||||
bottom:0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrap">
|
||||
<div id="placeholder"></div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="api.js"></script>
|
||||
<script>
|
||||
(function() {
|
||||
|
||||
// Url parameters
|
||||
|
||||
var urlParams = getUrlParams(),
|
||||
cfg = getEditorConfig(urlParams),
|
||||
doc = getDocumentData(urlParams);
|
||||
|
||||
// Document Editor
|
||||
|
||||
var docEditor = new DocsAPI.DocEditor('placeholder', {
|
||||
type: urlParams['type'],
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
documentType: urlParams['doctype'] || 'text',
|
||||
document: doc,
|
||||
editorConfig: cfg,
|
||||
events: {
|
||||
'onReady': onDocEditorReady,
|
||||
'onDocumentStateChange': onDocumentStateChange,
|
||||
'onRequestEditRights': onRequestEditRights,
|
||||
'onRequestHistory': onRequestHistory,
|
||||
'onRequestHistoryData': onRequestHistoryData,
|
||||
'onRequestEmailAddresses': onRequestEmailAddresses,
|
||||
'onRequestStartMailMerge': onRequestStartMailMerge,
|
||||
'onRequestHistoryClose': onRequestHistoryClose,
|
||||
'onSave': onDocumentSave,
|
||||
'onError': onError
|
||||
}
|
||||
});
|
||||
|
||||
// Document Editor event handlers
|
||||
|
||||
function onRequestEmailAddresses() {
|
||||
docEditor.setEmailAddresses({emailAddresses: ['aaa@mail.ru'], createEmailAccountUrl: 'http://ya.ru'});
|
||||
}
|
||||
|
||||
function onRequestHistory() {
|
||||
docEditor.refreshHistory({
|
||||
'currentVersion': 3,
|
||||
'history': [
|
||||
{
|
||||
'user': {
|
||||
id: '8952d4ee-e8a5-42bf-86f0-6cd77801ec15',
|
||||
name: 'Татьяна Щербакова'
|
||||
},
|
||||
'changes': null,
|
||||
'created': '1/18/2015 6:38 PM',
|
||||
'version': 1,
|
||||
'versionGroup': 1,
|
||||
'key': 'wyX9AwRq_677SWKjhfk='
|
||||
},
|
||||
{
|
||||
'user': {
|
||||
id: '8952d4ee-e8a5-42bf-86f0-6cd77801ec15',
|
||||
name: 'Татьяна Щербакова'
|
||||
},
|
||||
'changes': [
|
||||
{
|
||||
'user': {
|
||||
id: '8952d4ee-e8a5-42bf-86f0-6cd77801ec15',
|
||||
name: 'Татьяна Щербакова'
|
||||
},
|
||||
'created': '1/19/2015 6:30 PM'
|
||||
},
|
||||
{
|
||||
'user': {
|
||||
'id': '8952d4ee-e8a5-42bf-11f0-6cd77801ec15',
|
||||
'name': 'Александр Трофимов'
|
||||
},
|
||||
'created': '1/19/2015 6:32 PM'
|
||||
},
|
||||
{
|
||||
'user': {
|
||||
id: '8952d4ee-e8a5-42bf-86f0-6cd77801ec15',
|
||||
name: 'Татьяна Щербакова'
|
||||
},
|
||||
'created': '1/19/2015 6:38 PM'
|
||||
}
|
||||
],
|
||||
'created': '2/19/2015 6:38 PM',
|
||||
'version': 2,
|
||||
'versionGroup': 1,
|
||||
'key': 'wyX9AwRq_677SWKjhfk='
|
||||
},
|
||||
{
|
||||
'user': {
|
||||
id: '895255ee-e8a5-42bf-86f0-6cd77801ec15',
|
||||
name: 'Me'
|
||||
},
|
||||
'changes': null,
|
||||
'created': '2/21/2015 6:38 PM',
|
||||
'version': 3,
|
||||
'versionGroup': 2,
|
||||
'key': 'wyX9AwRq_677SWKjhfk='
|
||||
},
|
||||
{
|
||||
'user': {
|
||||
id: '8952d4ee-e8a5-42bf-11f0-6cd77801ec15',
|
||||
name: 'Александр Трофимов'
|
||||
},
|
||||
'changes': null,
|
||||
'created': '2/22/2015 6:37 PM',
|
||||
'version': 4,
|
||||
'versionGroup': 3,
|
||||
'key': 'wyX9AwRq_677SWKjhfk='
|
||||
},
|
||||
{
|
||||
'user': {
|
||||
id: '8952d4ee-e8a5-42bf-11f0-6cd33801ec15',
|
||||
name: 'Леонид Орлов'
|
||||
},
|
||||
'changes': null,
|
||||
'created': '2/24/2015 6:29 PM',
|
||||
'version': 5,
|
||||
'versionGroup': 3,
|
||||
'key': 'wyX9AwRq_677SWKjhfk='
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
function onRequestHistoryData(revision) {
|
||||
docEditor.setHistoryData(
|
||||
{
|
||||
'version': revision.data,
|
||||
'url': 'http://isa2',
|
||||
'urlDiff': 'http://isa2'
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function onRequestStartMailMerge() {
|
||||
docEditor.processMailMerge(true, 'some error message');
|
||||
}
|
||||
|
||||
function onRequestHistoryClose() {
|
||||
// reload page
|
||||
}
|
||||
|
||||
function onDocEditorReady(event) {
|
||||
if (event.target) {
|
||||
//console.log('Ready! Editor: ', event.target);
|
||||
}
|
||||
}
|
||||
|
||||
function onDocumentStateChange(event) {
|
||||
var isModified = event.data;
|
||||
//console.log(isModified);
|
||||
}
|
||||
|
||||
function onRequestEditRights(event) {
|
||||
// occurs whenever the user tryes to enter edit mode
|
||||
docEditor.applyEditRights(true, "Someone is editing this document right now. Please try again later.");
|
||||
}
|
||||
|
||||
function onDocumentSave(event) {
|
||||
var url = event.data;
|
||||
// if you want to async save process return false
|
||||
// and call api.processSaveResult when ready
|
||||
}
|
||||
|
||||
function onError(event) {
|
||||
// critical error happened
|
||||
// examine event.data.errorCode and event.data.errorDescription for details
|
||||
}
|
||||
|
||||
function onDownloadAs(event) {
|
||||
// return url of downloaded doc
|
||||
// console.log(event.data);
|
||||
}
|
||||
|
||||
|
||||
// helpers
|
||||
|
||||
function getUrlParams() {
|
||||
var e,
|
||||
a = /\+/g, // Regex for replacing addition symbol with a space
|
||||
r = /([^&=]+)=?([^&]*)/g,
|
||||
d = function (s) { return decodeURIComponent(s.replace(a, " ")); },
|
||||
q = window.location.search.substring(1),
|
||||
urlParams = {};
|
||||
|
||||
while (e = r.exec(q))
|
||||
urlParams[d(e[1])] = d(e[2]);
|
||||
|
||||
return urlParams;
|
||||
}
|
||||
|
||||
function getDocumentData(urlParams) {
|
||||
return {
|
||||
key: urlParams["key"],
|
||||
url: urlParams["url"] || '_offline_',
|
||||
title: urlParams["title"],
|
||||
fileType: urlParams["filetype"],
|
||||
vkey: urlParams["vkey"],
|
||||
permissions: {
|
||||
edit: true,
|
||||
download: true,
|
||||
reader: true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getEditorConfig(urlParams) {
|
||||
return {
|
||||
mode : urlParams["mode"] || 'edit',
|
||||
lang : urlParams["lang"] || 'en',
|
||||
canCoAuthoring : true,
|
||||
createUrl : 'http://www.example.com/create',
|
||||
|
||||
user: {
|
||||
id: urlParams["userid"] || 'uid-901', firstname: urlParams["userfname"] || 'Mitchell', lastname: urlParams["userlname"] || 'Hamish'
|
||||
},
|
||||
recent : [
|
||||
{title: 'Memory.docx', url: 'http://onlyoffice.com', folder: 'Document Editor'},
|
||||
{title: 'Description.doc', url: 'http://onlyoffice.com', folder: 'Document Editor'},
|
||||
{title: 'DocEditor_right.xsl', url: 'http://onlyoffice.com', folder: 'Spreadsheet Editor'},
|
||||
{title: 'api.rtf', url: 'http://onlyoffice.com', folder: 'Unnamed folder'}
|
||||
],
|
||||
// templates : [
|
||||
// {name: 'Contracts', icon: '../../api/documents/resources/templates/contracts.png', url: 'http://...'},
|
||||
// {name: 'Letter', icon: '../../api/documents/resources/templates/letter.png', url: 'http://...'},
|
||||
// {name: 'List', icon: '../../api/documents/resources/templates/list.png', url: 'http://...'},
|
||||
// {name: 'Plan', icon: '../../api/documents/resources/templates/plan.png', url: 'http://...'}
|
||||
// ],
|
||||
embedded : {
|
||||
embedUrl : 'http://onlyoffice.com/embed',
|
||||
fullscreenUrl : 'http://onlyoffice.com/fullscreen',
|
||||
saveUrl : 'http://onlyoffice.com/download',
|
||||
shareUrl : 'http://tl.com/72b4la97',
|
||||
toolbarDocked : 'top'
|
||||
}
|
||||
,customization: {
|
||||
// logo: {
|
||||
// image: 'https://dylnrgbh910l3.cloudfront.net/studio/tag/i8.8.237/skins/default/images/onlyoffice_logo/editor_logo_general.png', // default size 86 x 20
|
||||
// imageEmbedded: 'https://d2hw9csky753gb.cloudfront.net/studio/tag/i8.8.237/skins/default/images/onlyoffice_logo/editor_embedded_logo.png', // default size 124 x 20
|
||||
// url: 'http://...'
|
||||
// },
|
||||
// backgroundColor: '#ffffff',
|
||||
// textColor: '#ff0000',
|
||||
// customer: {
|
||||
// name: 'SuperPuper',
|
||||
// address: 'New-York, 125f-25',
|
||||
// mail: 'support@gmail.com',
|
||||
// www: 'www.superpuper.com',
|
||||
// info: 'Some info',
|
||||
// logo: 'https://img.imgsmail.ru/r/default/portal/0.1.29/logo.png' // default size 216 x 35
|
||||
// },
|
||||
// goback: {text: 'Go To London', url: 'http://...'},
|
||||
about: true,
|
||||
feedback: true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Mobile version
|
||||
|
||||
function isMobile(){
|
||||
var prefixes = {
|
||||
ios: 'i(?:Pad|Phone|Pod)(?:.*)CPU(?: iPhone)? OS ',
|
||||
android: '(Android |HTC_|Silk/)',
|
||||
blackberry: 'BlackBerry(?:.*)Version\/',
|
||||
rimTablet: 'RIM Tablet OS ',
|
||||
webos: '(?:webOS|hpwOS)\/',
|
||||
bada: 'Bada\/'
|
||||
},
|
||||
i, prefix, match;
|
||||
|
||||
for (i in prefixes){
|
||||
if (prefixes.hasOwnProperty(i)) {
|
||||
prefix = prefixes[i];
|
||||
|
||||
if (navigator.userAgent.match(new RegExp('(?:'+prefix+')([^\\s;]+)')))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var fixSize = function() {
|
||||
var wrapEl = document.getElementById('wrap');
|
||||
if (wrapEl){
|
||||
wrapEl.style.height = screen.availHeight + 'px';
|
||||
window.scrollTo(0, -1);
|
||||
wrapEl.style.height = window.innerHeight + 'px';
|
||||
}
|
||||
};
|
||||
|
||||
var fixIpadLandscapeIos7 = function() {
|
||||
if (navigator.userAgent.match(/iPad;.*CPU.*OS 7_\d/i)) {
|
||||
var wrapEl = document.getElementById('wrap');
|
||||
if (wrapEl){
|
||||
wrapEl.style.position = "fixed";
|
||||
wrapEl.style.bottom = 0;
|
||||
wrapEl.style.width = "100%";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (isMobile()){
|
||||
window.addEventListener('load', fixSize);
|
||||
window.addEventListener('resize', fixSize);
|
||||
|
||||
fixIpadLandscapeIos7();
|
||||
}
|
||||
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
157
apps/api/documents/index.html.desktop
Normal file
157
apps/api/documents/index.html.desktop
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>ONLYOFFICE Documents</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=IE8"/>
|
||||
<meta name="description" content="" />
|
||||
<meta name="keywords" content="" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-touch-fullscreen" content="yes">
|
||||
|
||||
<style type="text/css">
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#wrap {
|
||||
position:absolute;
|
||||
left:0;
|
||||
top:0;
|
||||
right:0;
|
||||
bottom:0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrap">
|
||||
<div id="placeholder"></div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="api.js"></script>
|
||||
<script>
|
||||
(function() {
|
||||
|
||||
// Url parameters
|
||||
|
||||
var urlParams = getUrlParams(),
|
||||
cfg = getEditorConfig(urlParams),
|
||||
doc = getDocumentData(urlParams);
|
||||
|
||||
// Document Editor
|
||||
|
||||
var docEditor = new DocsAPI.DocEditor('placeholder', {
|
||||
type: urlParams['type'],
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
documentType: urlParams['doctype'] || 'text',
|
||||
document: doc,
|
||||
editorConfig: cfg
|
||||
});
|
||||
|
||||
|
||||
// helpers
|
||||
|
||||
function getUrlParams() {
|
||||
var e,
|
||||
a = /\+/g, // Regex for replacing addition symbol with a space
|
||||
r = /([^&=]+)=?([^&]*)/g,
|
||||
d = function (s) { return decodeURIComponent(s.replace(a, " ")); },
|
||||
q = window.location.search.substring(1),
|
||||
urlParams = {};
|
||||
|
||||
while (e = r.exec(q))
|
||||
urlParams[d(e[1])] = d(e[2]);
|
||||
|
||||
return urlParams;
|
||||
}
|
||||
|
||||
function getDocumentData(urlParams) {
|
||||
return {
|
||||
key: urlParams["key"],
|
||||
url: urlParams["url"] || '_offline_',
|
||||
title: urlParams["title"],
|
||||
fileType: urlParams["filetype"],
|
||||
vkey: urlParams["vkey"],
|
||||
permissions: {
|
||||
edit: true,
|
||||
download: true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getEditorConfig(urlParams) {
|
||||
return {
|
||||
mode : urlParams["mode"] || 'edit',
|
||||
lang : urlParams["lang"] || 'en',
|
||||
user: {
|
||||
id: urlParams["userid"], firstname: urlParams["userfname"], lastname: urlParams["userlname"]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Mobile version
|
||||
|
||||
function isMobile(){
|
||||
var prefixes = {
|
||||
ios: 'i(?:Pad|Phone|Pod)(?:.*)CPU(?: iPhone)? OS ',
|
||||
android: '(Android |HTC_|Silk/)',
|
||||
blackberry: 'BlackBerry(?:.*)Version\/',
|
||||
rimTablet: 'RIM Tablet OS ',
|
||||
webos: '(?:webOS|hpwOS)\/',
|
||||
bada: 'Bada\/'
|
||||
},
|
||||
i, prefix, match;
|
||||
|
||||
for (i in prefixes){
|
||||
if (prefixes.hasOwnProperty(i)) {
|
||||
prefix = prefixes[i];
|
||||
|
||||
if (navigator.userAgent.match(new RegExp('(?:'+prefix+')([^\\s;]+)')))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var fixSize = function() {
|
||||
var wrapEl = document.getElementById('wrap');
|
||||
if (wrapEl){
|
||||
wrapEl.style.height = screen.availHeight + 'px';
|
||||
window.scrollTo(0, -1);
|
||||
wrapEl.style.height = window.innerHeight + 'px';
|
||||
}
|
||||
};
|
||||
|
||||
var fixIpadLandscapeIos7 = function() {
|
||||
if (navigator.userAgent.match(/iPad;.*CPU.*OS 7_\d/i)) {
|
||||
var wrapEl = document.getElementById('wrap');
|
||||
if (wrapEl){
|
||||
wrapEl.style.position = "fixed";
|
||||
wrapEl.style.bottom = 0;
|
||||
wrapEl.style.width = "100%";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (isMobile()){
|
||||
window.addEventListener('load', fixSize);
|
||||
window.addEventListener('resize', fixSize);
|
||||
|
||||
fixIpadLandscapeIos7();
|
||||
}
|
||||
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
apps/api/documents/resources/templates/contracts.png
Normal file
BIN
apps/api/documents/resources/templates/contracts.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
BIN
apps/api/documents/resources/templates/letter.png
Normal file
BIN
apps/api/documents/resources/templates/letter.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
BIN
apps/api/documents/resources/templates/list.png
Normal file
BIN
apps/api/documents/resources/templates/list.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
BIN
apps/api/documents/resources/templates/plan.png
Normal file
BIN
apps/api/documents/resources/templates/plan.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
54
apps/common/Analytics.js
Normal file
54
apps/common/Analytics.js
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
Common.component = Common.component || {};
|
||||
|
||||
Common.Analytics = Common.component.Analytics = new(function() {
|
||||
var _category;
|
||||
|
||||
return {
|
||||
initialize: function(id, category) {
|
||||
|
||||
if (typeof id === 'undefined')
|
||||
throw 'Analytics: invalid id.';
|
||||
|
||||
if (typeof category === 'undefined' || Object.prototype.toString.apply(category) !== '[object String]')
|
||||
throw 'Analytics: invalid category type.';
|
||||
|
||||
_category = category;
|
||||
|
||||
$('head').append(
|
||||
'<script type="text/javascript">' +
|
||||
'var _gaq = _gaq || [];' +
|
||||
'_gaq.push(["_setAccount", "' + id + '"]);' +
|
||||
'_gaq.push(["_trackPageview"]);' +
|
||||
'(function() {' +
|
||||
'var ga = document.createElement("script"); ga.type = "text/javascript"; ga.async = true;' +
|
||||
'ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";' +
|
||||
'var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ga, s);' +
|
||||
'})();' +
|
||||
'</script>'
|
||||
);
|
||||
},
|
||||
|
||||
trackEvent: function(action, label, value) {
|
||||
|
||||
if (typeof action !== 'undefined' && Object.prototype.toString.apply(action) !== '[object String]')
|
||||
throw 'Analytics: invalid action type.';
|
||||
|
||||
if (typeof label !== 'undefined' && Object.prototype.toString.apply(label) !== '[object String]')
|
||||
throw 'Analytics: invalid label type.';
|
||||
|
||||
if (typeof value !== 'undefined' && !(Object.prototype.toString.apply(value) === '[object Number]' && isFinite(value)))
|
||||
throw 'Analytics: invalid value type.';
|
||||
|
||||
if (typeof _gaq === 'undefined')
|
||||
return;
|
||||
|
||||
if (_category === 'undefined')
|
||||
throw 'Analytics is not initialized.';
|
||||
|
||||
_gaq.push(['_trackEvent', _category, action, label, value]);
|
||||
}
|
||||
}
|
||||
})();
|
||||
203
apps/common/Gateway.js
Normal file
203
apps/common/Gateway.js
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
if (Common === undefined) {
|
||||
var Common = {};
|
||||
}
|
||||
|
||||
Common.Gateway = new(function() {
|
||||
var me = this,
|
||||
$me = $(me);
|
||||
|
||||
var commandMap = {
|
||||
'init': function(data) {
|
||||
$me.trigger('init', data);
|
||||
},
|
||||
|
||||
'openDocument': function(data) {
|
||||
$me.trigger('opendocument', data);
|
||||
},
|
||||
|
||||
'showMessage': function(data) {
|
||||
$me.trigger('showmessage', data);
|
||||
},
|
||||
|
||||
'applyEditRights': function(data) {
|
||||
$me.trigger('applyeditrights', data);
|
||||
},
|
||||
|
||||
'processSaveResult': function(data) {
|
||||
$me.trigger('processsaveresult', data);
|
||||
},
|
||||
|
||||
'processRightsChange': function(data) {
|
||||
$me.trigger('processrightschange', data);
|
||||
},
|
||||
|
||||
'refreshHistory': function(data) {
|
||||
$me.trigger('refreshhistory', data);
|
||||
},
|
||||
|
||||
'setHistoryData': function(data) {
|
||||
$me.trigger('sethistorydata', data);
|
||||
},
|
||||
|
||||
'setEmailAddresses': function(data) {
|
||||
$me.trigger('setemailaddresses', data);
|
||||
},
|
||||
|
||||
'processMailMerge': function(data) {
|
||||
$me.trigger('processmailmerge', data);
|
||||
},
|
||||
|
||||
'downloadAs': function() {
|
||||
$me.trigger('downloadas');
|
||||
},
|
||||
|
||||
'processMouse': function(data) {
|
||||
$me.trigger('processmouse', data);
|
||||
},
|
||||
|
||||
'internalCommand': function(data) {
|
||||
$me.trigger('internalcommand', data);
|
||||
},
|
||||
|
||||
'resetFocus': function(data) {
|
||||
$me.trigger('resetfocus', data);
|
||||
}
|
||||
};
|
||||
|
||||
var _postMessage = function(msg) {
|
||||
// TODO: specify explicit origin
|
||||
if (window.parent && window.JSON) {
|
||||
window.parent.postMessage(window.JSON.stringify(msg), "*");
|
||||
}
|
||||
};
|
||||
|
||||
var _onMessage = function(msg) {
|
||||
// TODO: check message origin
|
||||
var data = msg.data;
|
||||
if (Object.prototype.toString.apply(data) !== '[object String]' || !window.JSON) {
|
||||
return;
|
||||
}
|
||||
|
||||
var cmd, handler;
|
||||
|
||||
try {
|
||||
cmd = window.JSON.parse(data)
|
||||
} catch(e) {
|
||||
cmd = '';
|
||||
}
|
||||
|
||||
if (cmd) {
|
||||
handler = commandMap[cmd.command];
|
||||
if (handler) {
|
||||
handler.call(this, cmd.data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var fn = function(e) { _onMessage(e); };
|
||||
|
||||
if (window.attachEvent) {
|
||||
window.attachEvent('onmessage', fn);
|
||||
} else {
|
||||
window.addEventListener('message', fn, false);
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
ready: function() {
|
||||
_postMessage({ event: 'onReady' });
|
||||
},
|
||||
|
||||
save: function(url) {
|
||||
_postMessage({
|
||||
event: 'onSave',
|
||||
data: url
|
||||
});
|
||||
},
|
||||
|
||||
requestEditRights: function() {
|
||||
_postMessage({ event: 'onRequestEditRights' });
|
||||
},
|
||||
|
||||
requestHistory: function() {
|
||||
_postMessage({ event: 'onRequestHistory' });
|
||||
},
|
||||
|
||||
requestHistoryData: function(revision) {
|
||||
_postMessage({
|
||||
event: 'onRequestHistoryData',
|
||||
data: revision
|
||||
});
|
||||
},
|
||||
|
||||
requestEmailAddresses: function() {
|
||||
_postMessage({ event: 'onRequestEmailAddresses' });
|
||||
},
|
||||
|
||||
requestStartMailMerge: function() {
|
||||
_postMessage({event: 'onRequestStartMailMerge'});
|
||||
},
|
||||
|
||||
requestHistoryClose: function(revision) {
|
||||
_postMessage({event: 'onRequestHistoryClose'});
|
||||
},
|
||||
|
||||
reportError: function(code, description) {
|
||||
_postMessage({
|
||||
event: 'onError',
|
||||
data: {
|
||||
errorCode: code,
|
||||
errorDescription: description
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
sendInfo: function(info) {
|
||||
_postMessage({
|
||||
event: 'onInfo',
|
||||
data: info
|
||||
});
|
||||
},
|
||||
|
||||
setDocumentModified: function(modified) {
|
||||
_postMessage({
|
||||
event: 'onDocumentStateChange',
|
||||
data: modified
|
||||
});
|
||||
},
|
||||
|
||||
internalMessage: function(type, data) {
|
||||
_postMessage({
|
||||
event: 'onInternalMessage',
|
||||
data: {
|
||||
type: type,
|
||||
data: data
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateVersion: function() {
|
||||
_postMessage({ event: 'onOutdatedVersion' });
|
||||
},
|
||||
|
||||
downloadAs: function(url) {
|
||||
_postMessage({
|
||||
event: 'onDownloadAs',
|
||||
data: url
|
||||
});
|
||||
},
|
||||
|
||||
collaborativeChanges: function() {
|
||||
_postMessage({event: 'onCollaborativeChanges'});
|
||||
},
|
||||
|
||||
on: function(event, handler){
|
||||
var localHandler = function(event, data){
|
||||
handler.call(me, data)
|
||||
};
|
||||
|
||||
$me.on(event, localHandler);
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
56
apps/common/IrregularStack.js
Normal file
56
apps/common/IrregularStack.js
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
Common.IrregularStack = function(config) {
|
||||
|
||||
var _stack = [];
|
||||
|
||||
var _compare = function(obj1, obj2){
|
||||
if (typeof obj1 === 'object' && typeof obj2 === 'object' && window.JSON)
|
||||
return window.JSON.stringify(obj1) === window.JSON.stringify(obj2);
|
||||
return obj1 === obj2;
|
||||
}
|
||||
|
||||
config = config || {};
|
||||
var _strongCompare = config.strongCompare || _compare;
|
||||
var _weakCompare = config.weakCompare || _compare;
|
||||
|
||||
var _indexOf = function(obj, compare) {
|
||||
for (var i = _stack.length - 1; i >= 0; i--) {
|
||||
if (compare(_stack[i], obj))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
var _push = function(obj) {
|
||||
_stack.push(obj);
|
||||
}
|
||||
|
||||
var _pop = function(obj) {
|
||||
var index = _indexOf(obj, _strongCompare);
|
||||
if (index != -1) {
|
||||
var removed = _stack.splice(index, 1);
|
||||
return removed[0];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var _get = function(obj) {
|
||||
var index = _indexOf(obj, _weakCompare);
|
||||
if (index != -1)
|
||||
return _stack[index];
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var _exist = function(obj) {
|
||||
return !(_indexOf(obj, _strongCompare) < 0);
|
||||
}
|
||||
|
||||
return {
|
||||
push: _push,
|
||||
pop: _pop,
|
||||
get: _get,
|
||||
exist: _exist
|
||||
}
|
||||
};
|
||||
BIN
apps/common/embed/resources/img/glyphicons.png
Normal file
BIN
apps/common/embed/resources/img/glyphicons.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.8 KiB |
521
apps/common/embed/resources/less/common.less
Normal file
521
apps/common/embed/resources/less/common.less
Normal file
|
|
@ -0,0 +1,521 @@
|
|||
// Core variables and mixins
|
||||
@import "../../../../../vendor/bootstrap/less/variables.less";
|
||||
|
||||
@icon-font-path: "../../../../../vendor/bootstrap/dist/fonts/";
|
||||
|
||||
@import "../../../../../vendor/bootstrap/less/mixins.less";
|
||||
|
||||
// Reset
|
||||
@import "../../../../../vendor/bootstrap/less/normalize.less";
|
||||
@import "../../../../../vendor/bootstrap/less/print.less";
|
||||
|
||||
// Core CSS
|
||||
@import "../../../../../vendor/bootstrap/less/scaffolding.less";
|
||||
@import "../../../../../vendor/bootstrap/less/type.less";
|
||||
//@import "code.less";
|
||||
//@import "grid.less";
|
||||
//@import "tables.less";
|
||||
@import "../../../../../vendor/bootstrap/less/forms.less";
|
||||
@import "../../../../../vendor/bootstrap/less/buttons.less";
|
||||
|
||||
// Components
|
||||
@import "../../../../../vendor/bootstrap/less/component-animations.less";
|
||||
@import "../../../../../vendor/bootstrap/less/glyphicons.less";
|
||||
//@import "dropdowns.less";
|
||||
//@import "button-groups.less";
|
||||
//@import "input-groups.less";
|
||||
//@import "navs.less";
|
||||
//@import "navbar.less";
|
||||
//@import "breadcrumbs.less";
|
||||
//@import "pagination.less";
|
||||
//@import "pager.less";
|
||||
@import "../../../../../vendor/bootstrap/less/labels.less";
|
||||
//@import "badges.less";
|
||||
//@import "jumbotron.less";
|
||||
//@import "thumbnails.less";
|
||||
@import "../../../../../vendor/bootstrap/less/alerts.less";
|
||||
//@import "progress-bars.less";
|
||||
//@import "media.less";
|
||||
//@import "list-group.less";
|
||||
//@import "panels.less";
|
||||
//@import "wells.less";
|
||||
//@import "close.less";
|
||||
|
||||
// Components w/ JavaScript
|
||||
@import "../../../../../vendor/bootstrap/less/modals.less";
|
||||
@import "../../../../../vendor/bootstrap/less/tooltip.less";
|
||||
@import "../../../../../vendor/bootstrap/less/popovers.less";
|
||||
//@import "carousel.less";
|
||||
|
||||
// Utility classes
|
||||
@import "../../../../../vendor/bootstrap/less/utilities.less";
|
||||
@import "../../../../../vendor/bootstrap/less/responsive-utilities.less";
|
||||
|
||||
|
||||
@toolbarBorderColor: #929292;
|
||||
@toolbarBorderShadowColor: #FAFAFA;
|
||||
@toolbarTopColor: #EBEBEB;
|
||||
@toolbarBottomColor: #CCCCCC;
|
||||
@toolbarHoverColor: #7698DE;
|
||||
@toolbarFontSize: 12px;
|
||||
@controlBtnHoverTopColor: #6180C4;
|
||||
@controlBtnHoverBottomColor: #8AACF1;
|
||||
@iconSpriteCommonPath: "../../../../common/embed/resources/img/glyphicons.png";
|
||||
|
||||
.input-xs {
|
||||
.input-size(@input-height-small - 8px; @padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);
|
||||
}
|
||||
|
||||
.embed-body {
|
||||
-moz-user-select: -moz-none;
|
||||
-khtml-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
font-size: @toolbarFontSize;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
// Document Viewer
|
||||
// -------------------------
|
||||
.viewer {
|
||||
position: absolute;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
&.top {
|
||||
top: 32px;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
&.bottom {
|
||||
top: 0;
|
||||
bottom: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
// Toolbar
|
||||
// -------------------------
|
||||
.toolbar {
|
||||
position: fixed;
|
||||
font-size: @toolbarFontSize;
|
||||
min-width: 340px;
|
||||
z-index: 100;
|
||||
#gradient > .vertical(@toolbarTopColor, @toolbarBottomColor);
|
||||
|
||||
&.top {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
|
||||
-webkit-box-shadow: inset 0 -1px 0 @toolbarBorderColor, inset 0 1px 0 @toolbarBorderShadowColor;
|
||||
//-moz-box-shadow: inset 0 -1px 0 @toolbarBorderColor, inset 0 1px 0 @toolbarBorderShadowColor;
|
||||
box-shadow: inset 0 -1px 0 @toolbarBorderColor, inset 0 1px 0 @toolbarBorderShadowColor;
|
||||
}
|
||||
|
||||
&.bottom {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
|
||||
-webkit-box-shadow: inset 0 1px 0 @toolbarBorderColor, inset 0 2px 0 @toolbarBorderShadowColor;
|
||||
//-moz-box-shadow: inset 0 1px 0 @toolbarBorderColor, inset 0 2px 0 @toolbarBorderShadowColor;
|
||||
box-shadow: inset 0 1px 0 @toolbarBorderColor, inset 0 2px 0 @toolbarBorderShadowColor;
|
||||
}
|
||||
|
||||
ul {
|
||||
position: absolute;
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
input {
|
||||
display: inline-block;
|
||||
width: 25px;
|
||||
padding: 0;
|
||||
height: 25px;
|
||||
margin: 3px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
&.left {
|
||||
left: 0;
|
||||
|
||||
li {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
&.right {
|
||||
right: 0;
|
||||
|
||||
li {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
.separator {
|
||||
height: 24px;
|
||||
margin: 4px 9px;
|
||||
border-right: 1px solid @toolbarBorderShadowColor;
|
||||
border-left: 1px solid @toolbarBorderColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Logo
|
||||
// -------------------------
|
||||
a.brand-logo {
|
||||
display: block;
|
||||
background-image: url("@{iconSpriteCommonPath}");
|
||||
width: 124px;
|
||||
height: 20px;
|
||||
margin: 5px 0 0 10px;
|
||||
background-position: 0 -100px;
|
||||
}
|
||||
|
||||
// Sprite icons path
|
||||
// -------------------------
|
||||
[class^="control-icon-"],
|
||||
[class*=" control-icon-"] {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
vertical-align: text-top;
|
||||
background-image: url("@{iconSpriteCommonPath}");
|
||||
background-repeat: no-repeat;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
[class^="overlay-icon-"],
|
||||
[class*=" overlay-icon-"] {
|
||||
display: inline-block;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
vertical-align: text-top;
|
||||
background-image: url("@{iconSpriteCommonPath}");
|
||||
background-repeat: no-repeat;
|
||||
opacity: .3;
|
||||
}
|
||||
|
||||
.control-icon-share { background-position: 0 0; }
|
||||
.control-icon-embed { background-position: 0 -20px; }
|
||||
.control-icon-fullscreen { background-position: 0 -40px; }
|
||||
.control-icon-close { background-position: 0 -60px; }
|
||||
.control-icon-save { background-position: 0 -80px; }
|
||||
|
||||
.overlay-icon-zoom-in { background-position: 0 -120px; }
|
||||
.overlay-icon-zoom-out { background-position: -32px -120px; }
|
||||
|
||||
// Control buttons
|
||||
// -------------------------
|
||||
.control-btn {
|
||||
display: inline-block;
|
||||
padding: 1px 5px;
|
||||
font-size: @toolbarFontSize;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
background-image: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 2px;
|
||||
margin: 4px 5px 0 0;
|
||||
|
||||
i {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
&.no-caption {
|
||||
padding: 1px 2px;
|
||||
|
||||
i {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Hover state
|
||||
&:hover {
|
||||
color: @toolbarHoverColor;
|
||||
text-decoration: none;
|
||||
text-shadow: 0 1px 0 @toolbarBorderShadowColor;
|
||||
|
||||
.control-icon-share { background-position: -20px 0; }
|
||||
.control-icon-embed { background-position: -20px -20px; }
|
||||
.control-icon-fullscreen { background-position: -20px -40px; }
|
||||
.control-icon-close { background-position: -20px -60px; }
|
||||
.control-icon-save { background-position: -20px -80px; }
|
||||
}
|
||||
|
||||
// Focus state for keyboard and accessibility
|
||||
&:focus {
|
||||
.tab-focus();
|
||||
outline: none;
|
||||
}
|
||||
|
||||
// Active state
|
||||
&.active,
|
||||
&:active {
|
||||
color: #ffffff;
|
||||
outline: none;
|
||||
border: 1px solid darken(@controlBtnHoverTopColor, 5%);
|
||||
#gradient > .vertical(@controlBtnHoverTopColor, @controlBtnHoverBottomColor);
|
||||
text-shadow: 0 1px 0 darken(@toolbarBorderColor, 20%);
|
||||
|
||||
.control-icon-share { background-position: -40px 0; }
|
||||
.control-icon-embed { background-position: -40px -20px; }
|
||||
.control-icon-fullscreen { background-position: -40px -40px; }
|
||||
.control-icon-close { background-position: -40px -60px; }
|
||||
.control-icon-save { background-position: -40px -80px; }
|
||||
}
|
||||
}
|
||||
|
||||
// Overlay control
|
||||
// -------------------------
|
||||
.overlay-controls {
|
||||
position: absolute;
|
||||
bottom: 55px;
|
||||
z-index: 10;
|
||||
left: 50%;
|
||||
|
||||
ul {
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
margin: 0 auto;
|
||||
|
||||
li {
|
||||
display: inline-block;
|
||||
|
||||
&:first-child {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.overlay {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
background-image: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
line-height: 0;
|
||||
outline: none;
|
||||
|
||||
&:hover {
|
||||
[class^="overlay-icon-"],
|
||||
[class*=" overlay-icon-"] {
|
||||
opacity: .6;
|
||||
}
|
||||
}
|
||||
|
||||
&.active,
|
||||
&:active {
|
||||
[class^="overlay-icon-"],
|
||||
[class*=" overlay-icon-"] {
|
||||
opacity: .8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Error mask
|
||||
// -------------------------
|
||||
.errormask {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
background-color: #f4f4f4;
|
||||
z-index: 30002;
|
||||
|
||||
.error-body {
|
||||
position: relative;
|
||||
top: 40%;
|
||||
width: 400px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #FFFFFF;
|
||||
border: 1px solid #C0C0C0;
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
font-size: 1.6em;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Share popover
|
||||
// -------------------------
|
||||
.popover{
|
||||
.popover-content {
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
&.hyperlink {
|
||||
.popover-content {
|
||||
padding: 5px 10px;
|
||||
|
||||
p {
|
||||
display: block;
|
||||
word-wrap: break-word;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.share {
|
||||
width: 280px;
|
||||
|
||||
.share-link {
|
||||
margin-bottom: 5px;
|
||||
|
||||
.caption {
|
||||
margin-top: 3px;
|
||||
margin-right: 8px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
input[readonly] {
|
||||
display: inline-block;
|
||||
font-size: 1em;
|
||||
padding: 0 4px;
|
||||
margin-right: 5px;
|
||||
border-radius: 0;
|
||||
cursor: text;
|
||||
background-color: #fff;
|
||||
-moz-user-select: text;
|
||||
-khtml-user-select: text;
|
||||
-webkit-user-select: text;
|
||||
-ms-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.input-xs {
|
||||
width: 130px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.share-buttons {
|
||||
ul {
|
||||
width: 244px;
|
||||
height: 25px;
|
||||
list-style-type: none;
|
||||
margin: 5px 0 0;
|
||||
overflow: hidden;
|
||||
|
||||
li {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
margin: 1px 5px 0 0;
|
||||
vertical-align: middle;
|
||||
|
||||
&.share-mail {
|
||||
float: right;
|
||||
padding-right: 1px;
|
||||
margin: 0;
|
||||
|
||||
a {
|
||||
min-width: 64px;
|
||||
}
|
||||
|
||||
.glyphicon {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
&.share-twitter {
|
||||
max-width: 93px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.embed {
|
||||
width: 270px;
|
||||
|
||||
.size-manual {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.caption {
|
||||
margin-top: 2px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
input {
|
||||
display: inline-block;
|
||||
font-size: 1em;
|
||||
padding: 0 4px;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
margin-top: -1px;
|
||||
|
||||
&.input-xs {
|
||||
width: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 238px;
|
||||
resize: none;
|
||||
cursor: auto;
|
||||
font-size: 1em;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
float: right;
|
||||
margin: 10px 0 15px;
|
||||
width: 86px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modals
|
||||
// -------------------------
|
||||
.modal {
|
||||
.modal-header {
|
||||
padding: 5px 15px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
87
apps/common/locale.js
Normal file
87
apps/common/locale.js
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
if (Common === undefined) {
|
||||
var Common = {};
|
||||
}
|
||||
|
||||
Common.Locale = new(function() {
|
||||
var l10n = {};
|
||||
|
||||
var _createXMLHTTPObject = function() {
|
||||
var xmlhttp;
|
||||
try {
|
||||
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
|
||||
}
|
||||
catch (e) {
|
||||
try {
|
||||
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
catch (E) {
|
||||
xmlhttp = false;
|
||||
}
|
||||
}
|
||||
if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
|
||||
xmlhttp = new XMLHttpRequest();
|
||||
}
|
||||
return xmlhttp;
|
||||
};
|
||||
|
||||
var _applyLocalization = function() {
|
||||
try {
|
||||
for (var prop in l10n) {
|
||||
var p = prop.split('.');
|
||||
if (p && p.length > 2) {
|
||||
|
||||
var obj = window;
|
||||
for (var i = 0; i < p.length - 1; ++i) {
|
||||
if (obj[p[i]] === undefined) {
|
||||
obj[p[i]] = new Object();
|
||||
}
|
||||
obj = obj[p[i]];
|
||||
}
|
||||
|
||||
if (obj) {
|
||||
obj[p[p.length - 1]] = l10n[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
};
|
||||
|
||||
var _get = function(prop, scope) {
|
||||
var res = '';
|
||||
if (scope && scope.name) {
|
||||
res = l10n[scope.name + '.' + prop];
|
||||
}
|
||||
|
||||
return res || (scope ? eval(scope.name).prototype[prop] : '');
|
||||
};
|
||||
|
||||
var _getUrlParameterByName = function(name) {
|
||||
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
|
||||
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
|
||||
results = regex.exec(location.search);
|
||||
return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
|
||||
};
|
||||
|
||||
try {
|
||||
var langParam = _getUrlParameterByName('lang');
|
||||
var xhrObj = _createXMLHTTPObject();
|
||||
if (xhrObj && langParam) {
|
||||
var lang = langParam.split("-")[0];
|
||||
xhrObj.open('GET', 'locale/' + lang + '.json', false);
|
||||
xhrObj.send('');
|
||||
l10n = eval("(" + xhrObj.responseText + ")");
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
|
||||
return {
|
||||
apply: _applyLocalization,
|
||||
get: _get
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
|
||||
22
apps/common/main/lib/collection/ChatMessages.js
Normal file
22
apps/common/main/lib/collection/ChatMessages.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* ChatMessages.js
|
||||
*
|
||||
* Collection
|
||||
*
|
||||
* Created by Maxim Kadushkin on 01 March 2014
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
define([
|
||||
'backbone',
|
||||
'common/main/lib/model/ChatMessage'
|
||||
], function(Backbone){
|
||||
'use strict';
|
||||
|
||||
!Common.Collections && (Common.Collections = {});
|
||||
|
||||
Common.Collections.ChatMessages = Backbone.Collection.extend({
|
||||
model: Common.Models.ChatMessage
|
||||
});
|
||||
});
|
||||
48
apps/common/main/lib/collection/Comments.js
Normal file
48
apps/common/main/lib/collection/Comments.js
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* Comments.js
|
||||
*
|
||||
* Created by Alexey Musinov on 17.01.14
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
Common.Collections = Common.Collections || {};
|
||||
|
||||
define([
|
||||
'underscore',
|
||||
'backbone',
|
||||
'common/main/lib/model/Comment'
|
||||
], function(_, Backbone){
|
||||
'use strict';
|
||||
|
||||
Common.Collections.Comments = Backbone.Collection.extend({
|
||||
model: Common.Models.Comment,
|
||||
|
||||
clearEditing: function () {
|
||||
this.each(function(comment) {
|
||||
comment.set('editText', false);
|
||||
comment.set('editTextInPopover', false);
|
||||
comment.set('showReply', false);
|
||||
comment.set('showReplyInPopover', false);
|
||||
comment.set('hideAddReply', false);
|
||||
});
|
||||
},
|
||||
|
||||
getCommentsReplysCount: function(userid) {
|
||||
var cnt = 0;
|
||||
this.each(function(comment) {
|
||||
if (comment.get('userid')==userid) cnt++;
|
||||
var rpl = comment.get('replys');
|
||||
if (rpl && rpl.length>0) {
|
||||
rpl.forEach(function(reply) {
|
||||
if (reply.get('userid')==userid) cnt ++;
|
||||
});
|
||||
}
|
||||
});
|
||||
return cnt;
|
||||
}
|
||||
});
|
||||
});
|
||||
27
apps/common/main/lib/collection/Fonts.js
Normal file
27
apps/common/main/lib/collection/Fonts.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* Fonts.js
|
||||
*
|
||||
* Created by Alexander Yuzhin on 2/11/14
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
Common.Collections = Common.Collections || {};
|
||||
|
||||
define([
|
||||
'backbone',
|
||||
'common/main/lib/model/Font'
|
||||
], function(Backbone){ 'use strict';
|
||||
Common.Collections.Fonts = Backbone.Collection.extend({
|
||||
model: Common.Models.Font,
|
||||
comparator: function(item1, item2) {
|
||||
var n1 = item1.get('name').toLowerCase(),
|
||||
n2 = item2.get('name').toLowerCase();
|
||||
if (n1==n2) return 0;
|
||||
return (n1<n2) ? -1 : 1;
|
||||
}
|
||||
});
|
||||
});
|
||||
30
apps/common/main/lib/collection/HistoryVersions.js
Normal file
30
apps/common/main/lib/collection/HistoryVersions.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* User: Julia.Radzhabova
|
||||
* Date: 05.03.15
|
||||
* Time: 17:05
|
||||
*/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
Common.Collections = Common.Collections || {};
|
||||
|
||||
define([
|
||||
'underscore',
|
||||
'backbone',
|
||||
'common/main/lib/model/HistoryVersion'
|
||||
], function(_, Backbone){
|
||||
'use strict';
|
||||
|
||||
Common.Collections.HistoryVersions = Backbone.Collection.extend({
|
||||
model: Common.Models.HistoryVersion,
|
||||
|
||||
findRevision: function(revision) {
|
||||
return this.findWhere({revision: revision});
|
||||
},
|
||||
|
||||
findRevisions: function(revision) {
|
||||
return this.where({revision: revision});
|
||||
}
|
||||
});
|
||||
});
|
||||
24
apps/common/main/lib/collection/ReviewChanges.js
Normal file
24
apps/common/main/lib/collection/ReviewChanges.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* ReviewChanges.js
|
||||
*
|
||||
* Created by Julia.Radzhabova on 05.08.15
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
Common.Collections = Common.Collections || {};
|
||||
|
||||
define([
|
||||
'underscore',
|
||||
'backbone',
|
||||
'common/main/lib/model/ReviewChange'
|
||||
], function(_, Backbone){
|
||||
'use strict';
|
||||
|
||||
Common.Collections.ReviewChanges = Backbone.Collection.extend({
|
||||
model: Common.Models.ReviewChange
|
||||
});
|
||||
});
|
||||
28
apps/common/main/lib/collection/TextArt.js
Normal file
28
apps/common/main/lib/collection/TextArt.js
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* Created by Julia.Radzhabova on 09.07.15
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
Common.Collections = Common.Collections || {};
|
||||
|
||||
define([
|
||||
'backbone'
|
||||
], function(Backbone){
|
||||
'use strict';
|
||||
|
||||
Common.Collections.TextArt = Backbone.Collection.extend({
|
||||
model: Backbone.Model.extend({
|
||||
defaults: function() {
|
||||
return {
|
||||
id: Common.UI.getId(),
|
||||
imageUrl: null,
|
||||
data: null
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
49
apps/common/main/lib/collection/Users.js
Normal file
49
apps/common/main/lib/collection/Users.js
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* Users.js
|
||||
*
|
||||
* Collection
|
||||
*
|
||||
* Created by Maxim Kadushkin on 27 February 2014
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
define([
|
||||
'backbone',
|
||||
'common/main/lib/model/User'
|
||||
], function(Backbone){
|
||||
'use strict';
|
||||
|
||||
Common.Collections = Common.Collections || {};
|
||||
|
||||
Common.Collections.Users = Backbone.Collection.extend({
|
||||
model: Common.Models.User,
|
||||
|
||||
getOnlineCount: function() {
|
||||
var count = 0;
|
||||
this.each(function(user){
|
||||
user.online && count++;
|
||||
});
|
||||
|
||||
return count;
|
||||
},
|
||||
|
||||
findUser: function(id) {
|
||||
return this.find(
|
||||
function(model){
|
||||
return model.get('id') == id;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Common.Collections.HistoryUsers = Backbone.Collection.extend({
|
||||
model: Common.Models.User,
|
||||
|
||||
findUser: function(id) {
|
||||
return this.find(
|
||||
function(model){
|
||||
return model.get('id') == id;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
83
apps/common/main/lib/component/BaseView.js
Normal file
83
apps/common/main/lib/component/BaseView.js
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/**
|
||||
* BaseView.js
|
||||
*
|
||||
* Created by Alexander Yuzhin on 1/17/14
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
define([
|
||||
'backbone'
|
||||
], function (Backbone) {
|
||||
'use strict';
|
||||
|
||||
Common.UI = _.extend(Common.UI || {}, {
|
||||
Keys : {
|
||||
BACKSPACE: 8,
|
||||
TAB: 9,
|
||||
RETURN: 13,
|
||||
SHIFT: 16,
|
||||
CTRL: 17,
|
||||
ALT: 18,
|
||||
ESC: 27,
|
||||
LEFT: 37,
|
||||
UP: 38,
|
||||
RIGHT: 39,
|
||||
DOWN: 40,
|
||||
DELETE: 46,
|
||||
HOME: 36,
|
||||
END: 35,
|
||||
SPACE: 32,
|
||||
PAGEUP: 33,
|
||||
PAGEDOWN: 34,
|
||||
INSERT: 45,
|
||||
NUM_PLUS: 107,
|
||||
NUM_MINUS: 109,
|
||||
F1: 112,
|
||||
F2: 113,
|
||||
F3: 114,
|
||||
F4: 115,
|
||||
F5: 116,
|
||||
F6: 117,
|
||||
F7: 118,
|
||||
F8: 119,
|
||||
F9: 120,
|
||||
F10: 121,
|
||||
F11: 122,
|
||||
F12: 123,
|
||||
EQUALITY: 187,
|
||||
MINUS: 189
|
||||
},
|
||||
|
||||
BaseView: Backbone.View.extend({
|
||||
isSuspendEvents: false,
|
||||
|
||||
initialize : function(options) {
|
||||
this.options = this.options ? _({}).extend(this.options, options) : options;
|
||||
},
|
||||
|
||||
setVisible: function(visible) {
|
||||
return this[visible ? 'show': 'hide']();
|
||||
},
|
||||
|
||||
isVisible: function() {
|
||||
return $(this.el).is(":visible");
|
||||
},
|
||||
|
||||
suspendEvents: function() {
|
||||
this.isSuspendEvents = true;
|
||||
},
|
||||
|
||||
resumeEvents: function() {
|
||||
this.isSuspendEvents = false;
|
||||
}
|
||||
}),
|
||||
|
||||
getId: function(prefix) {
|
||||
return _.uniqueId(prefix || "asc-gen");
|
||||
}
|
||||
});
|
||||
});
|
||||
463
apps/common/main/lib/component/Button.js
Normal file
463
apps/common/main/lib/component/Button.js
Normal file
|
|
@ -0,0 +1,463 @@
|
|||
/**
|
||||
* Button.js
|
||||
*
|
||||
* Created by Alexander Yuzhin on 1/20/14
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Using template
|
||||
*
|
||||
* A simple button with text:
|
||||
* <button type="button" class="btn" id="id-button">Caption</button>
|
||||
*
|
||||
* A simple button with icon:
|
||||
* <button type="button" class="btn" id="id-button"><span class="btn-icon"> </span></button>
|
||||
*
|
||||
* A button with menu:
|
||||
* <div class="btn-group" id="id-button">
|
||||
* <button type="button" class="btn dropdown-toggle" data-toggle="dropdown">
|
||||
* <span class="btn-icon"> </span>
|
||||
* <span class="caret"></span>
|
||||
* </button>
|
||||
* <ul class="dropdown-menu" role="menu">
|
||||
* </ul>
|
||||
* </div>
|
||||
*
|
||||
* A split button:
|
||||
* <div class="btn-group split" id="id-button">
|
||||
* <button type="button" class="btn"><span class="btn-icon"> </span></button>
|
||||
* <button type="button" class="btn dropdown-toggle" data-toggle="dropdown">
|
||||
* <span class="caret"></span>
|
||||
* <span class="sr-only"></span>
|
||||
* </button>
|
||||
* <ul class="dropdown-menu" role="menu">
|
||||
* </ul>
|
||||
* </div>
|
||||
*
|
||||
* A useful classes of button size
|
||||
*
|
||||
* - `'small'`
|
||||
* - `'normal'`
|
||||
* - `'large'`
|
||||
* - `'huge'`
|
||||
*
|
||||
* A useful classes of button type
|
||||
*
|
||||
* - `'default'`
|
||||
* - `'active'`
|
||||
*
|
||||
*
|
||||
* Buttons can also be toggled. To enable this, you simple set the {@link #enableToggle} property to `true`.
|
||||
*
|
||||
* Example usage:
|
||||
* new Common.UI.Button({
|
||||
* el: $('#id'),
|
||||
* enableToggle: true
|
||||
* });
|
||||
*
|
||||
*
|
||||
* @property {Boolean} disabled
|
||||
* True if this button is disabled. Read-only.
|
||||
*
|
||||
* disabled: false,
|
||||
*
|
||||
*
|
||||
* @property {Boolean} pressed
|
||||
* True if this button is pressed (only if enableToggle = true). Read-only.
|
||||
*
|
||||
* pressed: false,
|
||||
*
|
||||
*
|
||||
* @cfg {Boolean} [allowDepress=true]
|
||||
* False to not allow a pressed Button to be depressed. Only valid when {@link #enableToggle} is true.
|
||||
*
|
||||
* @cfg {String/Object} hint
|
||||
* The tooltip for the button - can be a string to be used as bootstrap tooltip
|
||||
*
|
||||
*/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
define([
|
||||
'common/main/lib/component/BaseView',
|
||||
'common/main/lib/component/ToggleManager'
|
||||
], function () {
|
||||
'use strict';
|
||||
|
||||
Common.UI.Button = Common.UI.BaseView.extend({
|
||||
options : {
|
||||
id : null,
|
||||
hint : false,
|
||||
enableToggle : false,
|
||||
allowDepress : true,
|
||||
toggleGroup : null,
|
||||
cls : '',
|
||||
iconCls : '',
|
||||
caption : '',
|
||||
menu : null,
|
||||
disabled : false,
|
||||
pressed : false,
|
||||
split : false
|
||||
},
|
||||
|
||||
template: _.template([
|
||||
'<% if (menu == null) { %>',
|
||||
'<button type="button" class="btn <%= cls %>" id="<%= id %>" style="<%= style %>">',
|
||||
'<span class="caption"><%= caption %></span>',
|
||||
'<% if (iconCls != "") { %>',
|
||||
'<span class="btn-icon <%= iconCls %>"> </span>',
|
||||
'<% } %>',
|
||||
'</button>',
|
||||
'<% } else if (split == false) {%>',
|
||||
'<div class="btn-group" id="<%= id %>" style="<%= style %>">',
|
||||
'<button type="button" class="btn dropdown-toggle <%= cls %>" data-toggle="dropdown">',
|
||||
'<span class="caption"><%= caption %></span>',
|
||||
'<% if (iconCls != "") { %>',
|
||||
'<span class="btn-icon <%= iconCls %>"> </span>',
|
||||
'<% } %>',
|
||||
'<span class="caret img-commonctrl"></span>',
|
||||
'</button>',
|
||||
'</div>',
|
||||
'<% } else { %>',
|
||||
'<div class="btn-group split" id="<%= id %>" style="<%= style %>">',
|
||||
'<button type="button" class="btn <%= cls %>">',
|
||||
'<span class="caption"><%= caption %></span>',
|
||||
'<% if (iconCls != "") { %>',
|
||||
'<span class="btn-icon <%= iconCls %>"> </span>',
|
||||
'<% } %>',
|
||||
'</button>',
|
||||
'<button type="button" class="btn <%= cls %> dropdown-toggle" data-toggle="dropdown">',
|
||||
'<span class="caret img-commonctrl"></span>',
|
||||
'<span class="sr-only"></span>',
|
||||
'</button>',
|
||||
'</div>',
|
||||
'<% } %>'
|
||||
].join('')),
|
||||
|
||||
initialize : function(options) {
|
||||
Common.UI.BaseView.prototype.initialize.call(this, options);
|
||||
|
||||
var me = this;
|
||||
|
||||
me.id = me.options.id || Common.UI.getId();
|
||||
me.hint = me.options.hint;
|
||||
me.enableToggle = me.options.enableToggle;
|
||||
me.allowDepress = me.options.allowDepress;
|
||||
me.cls = me.options.cls;
|
||||
me.iconCls = me.options.iconCls;
|
||||
me.menu = me.options.menu;
|
||||
me.split = me.options.split;
|
||||
me.toggleGroup = me.options.toggleGroup;
|
||||
me.disabled = me.options.disabled;
|
||||
me.pressed = me.options.pressed;
|
||||
me.caption = me.options.caption;
|
||||
me.template = me.options.template || me.template;
|
||||
me.style = me.options.style;
|
||||
me.rendered = false;
|
||||
|
||||
if (me.options.el) {
|
||||
me.render();
|
||||
}
|
||||
},
|
||||
|
||||
render: function(parentEl) {
|
||||
var me = this;
|
||||
|
||||
me.trigger('render:before', me);
|
||||
|
||||
me.cmpEl = $(me.el);
|
||||
|
||||
if (parentEl) {
|
||||
me.setElement(parentEl, false);
|
||||
|
||||
if (!me.rendered) {
|
||||
me.cmpEl = $(this.template({
|
||||
id : me.id,
|
||||
cls : me.cls,
|
||||
iconCls : me.iconCls,
|
||||
menu : me.menu,
|
||||
split : me.split,
|
||||
disabled : me.disabled,
|
||||
pressed : me.pressed,
|
||||
caption : me.caption,
|
||||
style : me.style
|
||||
}));
|
||||
|
||||
if (me.menu && _.isFunction(me.menu.render))
|
||||
me.menu.render(me.cmpEl);
|
||||
|
||||
parentEl.html(me.cmpEl);
|
||||
}
|
||||
}
|
||||
|
||||
if (!me.rendered) {
|
||||
var el = me.cmpEl,
|
||||
isGroup = el.hasClass('btn-group'),
|
||||
isSplit = el.hasClass('split');
|
||||
|
||||
if (me.options.hint) {
|
||||
var modalParents = me.cmpEl.closest('.asc-window');
|
||||
|
||||
me.cmpEl.attr('data-toggle', 'tooltip');
|
||||
me.cmpEl.tooltip({
|
||||
title : me.options.hint,
|
||||
placement : me.options.hintAnchor||'cursor'
|
||||
});
|
||||
|
||||
if (modalParents.length > 0) {
|
||||
me.cmpEl.data('bs.tooltip').tip().css('z-index', parseInt(modalParents.css('z-index')) + 10);
|
||||
}
|
||||
}
|
||||
|
||||
if (_.isString(me.toggleGroup)) {
|
||||
me.enableToggle = true;
|
||||
}
|
||||
|
||||
var buttonHandler = function(e) {
|
||||
if (!me.disabled && e.which == 1) {
|
||||
me.doToggle();
|
||||
if (me.options.hint) {
|
||||
var tip = me.cmpEl.data('bs.tooltip');
|
||||
if (tip) {
|
||||
if (tip.dontShow===undefined)
|
||||
tip.dontShow = true;
|
||||
|
||||
tip.hide();
|
||||
}
|
||||
}
|
||||
me.trigger('click', me, e);
|
||||
}
|
||||
};
|
||||
|
||||
var doSplitSelect = function(select, e) {
|
||||
if (!select) {
|
||||
// Is mouse under button
|
||||
var isUnderMouse = false;
|
||||
|
||||
_.each($('button', el), function(el){
|
||||
if ($(el).is(':hover')) {
|
||||
isUnderMouse = true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (!isUnderMouse) {
|
||||
el.removeClass('over');
|
||||
$('button', el).removeClass('over');
|
||||
}
|
||||
}
|
||||
|
||||
if (!select && (me.enableToggle && me.allowDepress && me.pressed))
|
||||
return;
|
||||
if (select && !isSplit && (me.enableToggle && me.allowDepress && !me.pressed)) { // to depress button with menu
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
$('button:first', el).toggleClass('active', select);
|
||||
$('[data-toggle^=dropdown]', el).toggleClass('active', select);
|
||||
el.toggleClass('active', select);
|
||||
};
|
||||
|
||||
var menuHandler = function(e) {
|
||||
if (!me.disabled && e.which == 1) {
|
||||
if (isSplit) {
|
||||
if (me.options.hint) {
|
||||
var tip = me.cmpEl.data('bs.tooltip');
|
||||
if (tip) {
|
||||
if (tip.dontShow===undefined)
|
||||
tip.dontShow = true;
|
||||
|
||||
tip.hide();
|
||||
}
|
||||
}
|
||||
var isOpen = el.hasClass('open');
|
||||
doSplitSelect(!isOpen, e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var doSetActiveState = function(e, state) {
|
||||
if (isSplit) {
|
||||
doSplitSelect(state, e);
|
||||
} else {
|
||||
el.toggleClass('active', state);
|
||||
$('button', el).toggleClass('active', state);
|
||||
}
|
||||
};
|
||||
|
||||
var onMouseDown = function (e) {
|
||||
doSplitSelect(true, e);
|
||||
$(document).on('mouseup', onMouseUp);
|
||||
};
|
||||
|
||||
var onMouseUp = function (e) {
|
||||
doSplitSelect(false, e);
|
||||
$(document).off('mouseup', onMouseUp);
|
||||
};
|
||||
|
||||
var onAfterHideMenu = function(e) {
|
||||
me.cmpEl.find('.dropdown-toggle').blur();
|
||||
if (me.cmpEl.hasClass('active') !== me.pressed)
|
||||
me.cmpEl.trigger('button.internal.active', [me.pressed]);
|
||||
};
|
||||
|
||||
if (isGroup) {
|
||||
if (isSplit) {
|
||||
$('[data-toggle^=dropdown]', el).on('mousedown', _.bind(menuHandler, this));
|
||||
$('button', el).on('mousedown', _.bind(onMouseDown, this));
|
||||
}
|
||||
|
||||
el.on('hide.bs.dropdown', _.bind(doSplitSelect, me, false));
|
||||
el.on('show.bs.dropdown', _.bind(doSplitSelect, me, true));
|
||||
el.on('hidden.bs.dropdown', _.bind(onAfterHideMenu, me));
|
||||
|
||||
$('button:first', el).on('click', buttonHandler);
|
||||
} else {
|
||||
el.on('click', buttonHandler);
|
||||
}
|
||||
|
||||
el.on('button.internal.active', _.bind(doSetActiveState, me));
|
||||
|
||||
el.on('mouseover', function(e) {
|
||||
if (!me.disabled) {
|
||||
me.cmpEl.addClass('over');
|
||||
me.trigger('mouseover', me, e);
|
||||
}
|
||||
});
|
||||
|
||||
el.on('mouseout', function(e) {
|
||||
if (!me.disabled) {
|
||||
me.cmpEl.removeClass('over');
|
||||
me.trigger('mouseout', me, e);
|
||||
}
|
||||
});
|
||||
|
||||
// Register the button in the toggle manager
|
||||
Common.UI.ToggleManager.register(me);
|
||||
}
|
||||
|
||||
me.rendered = true;
|
||||
|
||||
if (me.pressed) {
|
||||
me.toggle(me.pressed, true);
|
||||
}
|
||||
|
||||
if (me.disabled) {
|
||||
me.setDisabled(me.disabled);
|
||||
}
|
||||
|
||||
me.trigger('render:after', me);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
doToggle: function(){
|
||||
var me = this;
|
||||
if (me.enableToggle && (me.allowDepress !== false || !me.pressed)) {
|
||||
me.toggle();
|
||||
}
|
||||
},
|
||||
|
||||
toggle: function(toggle, suppressEvent) {
|
||||
var state = toggle === undefined ? !this.pressed : !!toggle;
|
||||
|
||||
this.pressed = state;
|
||||
|
||||
if (this.cmpEl)
|
||||
this.cmpEl.trigger('button.internal.active', [state]);
|
||||
|
||||
if (!suppressEvent)
|
||||
this.trigger('toggle', this, state);
|
||||
},
|
||||
|
||||
isActive: function() {
|
||||
if (this.enableToggle)
|
||||
return this.pressed;
|
||||
|
||||
return this.cmpEl.hasClass('active')
|
||||
},
|
||||
|
||||
setDisabled: function(disabled) {
|
||||
if (this.rendered) {
|
||||
var el = this.cmpEl,
|
||||
isGroup = el.hasClass('btn-group');
|
||||
|
||||
disabled = (disabled===true);
|
||||
|
||||
if (disabled !== el.hasClass('disabled')) {
|
||||
var decorateBtn = function(button) {
|
||||
button.toggleClass('disabled', disabled);
|
||||
(disabled) ? button.attr({disabled: disabled}) : button.removeAttr('disabled');
|
||||
};
|
||||
|
||||
decorateBtn(el);
|
||||
isGroup && decorateBtn(el.children('button'));
|
||||
}
|
||||
|
||||
if (disabled) {
|
||||
var tip = this.cmpEl.data('bs.tooltip');
|
||||
if (tip) {
|
||||
tip.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.disabled = disabled;
|
||||
},
|
||||
|
||||
isDisabled: function() {
|
||||
return this.disabled;
|
||||
},
|
||||
|
||||
setIconCls: function(cls) {
|
||||
var btnIconEl = $(this.el).find('span.btn-icon'),
|
||||
oldCls = this.iconCls;
|
||||
|
||||
this.iconCls = cls;
|
||||
btnIconEl.removeClass(oldCls);
|
||||
btnIconEl.addClass(cls || '');
|
||||
},
|
||||
|
||||
setVisible: function(visible) {
|
||||
if (this.cmpEl) this.cmpEl.toggleClass('hidden', !visible);
|
||||
},
|
||||
|
||||
updateHint: function(hint) {
|
||||
this.options.hint = hint;
|
||||
|
||||
var cmpEl = this.cmpEl,
|
||||
modalParents = cmpEl.closest('.asc-window');
|
||||
|
||||
cmpEl.attr('data-toggle', 'tooltip');
|
||||
cmpEl.tooltip('destroy').tooltip({
|
||||
title : hint,
|
||||
placement : this.options.hintAnchor || 'cursor'
|
||||
});
|
||||
|
||||
if (modalParents.length > 0) {
|
||||
cmpEl.data('bs.tooltip').tip().css('z-index', parseInt(modalParents.css('z-index')) + 10);
|
||||
}
|
||||
},
|
||||
|
||||
setCaption: function(caption) {
|
||||
if (this.caption != caption) {
|
||||
this.caption = caption;
|
||||
|
||||
if (this.rendered) {
|
||||
var captionNode = this.cmpEl.find('button:first > .caption').andSelf().filter('button > .caption');
|
||||
|
||||
if (captionNode.length > 0) {
|
||||
captionNode.text(caption);
|
||||
} else {
|
||||
this.cmpEl.find('button:first').andSelf().filter('button').text(caption);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
156
apps/common/main/lib/component/CheckBox.js
Normal file
156
apps/common/main/lib/component/CheckBox.js
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
/**
|
||||
* CheckBox.js
|
||||
*
|
||||
* Created by Julia Radzhabova on 1/24/14
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
|
||||
* Checkboxes may be given an optional {@link #labelText} which will be displayed immediately after checkbox.
|
||||
*
|
||||
* Example usage:
|
||||
* new Common.UI.CheckBox({
|
||||
* el : $('#id'),
|
||||
* labelText : 'someText',
|
||||
* value : true
|
||||
* });
|
||||
*
|
||||
* # Values
|
||||
*
|
||||
* The main value of a checkbox is a boolean, indicating whether or not the checkbox is checked.
|
||||
* To check the checkbox use setValue(...) function with parameters:
|
||||
*
|
||||
* - `true`
|
||||
* - `'true'`
|
||||
* - `'1'`
|
||||
* - `1`
|
||||
* - 'checked'
|
||||
*
|
||||
* Checkbox can be in indeterminate state. Use setValue('indeterminate').
|
||||
*
|
||||
* Any other value will uncheck the checkbox.
|
||||
*
|
||||
* To get the checkbox state use getValue() function. It can return 'checked' / 'unchecked' / 'indeterminate'.
|
||||
*
|
||||
* @property {Boolean} disabled
|
||||
* True if this checkbox is disabled.
|
||||
*
|
||||
* disabled: false,
|
||||
*
|
||||
* **/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
define([
|
||||
'common/main/lib/component/BaseView',
|
||||
'underscore'
|
||||
], function (base, _) {
|
||||
'use strict';
|
||||
|
||||
Common.UI.CheckBox = Common.UI.BaseView.extend({
|
||||
|
||||
options : {
|
||||
labelText: ''
|
||||
},
|
||||
|
||||
disabled : false,
|
||||
rendered : false,
|
||||
indeterminate: false,
|
||||
checked : false,
|
||||
value : 'unchecked',
|
||||
|
||||
template : _.template('<label class="checkbox-indeterminate"><input type="button" class="img-commonctrl"><span><%= labelText %></span></label>'),
|
||||
|
||||
initialize : function(options) {
|
||||
Common.UI.BaseView.prototype.initialize.call(this, options);
|
||||
|
||||
var me = this,
|
||||
el = $(this.el);
|
||||
|
||||
this.render();
|
||||
|
||||
if (this.options.disabled)
|
||||
this.setDisabled(this.options.disabled);
|
||||
|
||||
if (this.options.value!==undefined)
|
||||
this.setValue(this.options.value, true);
|
||||
|
||||
// handle events
|
||||
this.$chk.on('click', _.bind(this.onItemCheck, this));
|
||||
},
|
||||
|
||||
render: function () {
|
||||
var el = $(this.el);
|
||||
el.html(this.template({
|
||||
labelText: this.options.labelText
|
||||
}));
|
||||
|
||||
this.$chk = el.find('input[type=button]');
|
||||
this.$label = el.find('label');
|
||||
|
||||
this.rendered = true;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
setDisabled: function(disabled) {
|
||||
if (disabled !== this.disabled) {
|
||||
this.$label.toggleClass('disabled', disabled);
|
||||
(disabled) ? this.$chk.attr({disabled: disabled}) : this.$chk.removeAttr('disabled');
|
||||
}
|
||||
|
||||
this.disabled = disabled;
|
||||
},
|
||||
|
||||
isDisabled: function() {
|
||||
return this.disabled;
|
||||
},
|
||||
|
||||
onItemCheck: function (e) {
|
||||
if (!this.disabled) {
|
||||
if (this.indeterminate){
|
||||
this.indeterminate = false;
|
||||
this.setValue(false);
|
||||
} else {
|
||||
this.setValue(!this.checked);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setRawValue: function(value) {
|
||||
this.checked = (value === true || value === 'true' || value === '1' || value === 1 || value === 'checked');
|
||||
this.indeterminate = (value === 'indeterminate');
|
||||
|
||||
this.$chk.toggleClass('checked', this.checked);
|
||||
this.$chk.toggleClass('indeterminate', this.indeterminate);
|
||||
|
||||
this.value = this.indeterminate ? 'indeterminate' : (this.checked ? 'checked' : 'unchecked');
|
||||
},
|
||||
|
||||
setValue: function(value, suspendchange) {
|
||||
if (this.rendered) {
|
||||
this.lastValue = this.value;
|
||||
this.setRawValue(value);
|
||||
if (suspendchange !== true && this.lastValue !== value)
|
||||
this.trigger('change', this, this.value, this.lastValue);
|
||||
} else {
|
||||
this.options.value = value;
|
||||
}
|
||||
},
|
||||
|
||||
getValue: function() {
|
||||
return this.value;
|
||||
},
|
||||
|
||||
isChecked: function () {
|
||||
return this.checked;
|
||||
},
|
||||
|
||||
setCaption: function(text) {
|
||||
this.$label.find('span').text(text);
|
||||
}
|
||||
});
|
||||
});
|
||||
40
apps/common/main/lib/component/ColorButton.js
Normal file
40
apps/common/main/lib/component/ColorButton.js
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
define([
|
||||
'common/main/lib/component/Button'
|
||||
], function () {
|
||||
'use strict';
|
||||
|
||||
Common.UI.ColorButton = Common.UI.Button.extend({
|
||||
options : {
|
||||
hint: false,
|
||||
enableToggle: false
|
||||
},
|
||||
|
||||
template: _.template([
|
||||
'<div class="btn-group" id="<%= id %>">',
|
||||
'<button type="button" class="btn btn-color dropdown-toggle <%= cls %>" data-toggle="dropdown" style="<%= style %>">',
|
||||
'<span> </span>',
|
||||
'</button>',
|
||||
'</div>'
|
||||
].join('')),
|
||||
|
||||
setColor: function(color) {
|
||||
var border_color, clr,
|
||||
span = $(this.cmpEl).find('button span');
|
||||
this.color = color;
|
||||
|
||||
if ( color== 'transparent' ) {
|
||||
border_color = '#BEBEBE';
|
||||
clr = color;
|
||||
span.addClass('color-transparent');
|
||||
} else {
|
||||
border_color = 'transparent';
|
||||
clr = (typeof(color) == 'object') ? '#'+color.color : '#'+color;
|
||||
span.removeClass('color-transparent');
|
||||
}
|
||||
span.css({'background-color': clr, 'border-color': border_color});
|
||||
}
|
||||
});
|
||||
});
|
||||
105
apps/common/main/lib/component/ColorPalette.js
Normal file
105
apps/common/main/lib/component/ColorPalette.js
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/**
|
||||
* ColorPalette.js
|
||||
*
|
||||
* Created by Alexander Yuzhin on 2/20/14
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
define([
|
||||
'common/main/lib/component/BaseView'
|
||||
], function () { 'use strict';
|
||||
|
||||
Common.UI.ColorPalette = Common.UI.BaseView.extend({
|
||||
options: {
|
||||
allowReselect: true,
|
||||
cls: '',
|
||||
style: ''
|
||||
},
|
||||
|
||||
template:_.template([
|
||||
'<div class="palette-color">',
|
||||
'<% _.each(colors, function(color, index) { %>',
|
||||
'<span class="color-item" data-color="<%= color %>" style="background-color: #<%= color %>;"></span>',
|
||||
'<% }) %>',
|
||||
'</div>'
|
||||
].join('')),
|
||||
|
||||
initialize : function(options) {
|
||||
Common.UI.BaseView.prototype.initialize.call(this, options);
|
||||
|
||||
var me = this;
|
||||
|
||||
this.id = me.options.id;
|
||||
this.cls = me.options.cls;
|
||||
this.style = me.options.style;
|
||||
this.colors = me.options.colors || [];
|
||||
this.value = me.options.value;
|
||||
|
||||
if (me.options.el) {
|
||||
me.render();
|
||||
}
|
||||
},
|
||||
|
||||
render: function (parentEl) {
|
||||
var me = this;
|
||||
|
||||
if (!me.rendered) {
|
||||
this.cmpEl = $(this.template({
|
||||
id : this.id,
|
||||
cls : this.cls,
|
||||
style : this.style,
|
||||
colors : this.colors
|
||||
}));
|
||||
|
||||
if (parentEl) {
|
||||
this.setElement(parentEl, false);
|
||||
parentEl.html(this.cmpEl);
|
||||
} else {
|
||||
$(this.el).html(this.cmpEl);
|
||||
}
|
||||
} else {
|
||||
this.cmpEl = $(this.el);
|
||||
}
|
||||
|
||||
if (!me.rendered) {
|
||||
var el = this.cmpEl;
|
||||
|
||||
el.on('click', 'span.color-item', _.bind(this.itemClick, this));
|
||||
}
|
||||
|
||||
me.rendered = true;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
itemClick: function(e) {
|
||||
var item = $(e.target);
|
||||
|
||||
this.select(item.attr('data-color'));
|
||||
},
|
||||
|
||||
select: function(color, suppressEvent) {
|
||||
if (this.value != color) {
|
||||
var me = this;
|
||||
|
||||
// Remove selection with other elements
|
||||
$('span.color-item', this.cmpEl).removeClass('selected');
|
||||
|
||||
this.value = color;
|
||||
|
||||
if (color && /#?[a-fA-F0-9]{6}/.test(color)) {
|
||||
color = /#?([a-fA-F0-9]{6})/.exec(color)[1].toUpperCase();
|
||||
|
||||
$('span[data-color=' + color + ']', this.cmpEl).addClass('selected');
|
||||
|
||||
if (!suppressEvent)
|
||||
me.trigger('select', me, this.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
183
apps/common/main/lib/component/ComboBorderSize.js
Normal file
183
apps/common/main/lib/component/ComboBorderSize.js
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
/**
|
||||
* ComboBorderSize.js
|
||||
*
|
||||
* Created by Julia Radzhabova on 2/10/14
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Using template
|
||||
*
|
||||
* <div class="input-group input-group-nr combobox combo-border-size" id="id-combobox">
|
||||
* <div class="form-control"></div>
|
||||
* <div style="display: table-cell;"></div>
|
||||
* <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button>
|
||||
* <ul class="dropdown-menu"></ul>
|
||||
* </div>
|
||||
*
|
||||
*/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
define([
|
||||
'common/main/lib/component/ComboBox'
|
||||
], function () {
|
||||
'use strict';
|
||||
|
||||
Common.UI.BordersModel = Backbone.Model.extend({
|
||||
defaults: function() {
|
||||
return {
|
||||
value: null,
|
||||
displayValue: null,
|
||||
pxValue: null,
|
||||
id: Common.UI.getId(),
|
||||
offsety: undefined
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Common.UI.BordersStore = Backbone.Collection.extend({
|
||||
model: Common.UI.BordersModel
|
||||
});
|
||||
|
||||
Common.UI.ComboBorderSize = Common.UI.ComboBox.extend(_.extend({
|
||||
template: _.template([
|
||||
'<div class="input-group combobox combo-border-size input-group-nr <%= cls %>" id="<%= id %>" style="<%= style %>">',
|
||||
'<div class="form-control" style="<%= style %>"></div>',
|
||||
'<div style="display: table-cell;"></div>',
|
||||
'<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"><span class="caret img-commonctrl"></span></button>',
|
||||
'<ul class="dropdown-menu <%= menuCls %>" style="<%= menuStyle %>" role="menu">',
|
||||
'<% _.each(items, function(item) { %>',
|
||||
'<li id="<%= item.id %>" data-value="<%= item.value %>"><a tabindex="-1" type="menuitem">',
|
||||
'<span><%= item.displayValue %></span>',
|
||||
'<% if (item.offsety!==undefined) { %>',
|
||||
'<img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" align="right" style="background-position: 0 -<%= item.offsety %>px;">',
|
||||
'<% } %>',
|
||||
'</a></li>',
|
||||
'<% }); %>',
|
||||
'</ul>',
|
||||
'</div>'
|
||||
].join('')),
|
||||
|
||||
initialize : function(options) {
|
||||
Common.UI.ComboBox.prototype.initialize.call(this, _.extend({
|
||||
editable: false,
|
||||
store: new Common.UI.BordersStore(),
|
||||
data: [
|
||||
{displayValue: this.txtNoBorders, value: 0, pxValue: 0 },
|
||||
{displayValue: '0.5 pt', value: 0.5, pxValue: 0.5, offsety: 0},
|
||||
{displayValue: '1 pt', value: 1, pxValue: 1, offsety: 20},
|
||||
{displayValue: '1.5 pt', value: 1.5, pxValue: 2, offsety: 40},
|
||||
{displayValue: '2.25 pt', value: 2.25,pxValue: 3, offsety: 60},
|
||||
{displayValue: '3 pt', value: 3, pxValue: 4, offsety: 80},
|
||||
{displayValue: '4.5 pt', value: 4.5, pxValue: 5, offsety: 100},
|
||||
{displayValue: '6 pt', value: 6, pxValue: 6, offsety: 120}
|
||||
],
|
||||
menuStyle: 'min-width: 150px;'
|
||||
}, options));
|
||||
},
|
||||
|
||||
render : function(parentEl) {
|
||||
Common.UI.ComboBox.prototype.render.call(this, parentEl);
|
||||
return this;
|
||||
},
|
||||
|
||||
itemClicked: function (e) {
|
||||
var el = $(e.currentTarget).parent();
|
||||
|
||||
this._selectedItem = this.store.findWhere({
|
||||
id: el.attr('id')
|
||||
});
|
||||
if (this._selectedItem) {
|
||||
$('.selected', $(this.el)).removeClass('selected');
|
||||
el.addClass('selected');
|
||||
this.updateFormControl(this._selectedItem);
|
||||
|
||||
this.trigger('selected', this, _.extend({}, this._selectedItem.toJSON()), e);
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
updateFormControl: function(record) {
|
||||
var formcontrol = $(this.el).find('.form-control');
|
||||
|
||||
if (record.get('value')>0) {
|
||||
formcontrol[0].innerHTML = '';
|
||||
formcontrol.removeClass('text').addClass('image');
|
||||
formcontrol.css('background-position', '0 -' + record.get('offsety') + 'px');
|
||||
} else {
|
||||
formcontrol[0].innerHTML = this.txtNoBorders;
|
||||
formcontrol.removeClass('image').addClass('text');
|
||||
}
|
||||
},
|
||||
|
||||
setValue: function(value) {
|
||||
this._selectedItem = (value===null || value===undefined) ? undefined : _.find(this.store.models, function(item) {
|
||||
if ( value<item.attributes.value+0.01 && value>item.attributes.value-0.01) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
$('.selected', $(this.el)).removeClass('selected');
|
||||
|
||||
if (this._selectedItem) {
|
||||
this.updateFormControl(this._selectedItem);
|
||||
$('#' + this._selectedItem.get('id'), $(this.el)).addClass('selected');
|
||||
} else {
|
||||
var formcontrol = $(this.el).find('.form-control');
|
||||
formcontrol[0].innerHTML = '';
|
||||
formcontrol.removeClass('image').addClass('text');
|
||||
}
|
||||
},
|
||||
|
||||
txtNoBorders: 'No Borders'
|
||||
}, Common.UI.ComboBorderSize || {}));
|
||||
|
||||
Common.UI.ComboBorderSizeEditable = Common.UI.ComboBox.extend(_.extend({
|
||||
template: _.template([
|
||||
'<span class="input-group combobox combo-border-size input-group-nr <%= cls %>" id="<%= id %>" style="<%= style %>">',
|
||||
'<input type="text" class="form-control text">',
|
||||
'<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"><span class="caret img-commonctrl"></span></button>',
|
||||
'<ul class="dropdown-menu <%= menuCls %>" style="<%= menuStyle %>" role="menu">',
|
||||
'<% _.each(items, function(item) { %>',
|
||||
'<li id="<%= item.id %>" data-value="<%= item.value %>"><a tabindex="-1" type="menuitem">',
|
||||
'<span><%= item.displayValue %></span>',
|
||||
'<% if (item.offsety!==undefined) { %>',
|
||||
'<img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" align="right" style="background-position: 0 -<%= item.offsety %>px;">',
|
||||
'<% } %>',
|
||||
'</a></li>',
|
||||
'<% }); %>',
|
||||
'</ul>',
|
||||
'</span>'
|
||||
].join('')),
|
||||
|
||||
initialize : function(options) {
|
||||
this.txtNoBorders = options.txtNoBorders || this.txtNoBorders;
|
||||
|
||||
Common.UI.ComboBox.prototype.initialize.call(this, _.extend({
|
||||
editable: true,
|
||||
store: new Common.UI.BordersStore(),
|
||||
data: [
|
||||
{displayValue: this.txtNoBorders, value: 0, pxValue: 0 },
|
||||
{displayValue: '0.5 pt', value: 0.5, pxValue: 0.5, offsety: 0},
|
||||
{displayValue: '1 pt', value: 1, pxValue: 1, offsety: 20},
|
||||
{displayValue: '1.5 pt', value: 1.5, pxValue: 2, offsety: 40},
|
||||
{displayValue: '2.25 pt', value: 2.25,pxValue: 3, offsety: 60},
|
||||
{displayValue: '3 pt', value: 3, pxValue: 4, offsety: 80},
|
||||
{displayValue: '4.5 pt', value: 4.5, pxValue: 5, offsety: 100},
|
||||
{displayValue: '6 pt', value: 6, pxValue: 6, offsety: 120}
|
||||
],
|
||||
menuStyle: 'min-width: 150px;'
|
||||
}, options));
|
||||
},
|
||||
|
||||
render : function(parentEl) {
|
||||
Common.UI.ComboBox.prototype.render.call(this, parentEl);
|
||||
return this;
|
||||
},
|
||||
|
||||
txtNoBorders: 'No Borders'
|
||||
}, Common.UI.ComboBorderSizeEditable || {}));
|
||||
});
|
||||
503
apps/common/main/lib/component/ComboBox.js
Normal file
503
apps/common/main/lib/component/ComboBox.js
Normal file
|
|
@ -0,0 +1,503 @@
|
|||
/**
|
||||
* ComboBox.js
|
||||
*
|
||||
* Created by Alexander Yuzhin on 1/22/14
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Using template
|
||||
*
|
||||
* <div class="input-group input-group-nr combobox" id="id-combobox">
|
||||
* <input type="text" class="form-control">
|
||||
* <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button>
|
||||
* <ul class="dropdown-menu"></ul>
|
||||
* </div>
|
||||
*
|
||||
*/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
define([
|
||||
'common/main/lib/component/BaseView',
|
||||
'common/main/lib/component/Scroller'
|
||||
], function () {
|
||||
'use strict';
|
||||
|
||||
Common.UI.ComboBoxModel = Backbone.Model.extend({
|
||||
defaults: function() {
|
||||
return {
|
||||
id: Common.UI.getId(),
|
||||
value: null,
|
||||
displayValue: null
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Common.UI.ComboBoxStore = Backbone.Collection.extend({
|
||||
model: Common.UI.ComboBoxModel
|
||||
});
|
||||
|
||||
Common.UI.ComboBox = Common.UI.BaseView.extend((function() {
|
||||
return {
|
||||
options : {
|
||||
id : null,
|
||||
cls : '',
|
||||
style : '',
|
||||
hint : false,
|
||||
editable : true,
|
||||
disabled : false,
|
||||
menuCls : '',
|
||||
menuStyle : '',
|
||||
displayField: 'displayValue',
|
||||
valueField : 'value'
|
||||
},
|
||||
|
||||
template: _.template([
|
||||
'<span class="input-group combobox <%= cls %>" id="<%= id %>" style="<%= style %>">',
|
||||
'<input type="text" class="form-control">',
|
||||
'<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"><span class="caret img-commonctrl"></span></button>',
|
||||
'<ul class="dropdown-menu <%= menuCls %>" style="<%= menuStyle %>" role="menu">',
|
||||
'<% _.each(items, function(item) { %>',
|
||||
'<li id="<%= item.id %>" data-value="<%= item.value %>"><a tabindex="-1" type="menuitem"><%= scope.getDisplayValue(item) %></a></li>',
|
||||
'<% }); %>',
|
||||
'</ul>',
|
||||
'</span>'
|
||||
].join('')),
|
||||
|
||||
initialize : function(options) {
|
||||
Common.UI.BaseView.prototype.initialize.call(this, options);
|
||||
|
||||
var me = this,
|
||||
el = $(this.el);
|
||||
|
||||
this.id = me.options.id || Common.UI.getId();
|
||||
this.cls = me.options.cls;
|
||||
this.style = me.options.style;
|
||||
this.menuCls = me.options.menuCls;
|
||||
this.menuStyle = me.options.menuStyle;
|
||||
this.template = me.options.template || me.template;
|
||||
this.hint = me.options.hint;
|
||||
this.editable = me.options.editable;
|
||||
this.disabled = me.options.disabled;
|
||||
this.store = me.options.store || new Common.UI.ComboBoxStore();
|
||||
this.displayField = me.options.displayField;
|
||||
this.valueField = me.options.valueField;
|
||||
me.rendered = me.options.rendered || false;
|
||||
|
||||
this.lastValue = null;
|
||||
|
||||
me.store.add(me.options.data);
|
||||
|
||||
if (me.options.el) {
|
||||
me.render();
|
||||
}
|
||||
},
|
||||
|
||||
render : function(parentEl) {
|
||||
var me = this;
|
||||
|
||||
if (!me.rendered) {
|
||||
this.cmpEl = $(this.template({
|
||||
id : this.id,
|
||||
cls : this.cls,
|
||||
style : this.style,
|
||||
menuCls : this.menuCls,
|
||||
menuStyle : this.menuStyle,
|
||||
items : this.store.toJSON(),
|
||||
scope : me
|
||||
}));
|
||||
|
||||
if (parentEl) {
|
||||
this.setElement(parentEl, false);
|
||||
parentEl.html(this.cmpEl);
|
||||
} else {
|
||||
$(this.el).html(this.cmpEl);
|
||||
}
|
||||
} else {
|
||||
this.cmpEl = $(this.el);
|
||||
}
|
||||
|
||||
if (!me.rendered) {
|
||||
var el = this.cmpEl;
|
||||
|
||||
this._input = el.find('input');
|
||||
this._button = el.find('.btn');
|
||||
|
||||
el.on('click', 'a', _.bind(this.itemClicked, this));
|
||||
el.on('mousedown', 'a', _.bind(this.itemMouseDown, this));
|
||||
|
||||
if (this.editable) {
|
||||
el.on('change', 'input', _.bind(this.onInputChanged, this));
|
||||
el.on('keydown', 'input', _.bind(this.onInputKeyDown, this));
|
||||
el.on('focusin', 'input', _.bind(this.onInputFocusIn, this));
|
||||
el.on('click', '.form-control', _.bind(this.onEditableInputClick, this));
|
||||
} else {
|
||||
el.on('click', '.form-control', _.bind(this.onInputClick, this));
|
||||
this._input.attr('readonly', 'readonly');
|
||||
this._input.attr('data-can-copy', false);
|
||||
}
|
||||
|
||||
if (me.options.hint) {
|
||||
el.attr('data-toggle', 'tooltip');
|
||||
el.tooltip({
|
||||
title : me.options.hint,
|
||||
placement : me.options.hintAnchor||'cursor'
|
||||
});
|
||||
}
|
||||
|
||||
el.on('show.bs.dropdown', _.bind(me.onBeforeShowMenu, me));
|
||||
el.on('shown.bs.dropdown', _.bind(me.onAfterShowMenu, me));
|
||||
el.on('hide.bs.dropdown', _.bind(me.onBeforeHideMenu, me));
|
||||
el.on('hidden.bs.dropdown', _.bind(me.onAfterHideMenu, me));
|
||||
el.on('keydown.after.bs.dropdown', _.bind(me.onAfterKeydownMenu, me));
|
||||
|
||||
Common.NotificationCenter.on('menumanager:hideall', _.bind(me.closeMenu, me));
|
||||
|
||||
this.scroller = new Common.UI.Scroller({
|
||||
el: $('.dropdown-menu', me.cmpEl),
|
||||
minScrollbarLength : 40,
|
||||
scrollYMarginOffset: 30,
|
||||
includePadding : true
|
||||
});
|
||||
|
||||
// set default selection
|
||||
this.setDefaultSelection();
|
||||
|
||||
this.listenTo(this.store, 'reset', this.onResetItems);
|
||||
}
|
||||
|
||||
me.rendered = true;
|
||||
if (me.disabled) me.setDisabled(me.disabled);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
setData: function(data) {
|
||||
this.store.reset([]);
|
||||
this.store.add(data);
|
||||
|
||||
this.setRawValue('');
|
||||
this.onResetItems();
|
||||
},
|
||||
|
||||
openMenu: function(delay) {
|
||||
var me = this;
|
||||
|
||||
_.delay(function(){
|
||||
me.cmpEl.addClass('open')
|
||||
}, delay || 0);
|
||||
},
|
||||
|
||||
closeMenu: function() {
|
||||
this.cmpEl.removeClass('open');
|
||||
},
|
||||
|
||||
isMenuOpen: function() {
|
||||
return this.cmpEl.hasClass('open');
|
||||
},
|
||||
|
||||
onBeforeShowMenu: function(e) {
|
||||
this.trigger('show:before', this, e);
|
||||
if (this.options.hint) {
|
||||
var tip = this.cmpEl.data('bs.tooltip');
|
||||
if (tip) {
|
||||
if (tip.dontShow===undefined)
|
||||
tip.dontShow = true;
|
||||
tip.hide();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onAfterShowMenu: function(e) {
|
||||
var $list = $(this.el).find('ul'),
|
||||
$selected = $list.find('> li.selected');
|
||||
|
||||
if ($selected.length) {
|
||||
var itemTop = $selected.position().top,
|
||||
itemHeight = $selected.height(),
|
||||
listHeight = $list.height();
|
||||
|
||||
if (itemTop < 0 || itemTop + itemHeight > listHeight) {
|
||||
$list.scrollTop($list.scrollTop() + itemTop + itemHeight - (listHeight/2));
|
||||
}
|
||||
}
|
||||
|
||||
if (this.scroller)
|
||||
this.scroller.update();
|
||||
|
||||
this.trigger('show:after', this, e);
|
||||
},
|
||||
|
||||
onBeforeHideMenu: function(e) {
|
||||
this.trigger('hide:before', this, e);
|
||||
|
||||
if (Common.UI.Scroller.isMouseCapture())
|
||||
e.preventDefault();
|
||||
},
|
||||
|
||||
onAfterHideMenu: function(e) {
|
||||
this.cmpEl.find('.dropdown-toggle').blur();
|
||||
this.trigger('hide:after', this, e);
|
||||
},
|
||||
|
||||
onAfterKeydownMenu: function(e) {
|
||||
if (e.keyCode == Common.UI.Keys.RETURN) {
|
||||
$(e.target).click();
|
||||
var me = this;
|
||||
if (this.rendered) {
|
||||
if (Common.Utils.isIE)
|
||||
this._input.trigger('change', { onkeydown: true });
|
||||
else
|
||||
this._input.blur();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (e.keyCode == Common.UI.Keys.ESC && this.isMenuOpen()) {
|
||||
this.closeMenu();
|
||||
this.onAfterHideMenu(e);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
onInputKeyDown: function(e) {
|
||||
var me = this;
|
||||
|
||||
if (e.keyCode == Common.UI.Keys.ESC){
|
||||
this.closeMenu();
|
||||
this.onAfterHideMenu(e);
|
||||
} else if (e.keyCode == Common.UI.Keys.UP || e.keyCode == Common.UI.Keys.DOWN) {
|
||||
if (!this.isMenuOpen())
|
||||
this.openMenu();
|
||||
|
||||
_.delay(function() {
|
||||
me._skipInputChange = true;
|
||||
me.cmpEl.find('ul li:first a').focus();
|
||||
}, 10);
|
||||
} else
|
||||
me._skipInputChange = false;
|
||||
},
|
||||
|
||||
onInputFocusIn: function(e) {
|
||||
this.trigger('combo:focusin', this, e);
|
||||
},
|
||||
|
||||
onInputChanged: function(e, extra) {
|
||||
// skip processing for internally-generated synthetic event
|
||||
// to avoid double processing
|
||||
if (extra && extra.synthetic)
|
||||
return;
|
||||
|
||||
if (this._skipInputChange) {
|
||||
this._skipInputChange = false; return;
|
||||
}
|
||||
|
||||
var val = $(e.target).val(),
|
||||
record = {};
|
||||
|
||||
if (this.lastValue === val) {
|
||||
if (extra && extra.onkeydown)
|
||||
this.trigger('combo:blur', this, e);
|
||||
return;
|
||||
}
|
||||
|
||||
record[this.valueField] = val;
|
||||
|
||||
this.trigger('changed:before', this, record, e);
|
||||
|
||||
if (e.isDefaultPrevented())
|
||||
return;
|
||||
|
||||
var obj;
|
||||
this._selectedItem = this.store.findWhere((obj={}, obj[this.displayField]=val, obj));
|
||||
|
||||
if (this._selectedItem) {
|
||||
record = this._selectedItem.toJSON();
|
||||
$('.selected', $(this.el)).removeClass('selected');
|
||||
$('#' + this._selectedItem.get('id'), $(this.el)).addClass('selected');
|
||||
}
|
||||
|
||||
// trigger changed event
|
||||
this.trigger('changed:after', this, record, e);
|
||||
},
|
||||
|
||||
onInputClick: function(e) {
|
||||
if (this._button)
|
||||
this._button.dropdown('toggle');
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
},
|
||||
|
||||
onEditableInputClick: function(e) {
|
||||
if (this.options.hint) {
|
||||
var tip = this.cmpEl.data('bs.tooltip');
|
||||
if (tip) {
|
||||
if (tip.dontShow===undefined)
|
||||
tip.dontShow = true;
|
||||
tip.hide();
|
||||
}
|
||||
}
|
||||
if (this.isMenuOpen() && e.which == 1)
|
||||
e.stopPropagation();
|
||||
},
|
||||
|
||||
setDefaultSelection: function () {
|
||||
if (!this.rendered)
|
||||
return;
|
||||
|
||||
var val = this._input.val(),
|
||||
obj;
|
||||
|
||||
if (val) {
|
||||
this._selectedItem = this.store.findWhere((obj={}, obj[this.displayField]=val, obj));
|
||||
|
||||
if (this._selectedItem) {
|
||||
$('.selected', $(this.el)).removeClass('selected');
|
||||
$('#' + this._selectedItem.get('id'), $(this.el)).addClass('selected');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setDisabled: function(disabled) {
|
||||
this.disabled = disabled;
|
||||
|
||||
if (!this.rendered)
|
||||
return;
|
||||
|
||||
disabled
|
||||
? this._input.attr('disabled', true)
|
||||
: this._input.removeAttr('disabled');
|
||||
|
||||
this.cmpEl.toggleClass('disabled', disabled);
|
||||
this._button.toggleClass('disabled', disabled);
|
||||
},
|
||||
|
||||
isDisabled: function() {
|
||||
return this.disabled;
|
||||
},
|
||||
|
||||
setRawValue: function(value) {
|
||||
if (this.rendered) {
|
||||
this._input.val(value).trigger('change', { synthetic: true });
|
||||
this.lastValue = (value!==null && value !== undefined) ? value.toString() : value;
|
||||
}
|
||||
},
|
||||
|
||||
getRawValue: function() {
|
||||
return this.rendered ? this._input.val() : null;
|
||||
},
|
||||
|
||||
setValue: function(value) {
|
||||
if (!this.rendered)
|
||||
return;
|
||||
|
||||
var obj;
|
||||
this._selectedItem = this.store.findWhere((obj={}, obj[this.valueField]=value, obj));
|
||||
|
||||
$('.selected', $(this.el)).removeClass('selected');
|
||||
|
||||
if (this._selectedItem) {
|
||||
this.setRawValue(this._selectedItem.get(this.displayField));
|
||||
$('#' + this._selectedItem.get('id'), $(this.el)).addClass('selected');
|
||||
} else {
|
||||
this.setRawValue(value);
|
||||
}
|
||||
},
|
||||
|
||||
getValue: function() {
|
||||
if (!this.rendered)
|
||||
return null;
|
||||
|
||||
if (this._selectedItem && !_.isUndefined(this._selectedItem.get(this.valueField))) {
|
||||
return this._selectedItem.get(this.valueField);
|
||||
}
|
||||
|
||||
return this._input.val();
|
||||
},
|
||||
|
||||
getDisplayValue: function(record) {
|
||||
return Common.Utils.String.htmlEncode(record[this.displayField]);
|
||||
},
|
||||
|
||||
getSelectedRecord: function() {
|
||||
if (!this.rendered)
|
||||
return null;
|
||||
|
||||
if (this._selectedItem && !_.isUndefined(this._selectedItem.get(this.valueField))) {
|
||||
return _.extend({}, this._selectedItem.toJSON());
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
selectRecord: function(record) {
|
||||
if (!this.rendered || !record)
|
||||
return;
|
||||
|
||||
this._selectedItem = record;
|
||||
|
||||
$('.selected', $(this.el)).removeClass('selected');
|
||||
this.setRawValue(this._selectedItem.get(this.displayField));
|
||||
$('#' + this._selectedItem.get('id'), $(this.el)).addClass('selected');
|
||||
},
|
||||
|
||||
itemClicked: function (e) {
|
||||
var el = $(e.target).closest('li');
|
||||
|
||||
this._selectedItem = this.store.findWhere({
|
||||
id: el.attr('id')
|
||||
});
|
||||
|
||||
if (this._selectedItem) {
|
||||
// set input text and trigger input change event marked as synthetic
|
||||
this.lastValue = this._selectedItem.get(this.displayField);
|
||||
this._input.val(this.lastValue).trigger('change', { synthetic: true });
|
||||
|
||||
$('.selected', $(this.el)).removeClass('selected');
|
||||
el.addClass('selected');
|
||||
|
||||
// trigger changed event
|
||||
this.trigger('selected', this, _.extend({}, this._selectedItem.toJSON()), e);
|
||||
|
||||
e.preventDefault();
|
||||
}
|
||||
this._isMouseDownMenu = false;
|
||||
},
|
||||
|
||||
itemMouseDown: function(e) {
|
||||
if (e.which != 1) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
return false;
|
||||
}
|
||||
this._isMouseDownMenu = true;
|
||||
},
|
||||
|
||||
onResetItems: function() {
|
||||
$(this.el).find('ul').html(_.template([
|
||||
'<% _.each(items, function(item) { %>',
|
||||
'<li id="<%= item.id %>" data-value="<%= item.value %>"><a tabindex="-1" type="menuitem"><%= scope.getDisplayValue(item) %></a></li>',
|
||||
'<% }); %>'
|
||||
].join(''), {
|
||||
items: this.store.toJSON(),
|
||||
scope: this
|
||||
}));
|
||||
|
||||
if (!_.isUndefined(this.scroller)) {
|
||||
this.scroller.destroy();
|
||||
delete this.scroller;
|
||||
}
|
||||
this.scroller = new Common.UI.Scroller({
|
||||
el: $('.dropdown-menu', this.cmpEl),
|
||||
minScrollbarLength : 40,
|
||||
scrollYMarginOffset: 30,
|
||||
includePadding : true
|
||||
});
|
||||
}
|
||||
}
|
||||
})());
|
||||
});
|
||||
474
apps/common/main/lib/component/ComboBoxFonts.js
Normal file
474
apps/common/main/lib/component/ComboBoxFonts.js
Normal file
|
|
@ -0,0 +1,474 @@
|
|||
/**
|
||||
* ComboBoxFonts.js
|
||||
*
|
||||
* Created by Alexander Yuzhin on 2/11/14
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
var FONT_TYPE_RECENT = 4;
|
||||
|
||||
define([
|
||||
'common/main/lib/component/ComboBox'
|
||||
], function () {
|
||||
'use strict';
|
||||
|
||||
Common.UI.ComboBoxFonts = Common.UI.ComboBox.extend((function() {
|
||||
var iconWidth = 302,
|
||||
iconHeight = FONT_THUMBNAIL_HEIGHT || 26,
|
||||
isRetina = window.devicePixelRatio > 1,
|
||||
thumbCanvas = document.createElement('canvas'),
|
||||
thumbContext = thumbCanvas.getContext('2d'),
|
||||
thumbPath = '../../../sdk/Common/Images/fonts_thumbnail.png',
|
||||
thumbPath2x = '../../../sdk/Common/Images/fonts_thumbnail@2x.png',
|
||||
listItemHeight = 36;
|
||||
|
||||
if (typeof window['AscDesktopEditor'] === 'object') {
|
||||
thumbPath = window['AscDesktopEditor'].getFontsSprite();
|
||||
thumbPath2x = window['AscDesktopEditor'].getFontsSprite(true);
|
||||
}
|
||||
|
||||
thumbCanvas.height = isRetina ? iconHeight * 2 : iconHeight;
|
||||
thumbCanvas.width = isRetina ? iconWidth * 2 : iconWidth;
|
||||
|
||||
return {
|
||||
template: _.template([
|
||||
'<div class="input-group combobox fonts <%= cls %>" id="<%= id %>" style="<%= style %>">',
|
||||
'<input type="text" class="form-control">',
|
||||
'<div style="display: table-cell;"></div>',
|
||||
'<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"><span class="caret img-commonctrl"></span></button>',
|
||||
'<ul class="dropdown-menu <%= menuCls %>" style="<%= menuStyle %>" role="menu">',
|
||||
'<li class="divider">',
|
||||
'<% _.each(items, function(item) { %>',
|
||||
'<li id="<%= item.id %>">',
|
||||
'<a class="font-item" tabindex="-1" type="menuitem" style="vertical-align:middle; margin: 0 0 0 -10px; height:<%=scope.getListItemHeight()%>px;"/>',
|
||||
'</li>',
|
||||
'<% }); %>',
|
||||
'</ul>',
|
||||
'</div>'
|
||||
].join('')),
|
||||
|
||||
initialize : function(options) {
|
||||
Common.UI.ComboBox.prototype.initialize.call(this, _.extend(options, {
|
||||
displayField: 'name'
|
||||
}));
|
||||
|
||||
this.recent = _.isNumber(options.recent) ? options.recent : 3;
|
||||
this.bindUpdateVisibleFontsTiles = _.bind(this.updateVisibleFontsTiles, this);
|
||||
|
||||
Common.NotificationCenter.on('fonts:change', _.bind(this.onApiChangeFont, this));
|
||||
Common.NotificationCenter.on('fonts:load', _.bind(this.fillFonts, this));
|
||||
},
|
||||
|
||||
render : function(parentEl) {
|
||||
var oldRawValue = null;
|
||||
|
||||
if (!_.isUndefined(this._input)) {
|
||||
oldRawValue = this._input.val();
|
||||
}
|
||||
|
||||
Common.UI.ComboBox.prototype.render.call(this, parentEl);
|
||||
|
||||
this.setRawValue(oldRawValue);
|
||||
|
||||
this._input.on('keyup', _.bind(this.onInputKeyUp, this));
|
||||
this._input.on('keydown', _.bind(this.onInputKeyDown, this));
|
||||
|
||||
this.scroller.update({alwaysVisibleY: true, onChange:this.bindUpdateVisibleFontsTiles});
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
onAfterKeydownMenu: function(e) {
|
||||
var me = this;
|
||||
if (e.keyCode == Common.UI.Keys.RETURN) {
|
||||
if ($(e.target).closest('input').length) { // enter in input field
|
||||
if (this.lastValue !== this._input.val())
|
||||
this._input.trigger('change');
|
||||
} else { // enter in dropdown list
|
||||
$(e.target).click();
|
||||
if (this.rendered) {
|
||||
if (Common.Utils.isIE)
|
||||
this._input.trigger('change', { onkeydown: true });
|
||||
else
|
||||
this._input.blur();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if (e.keyCode == Common.UI.Keys.ESC && this.isMenuOpen()) {
|
||||
this._input.val(this.lastValue);
|
||||
setTimeout(function() {
|
||||
me.closeMenu();
|
||||
me.onAfterHideMenu(e);
|
||||
}, 10);
|
||||
return false;
|
||||
} else if ((e.keyCode == Common.UI.Keys.HOME || e.keyCode == Common.UI.Keys.END || e.keyCode == Common.UI.Keys.BACKSPACE) && this.isMenuOpen()) {
|
||||
setTimeout(function() {
|
||||
me._input.focus();
|
||||
}, 10);
|
||||
}
|
||||
|
||||
this.updateVisibleFontsTiles();
|
||||
},
|
||||
|
||||
onInputKeyUp: function(e) {
|
||||
if (e.keyCode != Common.UI.Keys.RETURN && e.keyCode !== Common.UI.Keys.SHIFT &&
|
||||
e.keyCode !== Common.UI.Keys.CTRL && e.keyCode !== Common.UI.Keys.ALT &&
|
||||
e.keyCode !== Common.UI.Keys.LEFT && e.keyCode !== Common.UI.Keys.RIGHT &&
|
||||
e.keyCode !== Common.UI.Keys.HOME && e.keyCode !== Common.UI.Keys.END &&
|
||||
e.keyCode !== Common.UI.Keys.ESC &&
|
||||
e.keyCode !== Common.UI.Keys.INSERT && e.keyCode !== Common.UI.Keys.TAB){
|
||||
e.stopPropagation();
|
||||
this.selectCandidate(e.keyCode == Common.UI.Keys.DELETE || e.keyCode == Common.UI.Keys.BACKSPACE);
|
||||
if (this._selectedItem) {
|
||||
var me = this;
|
||||
setTimeout(function() {
|
||||
var input = me._input[0],
|
||||
text = me._selectedItem.get(me.displayField),
|
||||
inputVal = input.value;
|
||||
if (me.rendered) {
|
||||
if (document.selection) { // IE
|
||||
document.selection.createRange().text = text;
|
||||
} else if (input.selectionStart || input.selectionStart == '0') { //FF и Webkit
|
||||
input.value = text;
|
||||
input.selectionStart = inputVal.length;
|
||||
input.selectionEnd = text.length;
|
||||
}
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onInputKeyDown: function(e) {
|
||||
var me = this;
|
||||
|
||||
if (e.keyCode == Common.UI.Keys.ESC){
|
||||
this._input.val(this.lastValue);
|
||||
setTimeout(function() {
|
||||
me.closeMenu();
|
||||
me.onAfterHideMenu(e);
|
||||
}, 10);
|
||||
} else if (e.keyCode != Common.UI.Keys.RETURN && e.keyCode != Common.UI.Keys.CTRL && e.keyCode != Common.UI.Keys.SHIFT && e.keyCode != Common.UI.Keys.ALT){
|
||||
if (!this.isMenuOpen())
|
||||
this.openMenu();
|
||||
|
||||
if (e.keyCode == Common.UI.Keys.UP || e.keyCode == Common.UI.Keys.DOWN) {
|
||||
_.delay(function() {
|
||||
var selected = me.cmpEl.find('ul li.selected a');
|
||||
|
||||
if (selected.length<=0)
|
||||
selected = me.cmpEl.find('ul li:not(.divider):first a');
|
||||
|
||||
me._skipInputChange = true;
|
||||
selected.focus();
|
||||
me.updateVisibleFontsTiles();
|
||||
}, 10);
|
||||
} else
|
||||
me._skipInputChange = false;
|
||||
}
|
||||
},
|
||||
|
||||
onInputChanged: function(e, extra) {
|
||||
// skip processing for internally-generated synthetic event
|
||||
// to avoid double processing
|
||||
if (extra && extra.synthetic)
|
||||
return;
|
||||
|
||||
if (this._skipInputChange) {
|
||||
this._skipInputChange = false; return;
|
||||
}
|
||||
|
||||
if (this._isMouseDownMenu) {
|
||||
this._isMouseDownMenu = false; return;
|
||||
}
|
||||
|
||||
var val = $(e.target).val(),
|
||||
record = {};
|
||||
|
||||
if (this.lastValue === val) {
|
||||
if (extra && extra.onkeydown)
|
||||
this.trigger('combo:blur', this, e);
|
||||
return;
|
||||
}
|
||||
|
||||
record[this.valueField] = val;
|
||||
record[this.displayField] = val;
|
||||
|
||||
this.trigger('changed:before', this, record, e);
|
||||
|
||||
if (e.isDefaultPrevented())
|
||||
return;
|
||||
|
||||
if (this._selectedItem) {
|
||||
record[this.valueField] = this._selectedItem.get(this.displayField);
|
||||
this.setRawValue(record[this.valueField]);
|
||||
this.trigger('selected', this, _.extend({}, this._selectedItem.toJSON()), e);
|
||||
this.addItemToRecent(this._selectedItem);
|
||||
this.closeMenu();
|
||||
} else {
|
||||
this.setRawValue(record[this.valueField]);
|
||||
record['isNewFont'] = true;
|
||||
this.trigger('selected', this, record, e);
|
||||
this.closeMenu();
|
||||
}
|
||||
|
||||
// trigger changed event
|
||||
this.trigger('changed:after', this, record, e);
|
||||
},
|
||||
|
||||
getImageUri: function(opts) {
|
||||
if (opts.cloneid) {
|
||||
var img = $(this.el).find('ul > li#'+opts.cloneid + ' img');
|
||||
return img != null ? img[0].src : undefined;
|
||||
}
|
||||
|
||||
if (isRetina) {
|
||||
thumbContext.clearRect(0, 0, iconWidth * 2, iconHeight * 2);
|
||||
thumbContext.drawImage(this.spriteThumbs, 0, -FONT_THUMBNAIL_HEIGHT * 2 * opts.imgidx);
|
||||
} else {
|
||||
thumbContext.clearRect(0, 0, iconWidth, iconHeight);
|
||||
thumbContext.drawImage(this.spriteThumbs, 0, -FONT_THUMBNAIL_HEIGHT * opts.imgidx);
|
||||
}
|
||||
|
||||
return thumbCanvas.toDataURL();
|
||||
},
|
||||
|
||||
getImageWidth: function() {
|
||||
return iconWidth;
|
||||
},
|
||||
|
||||
getImageHeight: function() {
|
||||
return iconHeight;
|
||||
},
|
||||
|
||||
getListItemHeight: function() {
|
||||
return listItemHeight;
|
||||
},
|
||||
|
||||
loadSprite: function(callback) {
|
||||
if (callback) {
|
||||
this.spriteThumbs = new Image();
|
||||
this.spriteThumbs.onload = callback;
|
||||
this.spriteThumbs.src = (window.devicePixelRatio > 1) ? thumbPath2x : thumbPath;
|
||||
}
|
||||
},
|
||||
|
||||
fillFonts: function(store, select) {
|
||||
var me = this;
|
||||
|
||||
this.loadSprite(function() {
|
||||
me.store.set(store.toJSON());
|
||||
|
||||
me.rendered = false;
|
||||
me.render($(me.el));
|
||||
|
||||
me._fontsArray = me.store.toJSON();
|
||||
|
||||
if (me.recent > 0) {
|
||||
me.store.on('add', me.onInsertItem, me);
|
||||
me.store.on('remove', me.onRemoveItem, me);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onApiChangeFont: function(font) {
|
||||
var name = (_.isFunction(font.get_Name) ? font.get_Name() : font.asc_getName());
|
||||
|
||||
if (this.getRawValue() !== name) {
|
||||
var record = this.store.findWhere({
|
||||
name: name
|
||||
});
|
||||
|
||||
$('.selected', $(this.el)).removeClass('selected');
|
||||
|
||||
if (record) {
|
||||
this.setRawValue(record.get(this.displayField));
|
||||
var itemNode = $('#' + record.get('id'), $(this.el)),
|
||||
menuNode = $('ul.dropdown-menu', this.cmpEl);
|
||||
|
||||
if (itemNode && menuNode) {
|
||||
itemNode.addClass('selected');
|
||||
if (this.recent<=0)
|
||||
menuNode.scrollTop(itemNode.offset().top - menuNode.offset().top);
|
||||
}
|
||||
} else {
|
||||
this.setRawValue(name);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
itemClicked: function (e) {
|
||||
var el = $(e.target).closest('li');
|
||||
var record = this.store.findWhere({id: el.attr('id')});
|
||||
this.addItemToRecent(record);
|
||||
|
||||
Common.UI.ComboBox.prototype.itemClicked.apply(this, arguments);
|
||||
},
|
||||
|
||||
onInsertItem: function(item) {
|
||||
$(this.el).find('ul').prepend(_.template([
|
||||
'<li id="<%= item.id %>">',
|
||||
'<a class="font-item" tabindex="-1" type="menuitem" style="vertical-align:middle; margin: 0 0 0 -10px; height:<%=scope.getListItemHeight()%>px;"/>',
|
||||
'</li>'
|
||||
].join(''), {
|
||||
item: item.attributes,
|
||||
scope: this
|
||||
}));
|
||||
},
|
||||
|
||||
onRemoveItem: function(item, store, opts) {
|
||||
$(this.el).find('ul > li#'+item.id).remove();
|
||||
},
|
||||
|
||||
onBeforeShowMenu: function(e) {
|
||||
Common.UI.ComboBox.prototype.onBeforeShowMenu.apply(this, arguments);
|
||||
|
||||
if (!this.getSelectedRecord() && !!this.getRawValue()) {
|
||||
var record = this.store.where({name: this.getRawValue()});
|
||||
if (record && record.length) {
|
||||
this.selectRecord(record[record.length - 1]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onAfterShowMenu: function(e) {
|
||||
if (this.recent > 0) {
|
||||
if (this.scroller && !this._scrollerIsInited) {
|
||||
this.scroller.update();
|
||||
this._scrollerIsInited = true;
|
||||
}
|
||||
$(this.el).find('ul').scrollTop(0);
|
||||
this.trigger('show:after', this, e);
|
||||
} else {
|
||||
Common.UI.ComboBox.prototype.onAfterShowMenu.apply(this, arguments);
|
||||
}
|
||||
|
||||
this.flushVisibleFontsTiles();
|
||||
this.updateVisibleFontsTiles(null, 0);
|
||||
},
|
||||
|
||||
onAfterHideMenu: function(e) {
|
||||
if (this.lastValue !== this._input.val())
|
||||
this._input.val(this.lastValue);
|
||||
|
||||
Common.UI.ComboBox.prototype.onAfterHideMenu.apply(this, arguments);
|
||||
},
|
||||
|
||||
addItemToRecent: function(record) {
|
||||
if (record.get('type') != FONT_TYPE_RECENT &&
|
||||
!this.store.findWhere({name: record.get('name'),type:FONT_TYPE_RECENT})) {
|
||||
var fonts = this.store.where({type:FONT_TYPE_RECENT});
|
||||
if (!(fonts.length < this.recent)) {
|
||||
this.store.remove(fonts[this.recent - 1]);
|
||||
}
|
||||
|
||||
var new_record = record.clone();
|
||||
new_record.set({'type': FONT_TYPE_RECENT, 'id': Common.UI.getId(), cloneid: record.id});
|
||||
this.store.add(new_record, {at:0});
|
||||
}
|
||||
},
|
||||
|
||||
selectCandidate: function(full) {
|
||||
var me = this,
|
||||
inputVal = this._input.val().toLowerCase();
|
||||
|
||||
if (!this._fontsArray)
|
||||
this._fontsArray = this.store.toJSON();
|
||||
|
||||
var font = _.find(this._fontsArray, function(font) {
|
||||
return (full) ? (font[me.displayField].toLowerCase() == inputVal) : (font[me.displayField].toLowerCase().indexOf(inputVal) == 0)
|
||||
});
|
||||
|
||||
if (font) {
|
||||
this._selectedItem = this.store.findWhere({
|
||||
id: font.id
|
||||
});
|
||||
} else
|
||||
this._selectedItem = null;
|
||||
|
||||
$('.selected', $(this.el)).removeClass('selected');
|
||||
|
||||
if (this._selectedItem) {
|
||||
var itemNode = $('#' + this._selectedItem.get('id'), $(this.el)),
|
||||
menuEl = $('ul[role=menu]', $(this.el));
|
||||
|
||||
if (itemNode.length > 0 && menuEl.length > 0) {
|
||||
itemNode.addClass('selected');
|
||||
|
||||
var itemTop = itemNode.position().top,
|
||||
menuTop = menuEl.scrollTop();
|
||||
|
||||
if (itemTop != 0)
|
||||
menuEl.scrollTop(menuTop + itemTop);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
updateVisibleFontsTiles: function(e, scrollY) {
|
||||
var me = this, j = 0, storeCount = me.store.length, index = 0;
|
||||
|
||||
if (!me.tiles) me.tiles = [];
|
||||
if (storeCount !== me.tiles.length) {
|
||||
for (j = me.tiles.length; j < storeCount; ++j) {
|
||||
me.tiles.push(null);
|
||||
}
|
||||
}
|
||||
|
||||
if (_.isUndefined(scrollY)) scrollY = parseInt($(me.el).find('.ps-scrollbar-x-rail').css('bottom'));
|
||||
|
||||
var scrollH = $(me.el).find('.dropdown-menu').height(),
|
||||
count = Math.max(Math.floor(scrollH / listItemHeight) + 3, 0),
|
||||
from = Math.max(Math.floor(-(scrollY / listItemHeight)) - 1, 0),
|
||||
to = from + count;
|
||||
|
||||
var listItems = $(me.el).find('a');
|
||||
|
||||
for (j = 0; j < storeCount; ++j) {
|
||||
if (from <= j && j < to) {
|
||||
if (null === me.tiles[j]) {
|
||||
var fontImage = document.createElement('canvas');
|
||||
var context = fontImage.getContext('2d');
|
||||
|
||||
fontImage.height = isRetina ? iconHeight * 2 : iconHeight;
|
||||
fontImage.width = isRetina ? iconWidth * 2 : iconWidth;
|
||||
|
||||
fontImage.style.width = iconWidth + 'px';
|
||||
fontImage.style.height = iconHeight + 'px';
|
||||
|
||||
index = me.store.at(j).get('imgidx');
|
||||
|
||||
if (isRetina) {
|
||||
context.clearRect(0, 0, iconWidth * 2, iconHeight * 2);
|
||||
context.drawImage(me.spriteThumbs, 0, -FONT_THUMBNAIL_HEIGHT * 2 * index);
|
||||
} else {
|
||||
context.clearRect(0, 0, iconWidth, iconHeight);
|
||||
context.drawImage(me.spriteThumbs, 0, -FONT_THUMBNAIL_HEIGHT * index);
|
||||
}
|
||||
|
||||
me.tiles[j] = fontImage;
|
||||
$(listItems[j]).get(0).appendChild(fontImage);
|
||||
}
|
||||
} else {
|
||||
if (me.tiles[j]) {
|
||||
me.tiles[j].parentNode.removeChild(me.tiles[j]);
|
||||
me.tiles[j] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
flushVisibleFontsTiles: function() {
|
||||
for (var j = this.tiles.length - 1; j >= 0; --j) {
|
||||
if (this.tiles[j]) {
|
||||
this.tiles[j].parentNode.removeChild(this.tiles[j]);
|
||||
this.tiles[j] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})());
|
||||
});
|
||||
433
apps/common/main/lib/component/ComboDataView.js
Normal file
433
apps/common/main/lib/component/ComboDataView.js
Normal file
|
|
@ -0,0 +1,433 @@
|
|||
/**
|
||||
* ComboDataView.js
|
||||
*
|
||||
* Created by Alexander Yuzhin on 2/13/14
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
define([
|
||||
'common/main/lib/component/BaseView',
|
||||
'common/main/lib/component/DataView'
|
||||
], function () {
|
||||
'use strict';
|
||||
|
||||
Common.UI.ComboDataView = Common.UI.BaseView.extend({
|
||||
options : {
|
||||
id : null,
|
||||
cls : '',
|
||||
style : '',
|
||||
hint : false,
|
||||
itemWidth : 80,
|
||||
itemHeight : 40,
|
||||
menuMaxHeight : 300,
|
||||
enableKeyEvents : false,
|
||||
beforeOpenHandler : null,
|
||||
additionalMenuItems : null,
|
||||
showLast: true
|
||||
},
|
||||
|
||||
template: _.template([
|
||||
'<div id="<%= id %>" class="combo-dataview <%= cls %>" style="<%= style %>">',
|
||||
'<div class="view"></div> ',
|
||||
'<div class="button"></div> ',
|
||||
'</div>'
|
||||
].join('')),
|
||||
|
||||
initialize : function(options) {
|
||||
Common.UI.BaseView.prototype.initialize.call(this, options);
|
||||
|
||||
this.id = this.options.id || Common.UI.getId();
|
||||
this.cls = this.options.cls;
|
||||
this.style = this.options.style;
|
||||
this.hint = this.options.hint;
|
||||
this.store = this.options.store || new Common.UI.DataViewStore();
|
||||
this.itemWidth = this.options.itemWidth;
|
||||
this.itemHeight = this.options.itemHeight;
|
||||
this.menuMaxHeight = this.options.menuMaxHeight;
|
||||
this.beforeOpenHandler = this.options.beforeOpenHandler;
|
||||
this.showLast = this.options.showLast;
|
||||
this.rootWidth = 0;
|
||||
this.rootHeight = 0;
|
||||
this.rendered = false;
|
||||
|
||||
this.fieldPicker = new Common.UI.DataView({
|
||||
cls: 'field-picker',
|
||||
allowScrollbar: false,
|
||||
itemTemplate : _.template([
|
||||
'<div class="style" id="<%= id %>">',
|
||||
'<img src="<%= imageUrl %>" width="' + this.itemWidth + '" height="' + this.itemHeight + '"/>',
|
||||
'<% if (typeof title !== "undefined") {%>',
|
||||
'<span class="title"><%= title %></span>',
|
||||
'<% } %>',
|
||||
'</div>'
|
||||
].join(''))
|
||||
});
|
||||
|
||||
this.openButton = new Common.UI.Button({
|
||||
cls: 'open-menu',
|
||||
menu: new Common.UI.Menu({
|
||||
menuAlign: 'tl-tl',
|
||||
offset: [0, 3],
|
||||
items: [
|
||||
{template: _.template('<div class="menu-picker-container"></div>')}
|
||||
]
|
||||
})
|
||||
});
|
||||
|
||||
if (this.options.additionalMenuItems != null) {
|
||||
this.openButton.menu.items = this.openButton.menu.items.concat(this.options.additionalMenuItems)
|
||||
}
|
||||
|
||||
this.menuPicker = new Common.UI.DataView({
|
||||
cls: 'menu-picker',
|
||||
parentMenu: this.openButton.menu,
|
||||
restoreHeight: this.menuMaxHeight,
|
||||
style: 'max-height: '+this.menuMaxHeight+'px;',
|
||||
enableKeyEvents: this.options.enableKeyEvents,
|
||||
itemTemplate : _.template([
|
||||
'<div class="style" id="<%= id %>">',
|
||||
'<img src="<%= imageUrl %>" width="' + this.itemWidth + '" height="' + this.itemHeight + '"/>',
|
||||
'<% if (typeof title !== "undefined") {%>',
|
||||
'<span class="title"><%= title %></span>',
|
||||
'<% } %>',
|
||||
'</div>'
|
||||
].join(''))
|
||||
});
|
||||
|
||||
// Handle resize
|
||||
setInterval(_.bind(this.checkSize, this), 500);
|
||||
|
||||
if (this.options.el) {
|
||||
this.render();
|
||||
}
|
||||
},
|
||||
|
||||
render: function(parentEl) {
|
||||
if (!this.rendered) {
|
||||
var me = this;
|
||||
|
||||
me.trigger('render:before', me);
|
||||
|
||||
me.cmpEl = $(me.el);
|
||||
|
||||
var templateEl = me.template({
|
||||
id : me.id,
|
||||
cls : me.cls,
|
||||
style : me.style
|
||||
});
|
||||
|
||||
if (parentEl) {
|
||||
me.setElement(parentEl, false);
|
||||
|
||||
me.cmpEl = $(templateEl);
|
||||
|
||||
parentEl.html(me.cmpEl);
|
||||
} else {
|
||||
me.cmpEl.html(templateEl);
|
||||
}
|
||||
|
||||
me.rootWidth = me.cmpEl.width();
|
||||
me.rootHeight = me.cmpEl.height();
|
||||
|
||||
me.fieldPicker.render($('.view', me.cmpEl));
|
||||
me.openButton.render($('.button', me.cmpEl));
|
||||
me.menuPicker.render($('.menu-picker-container', me.cmpEl));
|
||||
|
||||
if (me.openButton.menu.cmpEl) {
|
||||
if (me.openButton.menu.cmpEl) {
|
||||
me.openButton.menu.menuAlignEl = me.cmpEl;
|
||||
me.openButton.menu.cmpEl.css('min-width', me.itemWidth);
|
||||
me.openButton.menu.on('show:before', _.bind(me.onBeforeShowMenu, me));
|
||||
me.openButton.menu.on('show:after', _.bind(me.onAfterShowMenu, me));
|
||||
me.openButton.cmpEl.on('hide.bs.dropdown', _.bind(me.onBeforeHideMenu, me));
|
||||
me.openButton.cmpEl.on('hidden.bs.dropdown', _.bind(me.onAfterHideMenu, me));
|
||||
}
|
||||
}
|
||||
|
||||
if (me.options.hint) {
|
||||
me.cmpEl.attr('data-toggle', 'tooltip');
|
||||
me.cmpEl.tooltip({
|
||||
title : me.options.hint,
|
||||
placement : me.options.hintAnchor || 'cursor'
|
||||
});
|
||||
}
|
||||
|
||||
me.fieldPicker.on('item:select', _.bind(me.onFieldPickerSelect, me));
|
||||
me.menuPicker.on('item:select', _.bind(me.onMenuPickerSelect, me));
|
||||
me.fieldPicker.on('item:click', _.bind(me.onFieldPickerClick, me));
|
||||
me.menuPicker.on('item:click', _.bind(me.onMenuPickerClick, me));
|
||||
me.fieldPicker.on('item:contextmenu', _.bind(me.onPickerItemContextMenu, me));
|
||||
me.menuPicker.on('item:contextmenu', _.bind(me.onPickerItemContextMenu, me));
|
||||
|
||||
me.fieldPicker.el.addEventListener('contextmenu', _.bind(me.onPickerComboContextMenu, me), false);
|
||||
me.menuPicker.el.addEventListener('contextmenu', _.bind(me.onPickerComboContextMenu, me), false);
|
||||
|
||||
me.onResize();
|
||||
|
||||
me.rendered = true;
|
||||
|
||||
me.trigger('render:after', me);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
checkSize: function() {
|
||||
if (this.cmpEl) {
|
||||
var me = this,
|
||||
width = this.cmpEl.width(),
|
||||
height = this.cmpEl.height();
|
||||
|
||||
if (this.rootWidth != width || this.rootHeight != height) {
|
||||
this.rootWidth = width;
|
||||
this.rootHeight = height;
|
||||
setTimeout(function() {
|
||||
me.openButton.menu.cmpEl.outerWidth();
|
||||
me.rootWidth = me.cmpEl.width();
|
||||
}, 10);
|
||||
this.onResize();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onResize: function() {
|
||||
if (this.openButton) {
|
||||
var button = $('button', this.openButton.cmpEl);
|
||||
button && button.css({
|
||||
width : $('.button', this.cmpEl).width(),
|
||||
height: $('.button', this.cmpEl).height()
|
||||
});
|
||||
|
||||
this.openButton.menu.hide();
|
||||
|
||||
var picker = this.menuPicker;
|
||||
if (picker) {
|
||||
var record = picker.getSelectedRec();
|
||||
|
||||
if (record) {
|
||||
record = record[0];
|
||||
this.fillComboView(record || picker.store.at(0), !!record, true);
|
||||
}
|
||||
|
||||
picker.onResize();
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.isSuspendEvents)
|
||||
this.trigger('resize', this);
|
||||
},
|
||||
|
||||
onBeforeShowMenu: function(e) {
|
||||
var me = this;
|
||||
|
||||
if (_.isFunction(me.beforeOpenHandler)){
|
||||
me.beforeOpenHandler(me, e);
|
||||
} else if (me.openButton.menu.cmpEl) {
|
||||
var itemMargin = 0;
|
||||
|
||||
try {
|
||||
var itemEl = $($('.dropdown-menu .dataview.inner .style', me.cmpEl)[0]);
|
||||
itemMargin = itemEl ? (parseInt(itemEl.css('margin-left')) + parseInt(itemEl.css('margin-right'))) : 0;
|
||||
} catch(e) {}
|
||||
|
||||
me.openButton.menu.cmpEl.css({
|
||||
'width' : Math.round((me.cmpEl.width() + (itemMargin * me.fieldPicker.store.length))/ me.itemWidth - .2) * (me.itemWidth + itemMargin),
|
||||
'min-height': this.cmpEl.height()
|
||||
});
|
||||
}
|
||||
|
||||
if (me.options.hint) {
|
||||
var tip = me.cmpEl.data('bs.tooltip');
|
||||
if (tip) {
|
||||
if (tip.dontShow===undefined)
|
||||
tip.dontShow = true;
|
||||
tip.hide();
|
||||
}
|
||||
}
|
||||
this.menuPicker.selectedBeforeHideRec = null; // for DataView - onKeyDown - Return key
|
||||
},
|
||||
|
||||
onBeforeHideMenu: function(e) {
|
||||
this.trigger('hide:before', this, e);
|
||||
|
||||
if (Common.UI.Scroller.isMouseCapture())
|
||||
e.preventDefault();
|
||||
|
||||
if (this.isStylesNotClosable)
|
||||
return false;
|
||||
},
|
||||
|
||||
onAfterShowMenu: function(e) {
|
||||
var me = this;
|
||||
if (me.menuPicker.scroller) {
|
||||
me.menuPicker.scroller.update({
|
||||
includePadding: true,
|
||||
suppressScrollX: true,
|
||||
alwaysVisibleY: true
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onAfterHideMenu: function(e) {
|
||||
this.menuPicker.selectedBeforeHideRec = this.menuPicker.getSelectedRec()[0]; // for DataView - onKeyDown - Return key
|
||||
(this.showLast) ? this.menuPicker.showLastSelected() : this.menuPicker.deselectAll();
|
||||
this.trigger('hide:after', this, e);
|
||||
},
|
||||
|
||||
onFieldPickerSelect: function(picker, item, record) {
|
||||
//
|
||||
},
|
||||
|
||||
onMenuPickerSelect: function(picker, item, record, fromKeyDown) {
|
||||
if (this.disabled || fromKeyDown===true) return;
|
||||
|
||||
this.fillComboView(record, false);
|
||||
if (record && !this.isSuspendEvents)
|
||||
this.trigger('select', this, record);
|
||||
},
|
||||
|
||||
onFieldPickerClick: function(dataView, itemView, record) {
|
||||
if (this.disabled) return;
|
||||
|
||||
if (!this.isSuspendEvents)
|
||||
this.trigger('click', this, record);
|
||||
|
||||
if (this.options.hint) {
|
||||
var tip = this.cmpEl.data('bs.tooltip');
|
||||
if (tip) {
|
||||
if (tip.dontShow===undefined)
|
||||
tip.dontShow = true;
|
||||
tip.hide();
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.showLast) this.fieldPicker.deselectAll();
|
||||
},
|
||||
|
||||
onMenuPickerClick: function(dataView, itemView, record) {
|
||||
if (this.disabled) return;
|
||||
|
||||
if (!this.isSuspendEvents)
|
||||
this.trigger('click', this, record);
|
||||
},
|
||||
|
||||
onPickerItemContextMenu: function(dataView, itemView, record, e) {
|
||||
if (this.disabled) return;
|
||||
|
||||
if (!this.isSuspendEvents) {
|
||||
this.trigger('contextmenu', this, record, e);
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
},
|
||||
|
||||
onPickerComboContextMenu: function(mouseEvent) {
|
||||
if (this.disabled) return;
|
||||
|
||||
if (!this.isSuspendEvents) {
|
||||
this.trigger('contextmenu', this, undefined, mouseEvent);
|
||||
}
|
||||
},
|
||||
|
||||
setDisabled: function(disabled) {
|
||||
this.disabled = disabled;
|
||||
|
||||
if (!this.rendered)
|
||||
return;
|
||||
|
||||
this.cmpEl.toggleClass('disabled', disabled);
|
||||
$('button', this.openButton.cmpEl).toggleClass('disabled', disabled);
|
||||
this.fieldPicker.setDisabled(disabled);
|
||||
},
|
||||
|
||||
isDisabled: function() {
|
||||
return this.disabled;
|
||||
},
|
||||
|
||||
fillComboView: function(record, forceSelect, forceFill) {
|
||||
if (!_.isUndefined(record) && record instanceof Backbone.Model){
|
||||
var me = this,
|
||||
store = me.menuPicker.store,
|
||||
fieldPickerEl = $(me.fieldPicker.el);
|
||||
|
||||
if (store) {
|
||||
if (forceFill || !me.fieldPicker.store.findWhere({'id': record.get('id')})){
|
||||
if (me.itemMarginLeft===undefined) {
|
||||
var div = $($(this.menuPicker.el).find('.inner > div:not(.grouped-data):not(.ps-scrollbar-x-rail):not(.ps-scrollbar-y-rail)')[0]);
|
||||
if (div.length > 0) {
|
||||
me.itemMarginLeft = parseInt(div.css('margin-left'));
|
||||
me.itemMarginRight = parseInt(div.css('margin-right'));
|
||||
me.itemPaddingLeft = parseInt(div.css('padding-left'));
|
||||
me.itemPaddingRight = parseInt(div.css('padding-right'));
|
||||
me.itemBorderLeft = parseInt(div.css('border-left-width'));
|
||||
me.itemBorderRight = parseInt(div.css('border-right-width'));
|
||||
}
|
||||
}
|
||||
|
||||
me.fieldPicker.store.reset([]); // remove all
|
||||
|
||||
var indexRec = store.indexOf(record),
|
||||
countRec = store.length,
|
||||
maxViewCount = Math.floor((fieldPickerEl.width()) / (me.itemWidth + (me.itemMarginLeft || 0) + (me.itemMarginRight || 0) + (me.itemPaddingLeft || 0) + (me.itemPaddingRight || 0) +
|
||||
(me.itemBorderLeft || 0) + (me.itemBorderRight || 0))),
|
||||
newStyles = [];
|
||||
|
||||
if (fieldPickerEl.height() / me.itemHeight > 2)
|
||||
maxViewCount *= Math.floor(fieldPickerEl.height() / me.itemHeight);
|
||||
|
||||
if (indexRec < 0)
|
||||
return;
|
||||
|
||||
indexRec = Math.floor(indexRec / maxViewCount) * maxViewCount;
|
||||
if (countRec - indexRec < maxViewCount)
|
||||
indexRec = Math.max(countRec - maxViewCount, 0);
|
||||
for (var index = indexRec, viewCount = 0; index < countRec && viewCount < maxViewCount; index++, viewCount++) {
|
||||
newStyles.push(store.at(index));
|
||||
}
|
||||
|
||||
me.fieldPicker.store.add(newStyles);
|
||||
}
|
||||
|
||||
if (forceSelect) {
|
||||
var selectRecord = me.fieldPicker.store.findWhere({'id': record.get('id')});
|
||||
if (selectRecord){
|
||||
me.suspendEvents();
|
||||
me.fieldPicker.selectRecord(selectRecord, true);
|
||||
me.resumeEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
selectByIndex: function(index) {
|
||||
if (index < 0)
|
||||
this.fieldPicker.deselectAll();
|
||||
|
||||
this.menuPicker.selectByIndex(index);
|
||||
},
|
||||
|
||||
setItemWidth: function(width) {
|
||||
if (this.itemWidth != width)
|
||||
this.itemWidth = window.devicePixelRatio > 1 ? width / 2 : width;
|
||||
},
|
||||
|
||||
setItemHeight: function(height) {
|
||||
if (this.itemHeight != height)
|
||||
this.itemHeight = window.devicePixelRatio > 1 ? height / 2 : height;
|
||||
},
|
||||
|
||||
removeTips: function() {
|
||||
var picker = this.menuPicker;
|
||||
_.each(picker.dataViewItems, function(item) {
|
||||
var tip = item.$el.data('bs.tooltip');
|
||||
if (tip) (tip.tip()).remove();
|
||||
}, picker);
|
||||
}
|
||||
})
|
||||
});
|
||||
722
apps/common/main/lib/component/DataView.js
Normal file
722
apps/common/main/lib/component/DataView.js
Normal file
|
|
@ -0,0 +1,722 @@
|
|||
/**
|
||||
* DataView.js
|
||||
*
|
||||
* A mechanism for displaying data using custom layout templates and formatting.
|
||||
*
|
||||
* Created by Alexander Yuzhin on 1/24/14
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The View uses an template as its internal templating mechanism, and is bound to an
|
||||
* {@link Common.UI.DataViewStore} so that as the data in the store changes the view is automatically updated
|
||||
* to reflect the changes.
|
||||
*
|
||||
* The example below binds a View to a {@link Common.UI.DataViewStore} and renders it into an el.
|
||||
*
|
||||
* new Common.UI.DataView({
|
||||
* el: $('#id'),
|
||||
* store: new Common.UI.DataViewStore([{value: 1, value: 2}]),
|
||||
* itemTemplate: _.template(['<li id="<%= id %>"><a href="#"><%= value %></a></li>'].join(''))
|
||||
* });
|
||||
*
|
||||
*
|
||||
* @property {Object} el
|
||||
* Backbone el
|
||||
*
|
||||
*
|
||||
* @property {Object} store
|
||||
* The Store class encapsulates a client side cache of Model objects.
|
||||
*
|
||||
*
|
||||
* @property {String} emptyText
|
||||
* The text to display in the view when there is no data to display.
|
||||
*
|
||||
*
|
||||
* @cfg {Object} itemTemplate
|
||||
* The inner portion of the item template to be rendered.
|
||||
*
|
||||
*/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
define([
|
||||
'common/main/lib/component/BaseView',
|
||||
'common/main/lib/component/Scroller'
|
||||
], function () {
|
||||
'use strict';
|
||||
|
||||
Common.UI.DataViewGroupModel = Backbone.Model.extend({
|
||||
defaults: function() {
|
||||
return {
|
||||
id: Common.UI.getId(),
|
||||
caption: ''
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Common.UI.DataViewGroupStore = Backbone.Collection.extend({
|
||||
model: Common.UI.DataViewGroupModel
|
||||
});
|
||||
|
||||
Common.UI.DataViewModel = Backbone.Model.extend({
|
||||
defaults: function() {
|
||||
return {
|
||||
id: Common.UI.getId(),
|
||||
selected: false,
|
||||
allowSelected: true,
|
||||
value: null
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Common.UI.DataViewStore = Backbone.Collection.extend({
|
||||
model: Common.UI.DataViewModel
|
||||
});
|
||||
|
||||
Common.UI.DataViewItem = Common.UI.BaseView.extend({
|
||||
options : {
|
||||
},
|
||||
|
||||
template: _.template([
|
||||
'<div id="<%= id %>"><%= value %></div>'
|
||||
].join('')),
|
||||
|
||||
initialize : function(options) {
|
||||
Common.UI.BaseView.prototype.initialize.call(this, options);
|
||||
|
||||
var me = this;
|
||||
|
||||
me.template = me.options.template || me.template;
|
||||
|
||||
me.listenTo(me.model, 'change', me.render);
|
||||
me.listenTo(me.model, 'change:selected', me.onSelectChange);
|
||||
me.listenTo(me.model, 'remove', me.remove);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
if (_.isUndefined(this.model.id))
|
||||
return this;
|
||||
|
||||
var el = $(this.el);
|
||||
|
||||
el.html(this.template(this.model.toJSON()));
|
||||
el.addClass('item');
|
||||
el.toggleClass('selected', this.model.get('selected') && this.model.get('allowSelected'));
|
||||
el.off('click').on('click', _.bind(this.onClick, this));
|
||||
el.off('dblclick').on('dblclick', _.bind(this.onDblClick, this));
|
||||
el.off('contextmenu').on('contextmenu', _.bind(this.onContextMenu, this));
|
||||
|
||||
if (!_.isUndefined(this.model.get('cls')))
|
||||
el.addClass(this.model.get('cls'));
|
||||
|
||||
this.trigger('change', this, this.model);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
remove: function() {
|
||||
this.stopListening(this.model);
|
||||
this.trigger('remove', this, this.model);
|
||||
|
||||
Common.UI.BaseView.prototype.remove.call(this);
|
||||
},
|
||||
|
||||
onClick: function(e) {
|
||||
this.trigger('click', this, this.model, e);
|
||||
},
|
||||
|
||||
onDblClick: function(e) {
|
||||
this.trigger('dblclick', this, this.model, e);
|
||||
},
|
||||
|
||||
onContextMenu: function(e) {
|
||||
this.trigger('contextmenu', this, this.model, e);
|
||||
},
|
||||
|
||||
onSelectChange: function(model, selected) {
|
||||
this.trigger('select', this, model, selected);
|
||||
}
|
||||
});
|
||||
|
||||
Common.UI.DataView = Common.UI.BaseView.extend({
|
||||
options : {
|
||||
multiSelect: false,
|
||||
handleSelect: true,
|
||||
enableKeyEvents: true,
|
||||
keyMoveDirection: 'both', // 'vertical', 'horizontal'
|
||||
restoreHeight: 0,
|
||||
emptyText: '',
|
||||
listenStoreEvents: true,
|
||||
allowScrollbar: true,
|
||||
showLast: true,
|
||||
useBSKeydown: false
|
||||
},
|
||||
|
||||
template: _.template([
|
||||
'<div class="dataview inner" style="<%= style %>">',
|
||||
'<% _.each(groups, function(group) { %>',
|
||||
'<div class="grouped-data" id="<%= group.id %>">',
|
||||
'<div class="group-description">',
|
||||
'<span><b><%= group.caption %></b></span>',
|
||||
'</div>',
|
||||
'<div class="group-items-container">',
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<% }); %>',
|
||||
'</div>'
|
||||
].join('')),
|
||||
|
||||
initialize : function(options) {
|
||||
Common.UI.BaseView.prototype.initialize.call(this, options);
|
||||
|
||||
var me = this;
|
||||
|
||||
me.template = me.options.template || me.template;
|
||||
me.store = me.options.store || new Common.UI.DataViewStore();
|
||||
me.groups = me.options.groups || null;
|
||||
me.itemTemplate = me.options.itemTemplate || null;
|
||||
me.multiSelect = me.options.multiSelect;
|
||||
me.handleSelect = me.options.handleSelect;
|
||||
me.parentMenu = me.options.parentMenu;
|
||||
me.enableKeyEvents= me.options.enableKeyEvents;
|
||||
me.useBSKeydown = me.options.useBSKeydown; // only with enableKeyEvents && parentMenu
|
||||
me.showLast = me.options.showLast;
|
||||
me.style = me.options.style || '';
|
||||
me.emptyText = me.options.emptyText || '';
|
||||
me.listenStoreEvents= (me.options.listenStoreEvents!==undefined) ? me.options.listenStoreEvents : true;
|
||||
me.allowScrollbar = (me.options.allowScrollbar!==undefined) ? me.options.allowScrollbar : true;
|
||||
me.rendered = false;
|
||||
me.dataViewItems = [];
|
||||
if (me.options.keyMoveDirection=='vertical')
|
||||
me.moveKeys = [Common.UI.Keys.UP, Common.UI.Keys.DOWN];
|
||||
else if (me.options.keyMoveDirection=='horizontal')
|
||||
me.moveKeys = [Common.UI.Keys.LEFT, Common.UI.Keys.RIGHT];
|
||||
else
|
||||
me.moveKeys = [Common.UI.Keys.UP, Common.UI.Keys.DOWN, Common.UI.Keys.LEFT, Common.UI.Keys.RIGHT];
|
||||
|
||||
if (me.options.el)
|
||||
me.render();
|
||||
},
|
||||
|
||||
render: function (parentEl) {
|
||||
var me = this;
|
||||
|
||||
this.trigger('render:before', this);
|
||||
|
||||
this.cmpEl = $(this.el);
|
||||
if (parentEl) {
|
||||
this.setElement(parentEl, false);
|
||||
this.cmpEl = $(this.template({
|
||||
groups: me.groups ? me.groups.toJSON() : null,
|
||||
style: me.style
|
||||
}));
|
||||
|
||||
parentEl.html(this.cmpEl);
|
||||
} else {
|
||||
this.cmpEl.html(this.template({
|
||||
groups: me.groups ? me.groups.toJSON() : null,
|
||||
style: me.style
|
||||
}));
|
||||
}
|
||||
|
||||
if (!this.rendered) {
|
||||
if (this.listenStoreEvents) {
|
||||
this.listenTo(this.store, 'add', this.onAddItem);
|
||||
this.listenTo(this.store, 'reset', this.onResetItems);
|
||||
}
|
||||
this.onResetItems();
|
||||
|
||||
if (this.parentMenu) {
|
||||
this.cmpEl.closest('li').css('height', '100%');
|
||||
this.cmpEl.css('height', '100%');
|
||||
this.parentMenu.on('show:after', _.bind(this.alignPosition, this));
|
||||
}
|
||||
|
||||
if (this.enableKeyEvents && this.parentMenu && this.handleSelect) {
|
||||
if (!me.showLast)
|
||||
this.parentMenu.on('show:before', function(menu) { me.deselectAll(); });
|
||||
this.parentMenu.on('show:after', function(menu) {
|
||||
if (me.showLast) me.showLastSelected();
|
||||
Common.NotificationCenter.trigger('dataview:focus');
|
||||
_.delay(function() {
|
||||
menu.cmpEl.find('.dataview').focus();
|
||||
}, 10);
|
||||
}).on('hide:after', function() {
|
||||
Common.NotificationCenter.trigger('dataview:blur');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (_.isUndefined(this.scroller) && this.allowScrollbar) {
|
||||
this.scroller = new Common.UI.Scroller({
|
||||
el: $(this.el).find('.inner').andSelf().filter('.inner'),
|
||||
useKeyboard: this.enableKeyEvents && !this.handleSelect,
|
||||
minScrollbarLength : 40,
|
||||
wheelSpeed: 10
|
||||
});
|
||||
}
|
||||
|
||||
var modalParents = this.cmpEl.closest('.asc-window');
|
||||
if (modalParents.length > 0) {
|
||||
this.tipZIndex = parseInt(modalParents.css('z-index')) + 10;
|
||||
}
|
||||
|
||||
this.rendered = true;
|
||||
|
||||
this.cmpEl.on('click', function(e){
|
||||
if (/dataview/.test(e.target.className)) return false;
|
||||
});
|
||||
|
||||
this.trigger('render:after', this);
|
||||
return this;
|
||||
},
|
||||
|
||||
setStore: function(store) {
|
||||
if (store) {
|
||||
this.stopListening(this.store);
|
||||
|
||||
this.store = store;
|
||||
|
||||
if (this.listenStoreEvents) {
|
||||
this.listenTo(this.store, 'add', this.onAddItem);
|
||||
this.listenTo(this.store, 'reset', this.onResetItems);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
selectRecord: function(record, suspendEvents) {
|
||||
if (!this.handleSelect)
|
||||
return;
|
||||
|
||||
if (suspendEvents)
|
||||
this.suspendEvents();
|
||||
|
||||
if (!this.multiSelect) {
|
||||
_.each(this.store.where({selected: true}), function(rec){
|
||||
rec.set({selected: false});
|
||||
});
|
||||
|
||||
if (record)
|
||||
record.set({selected: true});
|
||||
} else {
|
||||
if (record)
|
||||
record.set({selected: !record.get('selected')});
|
||||
}
|
||||
|
||||
if (suspendEvents)
|
||||
this.resumeEvents();
|
||||
},
|
||||
|
||||
selectByIndex: function(index, suspendEvents) {
|
||||
if (this.store.length > 0 && index > -1 && index < this.store.length) {
|
||||
this.selectRecord(this.store.at(index), suspendEvents);
|
||||
}
|
||||
},
|
||||
|
||||
deselectAll: function(suspendEvents) {
|
||||
if (suspendEvents)
|
||||
this.suspendEvents();
|
||||
|
||||
_.each(this.store.where({selected: true}), function(record){
|
||||
record.set({selected: false});
|
||||
});
|
||||
|
||||
if (suspendEvents)
|
||||
this.resumeEvents();
|
||||
},
|
||||
|
||||
getSelectedRec: function() {
|
||||
if (this.multiSelect) {
|
||||
|
||||
var items = [];
|
||||
_.each(this.store.where({selected: true}), function(rec){
|
||||
items.push(rec);
|
||||
});
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
return this.store.where({selected: true});
|
||||
},
|
||||
|
||||
onAddItem: function(record, index, opts) {
|
||||
var view = new Common.UI.DataViewItem({
|
||||
template: this.itemTemplate,
|
||||
model: record
|
||||
});
|
||||
|
||||
if (view) {
|
||||
var innerEl = $(this.el).find('.inner').andSelf().filter('.inner');
|
||||
|
||||
if (this.groups && this.groups.length > 0) {
|
||||
var group = this.groups.findWhere({id: record.get('group')});
|
||||
|
||||
if (group) {
|
||||
innerEl = innerEl.find('#' + group.id + ' ' + '.group-items-container');
|
||||
}
|
||||
}
|
||||
|
||||
if (innerEl) {
|
||||
if (opts && opts.at == 0)
|
||||
innerEl.prepend(view.render().el); else
|
||||
innerEl.append(view.render().el);
|
||||
|
||||
innerEl.find('.empty-text').remove();
|
||||
this.dataViewItems.push(view);
|
||||
|
||||
if (record.get('tip')) {
|
||||
var view_el = $(view.el);
|
||||
view_el.attr('data-toggle', 'tooltip');
|
||||
view_el.tooltip({
|
||||
title : record.get('tip'),
|
||||
placement : 'cursor',
|
||||
zIndex : this.tipZIndex
|
||||
});
|
||||
}
|
||||
|
||||
this.listenTo(view, 'change', this.onChangeItem);
|
||||
this.listenTo(view, 'remove', this.onRemoveItem);
|
||||
this.listenTo(view, 'click', this.onClickItem);
|
||||
this.listenTo(view, 'dblclick', this.onDblClickItem);
|
||||
this.listenTo(view, 'select', this.onSelectItem);
|
||||
this.listenTo(view, 'contextmenu', this.onContextMenuItem);
|
||||
|
||||
if (!this.isSuspendEvents)
|
||||
this.trigger('item:add', this, view, record);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onResetItems: function() {
|
||||
_.each(this.dataViewItems, function(item) {
|
||||
var tip = item.$el.data('bs.tooltip');
|
||||
if (tip) (tip.tip()).remove();
|
||||
}, this);
|
||||
|
||||
$(this.el).html(this.template({
|
||||
groups: this.groups ? this.groups.toJSON() : null,
|
||||
style: this.style
|
||||
}));
|
||||
|
||||
if (!_.isUndefined(this.scroller)) {
|
||||
this.scroller.destroy();
|
||||
delete this.scroller;
|
||||
}
|
||||
|
||||
if (this.store.length < 1 && this.emptyText.length > 0)
|
||||
$(this.el).find('.inner').andSelf().filter('.inner').append('<table cellpadding="10" class="empty-text"><tr><td>' + this.emptyText + '</td></tr></table>');
|
||||
|
||||
_.each(this.dataViewItems, function(item) {
|
||||
this.stopListening(item);
|
||||
item.stopListening(item.model);
|
||||
}, this);
|
||||
this.dataViewItems = [];
|
||||
|
||||
this.store.each(this.onAddItem, this);
|
||||
|
||||
if (this.allowScrollbar) {
|
||||
this.scroller = new Common.UI.Scroller({
|
||||
el: $(this.el).find('.inner').andSelf().filter('.inner'),
|
||||
useKeyboard: this.enableKeyEvents && !this.handleSelect,
|
||||
minScrollbarLength : 40,
|
||||
wheelSpeed: 10
|
||||
});
|
||||
}
|
||||
|
||||
this.attachKeyEvents();
|
||||
this.lastSelectedRec = null;
|
||||
this._layoutParams = undefined;
|
||||
},
|
||||
|
||||
onChangeItem: function(view, record) {
|
||||
if (!this.isSuspendEvents) {
|
||||
this.trigger('item:change', this, view, record);
|
||||
}
|
||||
},
|
||||
|
||||
onRemoveItem: function(view, record) {
|
||||
this.stopListening(view);
|
||||
view.stopListening();
|
||||
|
||||
if (this.store.length < 1 && this.emptyText.length > 0) {
|
||||
var el = $(this.el).find('.inner').andSelf().filter('.inner');
|
||||
if ( el.find('.empty-text').length<=0 )
|
||||
el.append('<table cellpadding="10" class="empty-text"><tr><td>' + this.emptyText + '</td></tr></table>');
|
||||
}
|
||||
|
||||
for (var i=0; i < this.dataViewItems.length; i++) {
|
||||
if (_.isEqual(view, this.dataViewItems[i]) ) {
|
||||
this.dataViewItems.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.isSuspendEvents) {
|
||||
this.trigger('item:remove', this, view, record);
|
||||
}
|
||||
},
|
||||
|
||||
onClickItem: function(view, record, e) {
|
||||
if ( this.disabled ) return;
|
||||
|
||||
window._event = e; // for FireFox only
|
||||
|
||||
if (this.showLast) this.selectRecord(record);
|
||||
this.lastSelectedRec = null;
|
||||
|
||||
var tip = view.$el.data('bs.tooltip');
|
||||
if (tip) (tip.tip()).remove();
|
||||
|
||||
if (!this.isSuspendEvents) {
|
||||
this.trigger('item:click', this, view, record, e);
|
||||
}
|
||||
},
|
||||
|
||||
onDblClickItem: function(view, record, e) {
|
||||
if ( this.disabled ) return;
|
||||
|
||||
window._event = e; // for FireFox only
|
||||
|
||||
this.selectRecord(record);
|
||||
this.lastSelectedRec = null;
|
||||
|
||||
if (!this.isSuspendEvents) {
|
||||
this.trigger('item:dblclick', this, view, record, e);
|
||||
}
|
||||
},
|
||||
|
||||
onSelectItem: function(view, record, selected) {
|
||||
if (!this.isSuspendEvents) {
|
||||
this.trigger(selected ? 'item:select' : 'item:deselect', this, view, record, this._fromKeyDown);
|
||||
}
|
||||
},
|
||||
|
||||
onContextMenuItem: function(view, record, e) {
|
||||
if (!this.isSuspendEvents) {
|
||||
this.trigger('item:contextmenu', this, view, record, e);
|
||||
}
|
||||
},
|
||||
|
||||
scrollToRecord: function (record) {
|
||||
var innerEl = $(this.el).find('.inner'),
|
||||
inner_top = innerEl.offset().top,
|
||||
idx = _.indexOf(this.store.models, record),
|
||||
div = (idx>=0) ? $(this.dataViewItems[idx].el) : innerEl.find('#' + record.get('id'));
|
||||
if (div.length<=0) return;
|
||||
|
||||
var div_top = div.offset().top;
|
||||
if (div_top < inner_top || div_top+div.outerHeight() > inner_top + innerEl.height()) {
|
||||
if (this.scroller && this.allowScrollbar) {
|
||||
this.scroller.scrollTop(innerEl.scrollTop() + div_top - inner_top, 0);
|
||||
} else {
|
||||
innerEl.scrollTop(innerEl.scrollTop() + div_top - inner_top);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onKeyDown: function (e, data) {
|
||||
if ( this.disabled ) return;
|
||||
if (data===undefined) data = e;
|
||||
if (_.indexOf(this.moveKeys, data.keyCode)>-1 || data.keyCode==Common.UI.Keys.RETURN) {
|
||||
data.preventDefault();
|
||||
data.stopPropagation();
|
||||
var rec = this.getSelectedRec()[0];
|
||||
if (this.lastSelectedRec===null)
|
||||
this.lastSelectedRec = rec;
|
||||
if (data.keyCode==Common.UI.Keys.RETURN) {
|
||||
this.lastSelectedRec = null;
|
||||
if (this.selectedBeforeHideRec) // only for ComboDataView menuPicker
|
||||
rec = this.selectedBeforeHideRec;
|
||||
this.trigger('item:click', this, this, rec, e);
|
||||
this.trigger('item:select', this, this, rec, e);
|
||||
this.trigger('entervalue', this, rec, e);
|
||||
if (this.parentMenu)
|
||||
this.parentMenu.hide();
|
||||
} else {
|
||||
var idx = _.indexOf(this.store.models, rec);
|
||||
if (idx<0) {
|
||||
if (data.keyCode==Common.UI.Keys.LEFT) {
|
||||
var target = $(e.target).closest('.dropdown-submenu.over');
|
||||
if (target.length>0) {
|
||||
target.removeClass('over');
|
||||
target.find('> a').focus();
|
||||
} else
|
||||
idx = 0;
|
||||
} else
|
||||
idx = 0;
|
||||
} else if (this.options.keyMoveDirection == 'both') {
|
||||
if (this._layoutParams === undefined)
|
||||
this.fillIndexesArray();
|
||||
var topIdx = this.dataViewItems[idx].topIdx,
|
||||
leftIdx = this.dataViewItems[idx].leftIdx;
|
||||
|
||||
idx = undefined;
|
||||
if (data.keyCode==Common.UI.Keys.LEFT) {
|
||||
while (idx===undefined) {
|
||||
leftIdx--;
|
||||
if (leftIdx<0) {
|
||||
var target = $(e.target).closest('.dropdown-submenu.over');
|
||||
if (target.length>0) {
|
||||
target.removeClass('over');
|
||||
target.find('> a').focus();
|
||||
break;
|
||||
} else
|
||||
leftIdx = this._layoutParams.columns-1;
|
||||
}
|
||||
idx = this._layoutParams.itemsIndexes[topIdx][leftIdx];
|
||||
}
|
||||
} else if (data.keyCode==Common.UI.Keys.RIGHT) {
|
||||
while (idx===undefined) {
|
||||
leftIdx++;
|
||||
if (leftIdx>this._layoutParams.columns-1) leftIdx = 0;
|
||||
idx = this._layoutParams.itemsIndexes[topIdx][leftIdx];
|
||||
}
|
||||
} else if (data.keyCode==Common.UI.Keys.UP) {
|
||||
while (idx===undefined) {
|
||||
topIdx--;
|
||||
if (topIdx<0) topIdx = this._layoutParams.rows-1;
|
||||
idx = this._layoutParams.itemsIndexes[topIdx][leftIdx];
|
||||
}
|
||||
} else {
|
||||
while (idx===undefined) {
|
||||
topIdx++;
|
||||
if (topIdx>this._layoutParams.rows-1) topIdx = 0;
|
||||
idx = this._layoutParams.itemsIndexes[topIdx][leftIdx];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
idx = (data.keyCode==Common.UI.Keys.UP || data.keyCode==Common.UI.Keys.LEFT)
|
||||
? Math.max(0, idx-1)
|
||||
: Math.min(this.store.length - 1, idx + 1) ;
|
||||
}
|
||||
|
||||
if (idx !== undefined && idx>=0) rec = this.store.at(idx);
|
||||
if (rec) {
|
||||
this._fromKeyDown = true;
|
||||
this.selectRecord(rec);
|
||||
this._fromKeyDown = false;
|
||||
this.scrollToRecord(rec);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.trigger('item:keydown', this, rec, e);
|
||||
}
|
||||
},
|
||||
|
||||
attachKeyEvents: function() {
|
||||
if (this.enableKeyEvents && this.handleSelect) {
|
||||
var el = $(this.el).find('.inner').andSelf().filter('.inner');
|
||||
el.addClass('canfocused');
|
||||
el.attr('tabindex', '0');
|
||||
el.on((this.parentMenu && this.useBSKeydown) ? 'dataview:keydown' : 'keydown', _.bind(this.onKeyDown, this));
|
||||
}
|
||||
},
|
||||
|
||||
showLastSelected: function() {
|
||||
if ( this.lastSelectedRec) {
|
||||
this.selectRecord(this.lastSelectedRec, true);
|
||||
this.scrollToRecord(this.lastSelectedRec);
|
||||
this.lastSelectedRec = null;
|
||||
} else {
|
||||
var rec = this.getSelectedRec()[0];
|
||||
if (rec) this.scrollToRecord(rec);
|
||||
}
|
||||
},
|
||||
|
||||
setDisabled: function(disabled) {
|
||||
this.disabled = disabled;
|
||||
$(this.el).find('.inner').andSelf().filter('.inner').toggleClass('disabled', disabled);
|
||||
},
|
||||
|
||||
isDisabled: function() {
|
||||
return this.disabled;
|
||||
},
|
||||
|
||||
setEmptyText: function(emptyText) {
|
||||
this.emptyText = emptyText;
|
||||
},
|
||||
|
||||
alignPosition: function() {
|
||||
var menuRoot = (this.parentMenu.cmpEl.attr('role') === 'menu')
|
||||
? this.parentMenu.cmpEl
|
||||
: this.parentMenu.cmpEl.find('[role=menu]'),
|
||||
innerEl = $(this.el).find('.inner').andSelf().filter('.inner'),
|
||||
docH = $(document).height(),
|
||||
menuH = menuRoot.outerHeight(),
|
||||
top = parseInt(menuRoot.css('top'));
|
||||
|
||||
if (menuH > docH) {
|
||||
innerEl.css('max-height', (docH - parseInt(menuRoot.css('padding-top')) - parseInt(menuRoot.css('padding-bottom'))-5) + 'px');
|
||||
if (this.allowScrollbar) this.scroller.update({minScrollbarLength : 40});
|
||||
} else if ( innerEl.height() < this.options.restoreHeight ) {
|
||||
innerEl.css('max-height', (Math.min(docH - parseInt(menuRoot.css('padding-top')) - parseInt(menuRoot.css('padding-bottom'))-5, this.options.restoreHeight)) + 'px');
|
||||
menuH = menuRoot.outerHeight();
|
||||
if (top+menuH > docH) {
|
||||
menuRoot.css('top', 0);
|
||||
}
|
||||
if (this.allowScrollbar) this.scroller.update({minScrollbarLength : 40});
|
||||
}
|
||||
},
|
||||
|
||||
fillIndexesArray: function() {
|
||||
if (this.dataViewItems.length<=0) return;
|
||||
|
||||
var top, left,
|
||||
el = $(this.dataViewItems[0].el),
|
||||
itemW = el.outerWidth() + parseInt(el.css('margin-left')) + parseInt(el.css('margin-right')),
|
||||
itemH = el.outerHeight() + parseInt(el.css('margin-top')) + parseInt(el.css('margin-bottom')),
|
||||
offsetLeft = this.$el.offset().left,
|
||||
offsetTop = this.$el.offset().top,
|
||||
idxOffset = 0;
|
||||
|
||||
this._layoutParams = {
|
||||
itemsIndexes: [],
|
||||
columns: 0,
|
||||
rows: 0
|
||||
};
|
||||
|
||||
if (this.groups && this.groups.length > 0) {
|
||||
var group_desc = this.cmpEl.find('.group-description:first');
|
||||
if (group_desc.length>0)
|
||||
offsetLeft += group_desc.width();
|
||||
}
|
||||
for (var i=0; i<this.dataViewItems.length; i++) {
|
||||
top = Math.floor(($(this.dataViewItems[i].el).offset().top - offsetTop)/itemH) + idxOffset;
|
||||
left = Math.floor(($(this.dataViewItems[i].el).offset().left - offsetLeft)/itemW);
|
||||
if (top<0) {
|
||||
idxOffset = -top;
|
||||
top += idxOffset;
|
||||
}
|
||||
if (top > this._layoutParams.itemsIndexes.length-1) {
|
||||
this._layoutParams.itemsIndexes.push([]);
|
||||
}
|
||||
this._layoutParams.itemsIndexes[top][left] = i;
|
||||
this.dataViewItems[i].topIdx = top;
|
||||
this.dataViewItems[i].leftIdx = left;
|
||||
if (this._layoutParams.columns<left) this._layoutParams.columns = left;
|
||||
}
|
||||
this._layoutParams.rows = this._layoutParams.itemsIndexes.length;
|
||||
this._layoutParams.columns++;
|
||||
},
|
||||
|
||||
onResize: function() {
|
||||
this._layoutParams = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('keydown.dataview', '[data-toggle=dropdown], [role=menu]', function(e) {
|
||||
if (e.keyCode !== Common.UI.Keys.UP && e.keyCode !== Common.UI.Keys.DOWN && e.keyCode !== Common.UI.Keys.LEFT && e.keyCode !== Common.UI.Keys.RIGHT && e.keyCode !== Common.UI.Keys.RETURN) return;
|
||||
|
||||
_.defer(function(){
|
||||
var target = $(e.target).closest('.dropdown-toggle');
|
||||
if (target.length)
|
||||
target.parent().find('.inner.canfocused').trigger('dataview:keydown', e);
|
||||
else {
|
||||
$(e.target).closest('.dropdown-submenu').find('.inner.canfocused').trigger('dataview:keydown', e);
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
148
apps/common/main/lib/component/DimensionPicker.js
Normal file
148
apps/common/main/lib/component/DimensionPicker.js
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/**
|
||||
* DimensionPicker.js
|
||||
*
|
||||
* Created by Alexander Yuzhin on 1/29/14
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
define([
|
||||
'common/main/lib/component/BaseView'
|
||||
], function () {
|
||||
'use strict';
|
||||
|
||||
Common.UI.DimensionPicker = Common.UI.BaseView.extend((function(){
|
||||
var me,
|
||||
rootEl,
|
||||
areaMouseCatcher,
|
||||
areaUnHighLighted,
|
||||
areaHighLighted,
|
||||
areaStatus,
|
||||
curColumns = 0,
|
||||
curRows = 0;
|
||||
|
||||
var onMouseMove = function(event){
|
||||
me.setTableSize(
|
||||
Math.ceil((event.offsetX === undefined ? event.originalEvent.layerX : event.offsetX) / me.itemSize),
|
||||
Math.ceil((event.offsetY === undefined ? event.originalEvent.layerY : event.offsetY) / me.itemSize),
|
||||
event
|
||||
);
|
||||
};
|
||||
|
||||
var onMouseLeave = function(event){
|
||||
me.setTableSize(0, 0, event);
|
||||
};
|
||||
|
||||
var onHighLightedMouseClick = function(e){
|
||||
me.trigger('select', me, curColumns, curRows, e);
|
||||
};
|
||||
|
||||
return {
|
||||
options: {
|
||||
itemSize : 18,
|
||||
minRows : 5,
|
||||
minColumns : 5,
|
||||
maxRows : 20,
|
||||
maxColumns : 20
|
||||
},
|
||||
|
||||
template:_.template([
|
||||
'<div style="width: 100%; height: 100%;">',
|
||||
'<div class="dimension-picker-status">0x0</div>',
|
||||
'<div class="dimension-picker-observecontainer">',
|
||||
'<div class="dimension-picker-mousecatcher"></div>',
|
||||
'<div class="dimension-picker-unhighlighted"></div>',
|
||||
'<div class="dimension-picker-highlighted"></div>',
|
||||
'</div>',
|
||||
'</div>'
|
||||
].join('')),
|
||||
|
||||
initialize : function(options) {
|
||||
Common.UI.BaseView.prototype.initialize.call(this, options);
|
||||
|
||||
me = this;
|
||||
|
||||
rootEl = $(this.el);
|
||||
|
||||
me.itemSize = me.options.itemSize;
|
||||
me.minRows = me.options.minRows;
|
||||
me.minColumns = me.options.minColumns;
|
||||
me.maxRows = me.options.maxRows;
|
||||
me.maxColumns = me.options.maxColumns;
|
||||
|
||||
this.render();
|
||||
|
||||
if (rootEl){
|
||||
areaMouseCatcher = rootEl.find('.dimension-picker-mousecatcher');
|
||||
areaUnHighLighted = rootEl.find('.dimension-picker-unhighlighted');
|
||||
areaHighLighted = rootEl.find('.dimension-picker-highlighted');
|
||||
areaStatus = rootEl.find('.dimension-picker-status');
|
||||
|
||||
rootEl.css({width: me.minColumns + 'em'});
|
||||
areaMouseCatcher.css('z-index', 1);
|
||||
areaMouseCatcher.width(me.maxColumns + 'em').height(me.maxRows + 'em');
|
||||
areaUnHighLighted.width(me.minColumns + 'em').height(me.minRows + 'em');
|
||||
areaStatus.html(curColumns + ' x ' + curRows);
|
||||
areaStatus.width(areaUnHighLighted.width());
|
||||
}
|
||||
|
||||
areaMouseCatcher.on('mousemove', onMouseMove);
|
||||
areaHighLighted.on('mousemove', onMouseMove);
|
||||
areaUnHighLighted.on('mousemove', onMouseMove);
|
||||
areaMouseCatcher.on('mouseleave', onMouseLeave);
|
||||
areaHighLighted.on('mouseleave', onMouseLeave);
|
||||
areaUnHighLighted.on('mouseleave', onMouseLeave);
|
||||
areaMouseCatcher.on('click', onHighLightedMouseClick);
|
||||
areaHighLighted.on('click', onHighLightedMouseClick);
|
||||
areaUnHighLighted.on('click', onHighLightedMouseClick);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
$(this.el).html(this.template());
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
setTableSize: function(columns, rows, event){
|
||||
if (columns > this.maxColumns) columns = this.maxColumns;
|
||||
if (rows > this.maxRows) rows = this.maxRows;
|
||||
|
||||
if (curColumns != columns || curRows != rows){
|
||||
curColumns = columns;
|
||||
curRows = rows;
|
||||
|
||||
areaHighLighted.width(curColumns + 'em').height(curRows + 'em');
|
||||
areaUnHighLighted.width(
|
||||
((curColumns < me.minColumns)
|
||||
? me.minColumns
|
||||
: ((curColumns + 1 > me.maxColumns)
|
||||
? me.maxColumns
|
||||
: curColumns + 1)) + 'em'
|
||||
).height(((curRows < me.minRows)
|
||||
? me.minRows
|
||||
: ((curRows + 1 > me.maxRows)
|
||||
? me.maxRows
|
||||
: curRows + 1)) + 'em'
|
||||
);
|
||||
|
||||
rootEl.width(areaUnHighLighted.width());
|
||||
areaStatus.html(curColumns + ' x ' + curRows);
|
||||
areaStatus.width(areaUnHighLighted.width());
|
||||
|
||||
me.trigger('change', me, curColumns, curRows, event);
|
||||
}
|
||||
},
|
||||
|
||||
getColumnsCount: function() {
|
||||
return curColumns;
|
||||
},
|
||||
|
||||
getRowsCount: function() {
|
||||
return curRows;
|
||||
}
|
||||
}
|
||||
})())
|
||||
});
|
||||
258
apps/common/main/lib/component/HSBColorPicker.js
Normal file
258
apps/common/main/lib/component/HSBColorPicker.js
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
define([
|
||||
'common/main/lib/component/BaseView',
|
||||
'common/main/lib/util/utils'
|
||||
|
||||
], function () {
|
||||
'use strict';
|
||||
|
||||
Common.UI.HSBColorPicker = Common.UI.BaseView.extend({
|
||||
|
||||
template :
|
||||
_.template(
|
||||
'<div class="hsb-colorpicker">'+
|
||||
'<% if (this.showCurrentColor) { %>'+
|
||||
'<div class="top-panel">'+
|
||||
'<span class="color-value">'+
|
||||
'<span class="transparent-color img-colorpicker"></span>'+
|
||||
'</span>'+
|
||||
'<div class="color-text"></div>'+
|
||||
'</div>'+
|
||||
'<% } %>'+
|
||||
'<div>'+
|
||||
'<div class="cnt-hb img-colorpicker">'+
|
||||
'<div class="cnt-hb-arrow img-colorpicker"></div>'+
|
||||
'</div>'+
|
||||
'<% if (this.changeSaturation) { %>'+
|
||||
'<div class="cnt-root">'+
|
||||
'<div class="cnt-sat img-colorpicker">'+
|
||||
'<div class="cnt-sat-arrow img-colorpicker"></div>'+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
'<% } %>'+
|
||||
'</div>'+
|
||||
'<% if (this.allowEmptyColor) { %>'+
|
||||
'<div class="empty-color"><%= this.textNoColor %></div>'+
|
||||
'<% } %>'+
|
||||
'</div>'),
|
||||
|
||||
color: '#ff0000',
|
||||
|
||||
options: {
|
||||
allowEmptyColor: false,
|
||||
changeSaturation: true,
|
||||
showCurrentColor: true
|
||||
},
|
||||
|
||||
initialize : function(options) {
|
||||
Common.UI.BaseView.prototype.initialize.call(this, options);
|
||||
|
||||
var me = this,
|
||||
el = $(this.el),
|
||||
arrowSatBrightness, arrowHue,
|
||||
areaSatBrightness, areaHue,
|
||||
previewColor, previewTransparentColor, previewColorText,
|
||||
btnNoColor,
|
||||
hueVal = 0,
|
||||
saturationVal = 100,
|
||||
brightnessVal = 100;
|
||||
|
||||
|
||||
me.allowEmptyColor = me.options.allowEmptyColor;
|
||||
me.changeSaturation = me.options.changeSaturation;
|
||||
me.showCurrentColor = me.options.showCurrentColor;
|
||||
|
||||
|
||||
var onUpdateColor = function(hsb, transparent){
|
||||
var rgbColor = new Common.Utils.RGBColor('hsb(' + hsb.h + ',' + hsb.s + ',' + hsb.b + ')'),
|
||||
hexColor = rgbColor.toHex();
|
||||
|
||||
me.color = transparent ? 'transparent' : hexColor;
|
||||
|
||||
refreshUI();
|
||||
|
||||
me.trigger('changecolor', me, me.color);
|
||||
};
|
||||
|
||||
var refreshUI = function(){
|
||||
if (previewColor.length>0 && previewTransparentColor.length>0){
|
||||
if (me.color == 'transparent'){
|
||||
previewTransparentColor.show();
|
||||
} else {
|
||||
previewColor.css("background-color", me.color);
|
||||
previewTransparentColor.hide();
|
||||
}
|
||||
}
|
||||
|
||||
if (areaSatBrightness.length>0)
|
||||
areaSatBrightness.css('background-color', new Common.Utils.RGBColor('hsb('+hueVal+', 100, 100)').toHex());
|
||||
|
||||
if (previewColorText.length>0)
|
||||
previewColorText[0].innerHTML = (me.color == 'transparent') ? me.textNoColor : me.color.toUpperCase();
|
||||
|
||||
if (arrowSatBrightness.length>0 && arrowHue.length>0) {
|
||||
arrowSatBrightness.css('left', saturationVal + '%');
|
||||
arrowSatBrightness.css('top', 100 - brightnessVal + '%');
|
||||
arrowHue.css('top', parseInt(hueVal * 100 / 360.0) + '%');
|
||||
}
|
||||
};
|
||||
|
||||
var onSBAreaMouseMove = function(event, element, eOpts){
|
||||
if (arrowSatBrightness.length>0 && areaSatBrightness.length>0) {
|
||||
var pos = [
|
||||
Math.max(0, Math.min(100, (parseInt((event.pageX - areaSatBrightness.offset().left) / areaSatBrightness.width() * 100)))),
|
||||
Math.max(0, Math.min(100, (parseInt((event.pageY - areaSatBrightness.offset().top) / areaSatBrightness.height() * 100))))
|
||||
];
|
||||
|
||||
arrowSatBrightness.css('left', pos[0] + '%');
|
||||
arrowSatBrightness.css('top', pos[1] + '%');
|
||||
|
||||
saturationVal = pos[0];
|
||||
brightnessVal = 100 - pos[1];
|
||||
|
||||
onUpdateColor({
|
||||
h: hueVal,
|
||||
s: saturationVal,
|
||||
b: brightnessVal
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var onHueAreaMouseMove = function(event, element, eOpts){
|
||||
if (arrowHue&& areaHue) {
|
||||
var pos = Math.max(0, Math.min(100, (parseInt((event.pageY - areaHue.offset().top) / areaHue.height() * 100))));
|
||||
arrowHue.css('top', pos + '%');
|
||||
|
||||
hueVal = parseInt(360 * pos / 100.0);
|
||||
|
||||
onUpdateColor({
|
||||
h: hueVal,
|
||||
s: saturationVal,
|
||||
b: brightnessVal
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var onSBAreaMouseDown = function(event, element, eOpts){
|
||||
$(document).on('mouseup', onSBAreaMouseUp);
|
||||
$(document).on('mousemove', onSBAreaMouseMove);
|
||||
};
|
||||
|
||||
var onSBAreaMouseUp = function(event, element, eOpts){
|
||||
$(document).off('mouseup', onSBAreaMouseUp);
|
||||
$(document).off('mousemove', onSBAreaMouseMove);
|
||||
onSBAreaMouseMove(event, element, eOpts);
|
||||
};
|
||||
|
||||
var onHueAreaMouseDown = function(event, element, eOpts){
|
||||
$(document).on('mouseup', onHueAreaMouseUp);
|
||||
$(document).on('mousemove', onHueAreaMouseMove);
|
||||
onHueAreaMouseMove(event, element, eOpts);
|
||||
};
|
||||
|
||||
var onHueAreaMouseUp = function(event, element, eOpts){
|
||||
$(document).off('mouseup', onHueAreaMouseUp);
|
||||
$(document).off('mousemove', onHueAreaMouseMove);
|
||||
};
|
||||
|
||||
var onNoColorClick = function(cnt){
|
||||
var hsbColor = new Common.util.RGBColor(me.color).toHSB();
|
||||
|
||||
onUpdateColor(hsbColor, true);
|
||||
};
|
||||
|
||||
var onAfterRender = function(ct){
|
||||
var rootEl = $(me.el),
|
||||
hsbColor;
|
||||
|
||||
if (rootEl){
|
||||
arrowSatBrightness = rootEl.find('.cnt-hb-arrow');
|
||||
arrowHue = rootEl.find('.cnt-sat-arrow');
|
||||
areaSatBrightness = rootEl.find('.cnt-hb');
|
||||
areaHue = rootEl.find('.cnt-sat');
|
||||
previewColor = rootEl.find('.color-value');
|
||||
previewColorText = rootEl.find('.color-text');
|
||||
btnNoColor = rootEl.find('.empty-color');
|
||||
|
||||
if (previewColor.length>0){
|
||||
previewTransparentColor = previewColor.find('.transparent-color');
|
||||
}
|
||||
|
||||
if (areaSatBrightness.length>0) {
|
||||
areaSatBrightness.off('mousedown');
|
||||
areaSatBrightness.on('mousedown', onSBAreaMouseDown);
|
||||
}
|
||||
|
||||
if (areaHue.length>0) {
|
||||
areaHue.off('mousedown');
|
||||
areaHue.on('mousedown', onHueAreaMouseDown);
|
||||
}
|
||||
|
||||
if (btnNoColor.length>0) {
|
||||
btnNoColor.off('click');
|
||||
btnNoColor.on('click', onNoColorClick);
|
||||
}
|
||||
|
||||
if (me.color == 'transparent')
|
||||
hsbColor = {h: 0, s: 100, b: 100};
|
||||
else
|
||||
hsbColor = new Common.Utils.RGBColor(me.color).toHSB();
|
||||
|
||||
hueVal = hsbColor.h;
|
||||
saturationVal = hsbColor.s;
|
||||
brightnessVal = hsbColor.b;
|
||||
|
||||
if (hueVal == saturationVal &&
|
||||
hueVal == brightnessVal &&
|
||||
hueVal == 0)
|
||||
saturationVal = 100;
|
||||
|
||||
refreshUI();
|
||||
}
|
||||
};
|
||||
|
||||
me.setColor = function(value){
|
||||
if (me.color == value)
|
||||
return;
|
||||
|
||||
var hsbColor;
|
||||
if (value == 'transparent')
|
||||
hsbColor = {h: 0, s: 100, b: 100};
|
||||
else
|
||||
hsbColor = new Common.Utils.RGBColor(value).toHSB();
|
||||
|
||||
hueVal = hsbColor.h;
|
||||
saturationVal = hsbColor.s;
|
||||
brightnessVal = hsbColor.b;
|
||||
|
||||
if (hueVal == saturationVal &&
|
||||
hueVal == brightnessVal &&
|
||||
hueVal == 0)
|
||||
saturationVal = 100;
|
||||
|
||||
me.color = value;
|
||||
|
||||
refreshUI();
|
||||
};
|
||||
|
||||
me.getColor = function(){
|
||||
return me.color;
|
||||
};
|
||||
|
||||
me.on('render:after', onAfterRender);
|
||||
me.render();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
$(this.el).html(this.template());
|
||||
|
||||
this.trigger('render:after', this);
|
||||
return this;
|
||||
},
|
||||
|
||||
textNoColor: 'No Color'
|
||||
|
||||
});
|
||||
});
|
||||
343
apps/common/main/lib/component/InputField.js
Normal file
343
apps/common/main/lib/component/InputField.js
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
/**
|
||||
* InputField.js
|
||||
*
|
||||
* Created by Alexander Yuzhin on 4/10/14
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Using template
|
||||
*
|
||||
* <div class="input-field">
|
||||
* <input type="text" name="range" class="form-control"><span class="input-error"/>
|
||||
* </div>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
define([
|
||||
'common/main/lib/component/BaseView',
|
||||
'common/main/lib/component/Tooltip'
|
||||
], function () { 'use strict';
|
||||
|
||||
Common.UI.InputField = Common.UI.BaseView.extend((function() {
|
||||
return {
|
||||
options : {
|
||||
id : null,
|
||||
cls : '',
|
||||
style : '',
|
||||
value : '',
|
||||
type : 'text',
|
||||
name : '',
|
||||
validation : null,
|
||||
allowBlank : true,
|
||||
placeHolder : '',
|
||||
blankError : null,
|
||||
spellcheck : false,
|
||||
maskExp : '',
|
||||
validateOnChange: false,
|
||||
validateOnBlur: true,
|
||||
disabled: false
|
||||
},
|
||||
|
||||
template: _.template([
|
||||
'<div class="input-field" style="<%= style %>">',
|
||||
'<input ',
|
||||
'type="<%= type %>" ',
|
||||
'name="<%= name %>" ',
|
||||
'spellcheck="<%= spellcheck %>" ',
|
||||
'class="form-control <%= cls %>" ',
|
||||
'placeholder="<%= placeHolder %>" ',
|
||||
'value="<%= value %>"',
|
||||
'>',
|
||||
'<span class="input-error"/>',
|
||||
'</div>'
|
||||
].join('')),
|
||||
|
||||
initialize : function(options) {
|
||||
Common.UI.BaseView.prototype.initialize.call(this, options);
|
||||
|
||||
var me = this,
|
||||
el = $(this.el);
|
||||
|
||||
this.id = me.options.id || Common.UI.getId();
|
||||
this.cls = me.options.cls;
|
||||
this.style = me.options.style;
|
||||
this.value = me.options.value;
|
||||
this.type = me.options.type;
|
||||
this.name = me.options.name;
|
||||
this.validation = me.options.validation;
|
||||
this.allowBlank = me.options.allowBlank;
|
||||
this.placeHolder = me.options.placeHolder;
|
||||
this.template = me.options.template || me.template;
|
||||
this.editable = me.options.editable || true;
|
||||
this.disabled = me.options.disabled;
|
||||
this.spellcheck = me.options.spellcheck;
|
||||
this.blankError = me.options.blankError || 'This field is required';
|
||||
this.validateOnChange = me.options.validateOnChange;
|
||||
this.validateOnBlur = me.options.validateOnBlur;
|
||||
this.maxLength = me.options.maxLength;
|
||||
|
||||
me.rendered = me.options.rendered || false;
|
||||
|
||||
if (me.options.el) {
|
||||
me.render();
|
||||
}
|
||||
},
|
||||
|
||||
render : function(parentEl) {
|
||||
var me = this;
|
||||
|
||||
if (!me.rendered) {
|
||||
this.cmpEl = $(this.template({
|
||||
id : this.id,
|
||||
cls : this.cls,
|
||||
style : this.style,
|
||||
value : this.value,
|
||||
type : this.type,
|
||||
name : this.name,
|
||||
placeHolder : this.placeHolder,
|
||||
spellcheck : this.spellcheck,
|
||||
scope : me
|
||||
}));
|
||||
|
||||
if (parentEl) {
|
||||
this.setElement(parentEl, false);
|
||||
parentEl.html(this.cmpEl);
|
||||
} else {
|
||||
$(this.el).html(this.cmpEl);
|
||||
}
|
||||
} else {
|
||||
this.cmpEl = $(this.el);
|
||||
}
|
||||
|
||||
if (!me.rendered) {
|
||||
var el = this.cmpEl;
|
||||
|
||||
this._input = this.cmpEl.find('input').andSelf().filter('input');
|
||||
|
||||
if (this.editable) {
|
||||
this._input.on('blur', _.bind(this.onInputChanged, this));
|
||||
this._input.on('keypress', _.bind(this.onKeyPress, this));
|
||||
this._input.on('keyup', _.bind(this.onKeyUp, this));
|
||||
if (this.validateOnChange) this._input.on('input', _.bind(this.onInputChanging, this));
|
||||
if (this.maxLength) this._input.attr('maxlength', this.maxLength);
|
||||
}
|
||||
|
||||
this.setEditable(this.editable);
|
||||
if (this.disabled)
|
||||
this.setDisabled(this.disabled);
|
||||
|
||||
if (this._input.closest('.asc-window').length>0)
|
||||
var onModalClose = function() {
|
||||
var errorTip = el.find('.input-error').data('bs.tooltip');
|
||||
if (errorTip) errorTip.tip().remove();
|
||||
Common.NotificationCenter.off({'modal:close': onModalClose});
|
||||
};
|
||||
Common.NotificationCenter.on({'modal:close': onModalClose});
|
||||
}
|
||||
|
||||
me.rendered = true;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_doChange: function(e, extra) {
|
||||
// skip processing for internally-generated synthetic event
|
||||
// to avoid double processing
|
||||
if (extra && extra.synthetic)
|
||||
return;
|
||||
|
||||
var newValue = $(e.target).val(),
|
||||
oldValue = this.value;
|
||||
|
||||
this.trigger('changed:before', this, newValue, oldValue, e);
|
||||
|
||||
if (e.isDefaultPrevented())
|
||||
return;
|
||||
|
||||
this.value = newValue;
|
||||
if (this.validateOnBlur)
|
||||
this.checkValidate();
|
||||
|
||||
// trigger changed event
|
||||
this.trigger('changed:after', this, newValue, oldValue, e);
|
||||
},
|
||||
|
||||
onInputChanged: function(e, extra) {
|
||||
this._doChange(e, extra);
|
||||
},
|
||||
|
||||
onInputChanging: function(e, extra) {
|
||||
var newValue = $(e.target).val(),
|
||||
oldValue = this.value;
|
||||
|
||||
if (e.isDefaultPrevented())
|
||||
return;
|
||||
|
||||
this.value = newValue;
|
||||
if (this.validateOnBlur)
|
||||
this.checkValidate();
|
||||
|
||||
// trigger changing event
|
||||
this.trigger('changing', this, newValue, oldValue, e);
|
||||
},
|
||||
|
||||
onKeyPress: function(e) {
|
||||
this.trigger('keypress:before', this, e);
|
||||
|
||||
if (e.isDefaultPrevented())
|
||||
return;
|
||||
|
||||
if (e.keyCode === Common.UI.Keys.RETURN) {
|
||||
this._doChange(e);
|
||||
} else if (this.options.maskExp && !_.isEmpty(this.options.maskExp.source)){
|
||||
var charCode = String.fromCharCode(e.which);
|
||||
if(!this.options.maskExp.test(charCode) && !e.ctrlKey && e.keyCode !== Common.UI.Keys.DELETE && e.keyCode !== Common.UI.Keys.BACKSPACE &&
|
||||
e.keyCode !== Common.UI.Keys.LEFT && e.keyCode !== Common.UI.Keys.RIGHT && e.keyCode !== Common.UI.Keys.HOME &&
|
||||
e.keyCode !== Common.UI.Keys.END && e.keyCode !== Common.UI.Keys.ESC && e.keyCode !== Common.UI.Keys.INSERT ){
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
this.trigger('keypress:after', this, e);
|
||||
},
|
||||
|
||||
onKeyUp: function(e) {
|
||||
this.trigger('keyup:before', this, e);
|
||||
|
||||
if (e.isDefaultPrevented())
|
||||
return;
|
||||
|
||||
this.trigger('keyup:after', this, e);
|
||||
},
|
||||
|
||||
setEditable: function(editable) {
|
||||
var input = this._input;
|
||||
|
||||
this.editable = editable;
|
||||
|
||||
if (editable && input) {
|
||||
input.removeAttr('readonly');
|
||||
input.removeAttr('data-can-copy');
|
||||
} else {
|
||||
input.attr('readonly', 'readonly');
|
||||
input.attr('data-can-copy', false);
|
||||
}
|
||||
},
|
||||
|
||||
isEditable: function() {
|
||||
return this.editable;
|
||||
},
|
||||
|
||||
setDisabled: function(disabled) {
|
||||
this.disabled = disabled;
|
||||
$(this.el).toggleClass('disabled', disabled);
|
||||
disabled
|
||||
? this._input.attr('disabled', true)
|
||||
: this._input.removeAttr('disabled');
|
||||
},
|
||||
|
||||
isDisabled: function() {
|
||||
return this.disabled;
|
||||
},
|
||||
|
||||
setValue: function(value) {
|
||||
this.value = value;
|
||||
|
||||
if (this.rendered){
|
||||
this._input.val(value);
|
||||
}
|
||||
},
|
||||
|
||||
getValue: function() {
|
||||
return this.value;
|
||||
},
|
||||
|
||||
focus: function() {
|
||||
this._input.focus();
|
||||
},
|
||||
|
||||
checkValidate: function() {
|
||||
var me = this,
|
||||
errors = [];
|
||||
|
||||
if (!me.allowBlank && _.isEmpty(me.value)) {
|
||||
errors.push(me.blankError);
|
||||
}
|
||||
|
||||
if (_.isFunction(me.validation)) {
|
||||
var res = me.validation.call(me, me.value);
|
||||
|
||||
if (res !== true) {
|
||||
errors = _.flatten(errors.concat(res));
|
||||
}
|
||||
}
|
||||
|
||||
if (!_.isEmpty(errors)) {
|
||||
if (me.cmpEl.hasClass('error')) {
|
||||
var errorTip = me.cmpEl.find('.input-error').data('bs.tooltip');
|
||||
if (errorTip) {
|
||||
errorTip.options.title = errors.join('\n');
|
||||
errorTip.setContent();
|
||||
}
|
||||
return errors;
|
||||
} else {
|
||||
me.cmpEl.addClass('error');
|
||||
|
||||
var errorBadge = me.cmpEl.find('.input-error'),
|
||||
modalParents = errorBadge.closest('.asc-window'),
|
||||
errorTip = errorBadge.data('bs.tooltip');
|
||||
|
||||
if (errorTip) errorTip.tip().remove();
|
||||
errorBadge.attr('data-toggle', 'tooltip');
|
||||
errorBadge.removeData('bs.tooltip');
|
||||
errorBadge.tooltip({
|
||||
title : errors.join('\n'),
|
||||
placement : 'cursor'
|
||||
});
|
||||
if (modalParents.length > 0) {
|
||||
errorBadge.data('bs.tooltip').tip().css('z-index', parseInt(modalParents.css('z-index')) + 10);
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
} else {
|
||||
me.cmpEl.removeClass('error');
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
showError: function(errors) {
|
||||
var me = this;
|
||||
if (!_.isEmpty(errors)) {
|
||||
me.cmpEl.addClass('error');
|
||||
|
||||
var errorBadge = me.cmpEl.find('.input-error'),
|
||||
modalParents = errorBadge.closest('.asc-window'),
|
||||
errorTip = errorBadge.data('bs.tooltip');
|
||||
|
||||
if (errorTip) errorTip.tip().remove();
|
||||
errorBadge.attr('data-toggle', 'tooltip');
|
||||
errorBadge.removeData('bs.tooltip');
|
||||
errorBadge.tooltip({
|
||||
title : errors.join('\n'),
|
||||
placement : 'cursor'
|
||||
});
|
||||
|
||||
if (modalParents.length > 0) {
|
||||
errorBadge.data('bs.tooltip').tip().css('z-index', parseInt(modalParents.css('z-index')) + 10);
|
||||
}
|
||||
} else {
|
||||
me.cmpEl.removeClass('error');
|
||||
}
|
||||
}
|
||||
}
|
||||
})());
|
||||
});
|
||||
474
apps/common/main/lib/component/Layout.js
Normal file
474
apps/common/main/lib/component/Layout.js
Normal file
|
|
@ -0,0 +1,474 @@
|
|||
/**
|
||||
* Layout.js
|
||||
*
|
||||
* Created by Maxim Kadushkin on 10 February 2014
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*
|
||||
* Configuration
|
||||
* -------------
|
||||
*
|
||||
* @selector layout-ct
|
||||
* css class selector for the layout container
|
||||
*
|
||||
* @selector layout-item
|
||||
* css class selector for the layout item
|
||||
*
|
||||
*
|
||||
* @cfg {Object} box
|
||||
* Contains the layout container object
|
||||
*
|
||||
* @cfg {Boolean} stretch
|
||||
* If true, layout item will be stretched to all parent's space free from the static items
|
||||
*
|
||||
* @cfg {Boolean} rely
|
||||
* If true, @width and @height will correspond to DOMElement.width() and DOMElement.height()
|
||||
* If @stretch is true, @rely will be ignored.
|
||||
*
|
||||
* @cfg {Boolean} resizable
|
||||
* reserved
|
||||
*
|
||||
* @cfg {Integer} width
|
||||
* @cfg {Integer} height
|
||||
* Describe static size for the layout item.
|
||||
* For VBoxLayout:
|
||||
* @width = 100%,
|
||||
* @height = DOMElement.height() if rely = true
|
||||
*
|
||||
* For HBoxLayout:
|
||||
* @height = 100%,
|
||||
* @width = DOMElement.width() if rely = true
|
||||
*
|
||||
* If @stretch is true, @width and @height will be ignored.
|
||||
*
|
||||
*
|
||||
* Methods
|
||||
* -------
|
||||
*
|
||||
* @method doLayout
|
||||
* Makes rearrangement of the layout items
|
||||
*
|
||||
*
|
||||
* Example of usage
|
||||
* ----------------
|
||||
*
|
||||
* var $container = $('#hbox-layout');
|
||||
* items = $container.find(' > .layout-item');
|
||||
* var hLayout = new Common.UI.HBoxLayout({
|
||||
* box: $container,
|
||||
* items: [
|
||||
* {el: items[0]},
|
||||
* {el: items[1], stretch: true},
|
||||
* {el: items[2], rely: true}
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
*/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
define([
|
||||
'backbone'
|
||||
], function () {
|
||||
'use strict';
|
||||
|
||||
var BaseLayout = function(options) {
|
||||
this.box = null;
|
||||
this.panels = [];
|
||||
this.splitters = [];
|
||||
|
||||
_.extend(this, options || {});
|
||||
};
|
||||
|
||||
var LayoutPanel = function() {
|
||||
return {
|
||||
width : null,
|
||||
height : null,
|
||||
resize : false,
|
||||
stretch : false,
|
||||
rely : false
|
||||
}
|
||||
};
|
||||
|
||||
_.extend(BaseLayout.prototype, Backbone.Events, {
|
||||
initialize: function(options) {
|
||||
this.$parent = this.box.parent();
|
||||
|
||||
this.resize = {
|
||||
eventMove: _.bind(this.resizeMove, this),
|
||||
eventStop: _.bind(this.resizeStop, this)
|
||||
};
|
||||
|
||||
var panel, resizer, stretch = false;
|
||||
options.items.forEach(function(item) {
|
||||
item.el instanceof HTMLElement && (item.el = $(item.el));
|
||||
panel = _.extend(new LayoutPanel(), item);
|
||||
if ( panel.stretch ) {
|
||||
stretch = true;
|
||||
panel.rely = false;
|
||||
panel.resize = false;
|
||||
}
|
||||
|
||||
this.panels.push(panel);
|
||||
|
||||
if (panel.resize) {
|
||||
resizer = {
|
||||
isresizer : true,
|
||||
minpos : panel.resize.min||0,
|
||||
maxpos : panel.resize.max||0,
|
||||
fmin : panel.resize.fmin,
|
||||
fmax : panel.resize.fmax,
|
||||
behaviour : panel.behaviour,
|
||||
index : this.splitters.length
|
||||
};
|
||||
|
||||
if (!stretch) {
|
||||
panel.resize.el =
|
||||
resizer.el = panel.el.after('<div class="layout-resizer after"></div>').next();
|
||||
this.panels.push(resizer);
|
||||
} else {
|
||||
panel.resize.el =
|
||||
resizer.el = panel.el.before('<div class="layout-resizer before"></div>').prev();
|
||||
this.panels.splice(this.panels.length - 1, 0, resizer);
|
||||
}
|
||||
|
||||
this.splitters.push({resizer:resizer});
|
||||
|
||||
panel.resize.hidden && resizer.el.hide();
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.freeze = options.freeze; this.freeze && this.freezePanels(this.freeze);
|
||||
},
|
||||
|
||||
doLayout: function() {
|
||||
},
|
||||
|
||||
getElementHeight: function(el) {
|
||||
return parseInt(el.css('height'));
|
||||
},
|
||||
|
||||
getElementWidth: function(el) {
|
||||
return parseInt(el.css('width'));
|
||||
},
|
||||
|
||||
onSelectStart: function(e) {
|
||||
if (e.preventDefault) e.preventDefault();
|
||||
return false;
|
||||
},
|
||||
|
||||
addHandler: function(elem, type, handler) {
|
||||
if (elem.addEventListener) {
|
||||
elem.addEventListener(type, handler);
|
||||
} else
|
||||
if (elem.attachEvent) {
|
||||
elem.attachEvent('on' + type, handler);
|
||||
} else {
|
||||
elem['on' + type] = handler;
|
||||
}
|
||||
},
|
||||
|
||||
removeHandler: function(elem, type, handler) {
|
||||
if (elem.removeEventListener) {
|
||||
elem.removeEventListener(type, handler);
|
||||
} else
|
||||
if (elem.detachEvent) {
|
||||
elem.detachEvent('on' + type, handler);
|
||||
} else {
|
||||
elem['on' + type] = null;
|
||||
}
|
||||
},
|
||||
|
||||
clearSelection: function() {
|
||||
if (window.getSelection) {
|
||||
var selection = window.getSelection();
|
||||
if (selection.empty) selection.empty(); else
|
||||
if (selection.removeAllRanges) selection.removeAllRanges();
|
||||
} else if (document.selection) {
|
||||
document.selection.empty();
|
||||
}
|
||||
},
|
||||
|
||||
resizeStart: function(e) {
|
||||
this.clearSelection();
|
||||
this.addHandler(window.document, 'selectstart', this.onSelectStart);
|
||||
|
||||
$(document).on({
|
||||
mousemove : this.resize.eventMove,
|
||||
mouseup : this.resize.eventStop
|
||||
});
|
||||
|
||||
var panel = e.data.panel;
|
||||
this.resize.type = e.data.type;
|
||||
this.resize.$el = panel.el;
|
||||
this.resize.min = panel.minpos;
|
||||
this.resize.fmin = panel.fmin;
|
||||
this.resize.fmax = panel.fmax;
|
||||
this.resize.behaviour = panel.behaviour;
|
||||
|
||||
this.resize.$el.addClass('move');
|
||||
|
||||
if (e.data.type == 'vertical') {
|
||||
this.resize.height = parseInt(this.resize.$el.css('height'));
|
||||
this.resize.max = (panel.maxpos > 0 ? panel.maxpos : this.resize.$el.parent().height() + panel.maxpos) - this.resize.height;
|
||||
this.resize.inity = e.pageY - parseInt(e.currentTarget.style.top);
|
||||
} else
|
||||
if (e.data.type == 'horizontal') {
|
||||
this.resize.width = parseInt(this.resize.$el.css('width'));
|
||||
this.resize.max = (panel.maxpos > 0 ? panel.maxpos : this.resize.$el.parent().height() + panel.maxpos) - this.resize.width;
|
||||
this.resize.initx = e.pageX - parseInt(e.currentTarget.style.left);
|
||||
}
|
||||
},
|
||||
|
||||
resizeMove: function(e) {
|
||||
if (this.resize.type == 'vertical') {
|
||||
var prop = 'top',
|
||||
value = e.pageY - this.resize.inity;
|
||||
} else
|
||||
if (this.resize.type == 'horizontal') {
|
||||
prop = 'left';
|
||||
value = e.pageX - this.resize.initx;
|
||||
}
|
||||
|
||||
if (this.resize.fmin && this.resize.fmax) {
|
||||
if (!(value < this.resize.fmin()) && !(value > this.resize.fmax())) {
|
||||
this.resize.$el[0].style[prop] = value + 'px';
|
||||
}
|
||||
} else {
|
||||
|
||||
if (!(value < this.resize.min) && !(value > this.resize.max)) {
|
||||
this.resize.$el[0].style[prop] = value + 'px';
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
resizeStop: function(e) {
|
||||
this.removeHandler(window.document, 'selectstart', this.onSelectStart);
|
||||
|
||||
$(document).off({
|
||||
mousemove : this.resize.eventMove,
|
||||
mouseup : this.resize.eventStop
|
||||
});
|
||||
|
||||
if (this.resize.type == 'vertical') {
|
||||
var prop = 'height';
|
||||
var value = e.pageY - this.resize.inity;
|
||||
} else
|
||||
if (this.resize.type == 'horizontal') {
|
||||
prop = 'width';
|
||||
value = e.pageX - this.resize.initx;
|
||||
}
|
||||
|
||||
if (this.resize.fmin && this.resize.fmax) {
|
||||
value < this.resize.fmin() && (value = this.resize.fmin());
|
||||
value > this.resize.fmax() && (value = this.resize.fmax());
|
||||
} else {
|
||||
value < this.resize.min && (value = this.resize.min);
|
||||
value > this.resize.max && (value = this.resize.max);
|
||||
}
|
||||
|
||||
var panel = null, next = null, oldValue = 0;
|
||||
|
||||
if (this.resize.$el.hasClass('after')) {
|
||||
panel = this.resize.$el.prev();
|
||||
next = this.resize.$el.next();
|
||||
oldValue = parseInt(panel.css(prop));
|
||||
} else {
|
||||
panel = this.resize.$el.next();
|
||||
next = this.resize.$el.next();
|
||||
oldValue = parseInt(panel.css(prop));
|
||||
value = panel.parent()[prop]() - (value + this.resize[prop]);
|
||||
}
|
||||
|
||||
if (this.resize.type == 'vertical')
|
||||
value -= panel.position().top;
|
||||
if (this.resize.type == 'horizontal')
|
||||
value -= panel.position().left;
|
||||
|
||||
panel.css(prop, value + 'px');
|
||||
|
||||
if (this.resize.behaviour) {
|
||||
next.css(prop, parseInt(next.css(prop)) - (value - oldValue));
|
||||
}
|
||||
|
||||
this.resize.$el.removeClass('move');
|
||||
delete this.resize.$el;
|
||||
|
||||
if (this.resize.value != value) {
|
||||
this.doLayout();
|
||||
this.trigger('layout:resizedrag', this);
|
||||
}
|
||||
},
|
||||
|
||||
freezePanels: function (value) {
|
||||
|
||||
this.panels.forEach( function (panel) {
|
||||
|
||||
if (!panel.stretch && panel.resize) {
|
||||
$(panel.resize.el).css('cursor', value ? 'default' : '');
|
||||
}
|
||||
});
|
||||
|
||||
this.freeze = value;
|
||||
},
|
||||
|
||||
setResizeValue: function (index, value) {
|
||||
if (index >= this.splitters.length)
|
||||
return;
|
||||
|
||||
var panel = null, next = null, oldValue = 0,
|
||||
resize = this.splitters[index].resizer,
|
||||
prop = 'height';
|
||||
|
||||
value < resize.fmin() && (value = resize.fmin());
|
||||
value > resize.fmax() && (value = resize.fmax());
|
||||
|
||||
|
||||
if (resize.el.hasClass('after')) {
|
||||
panel = resize.el.prev();
|
||||
next = resize.el.next();
|
||||
oldValue = parseInt(panel.css(prop));
|
||||
} else {
|
||||
panel = resize.el.next();
|
||||
value = panel.parent()[prop]() - (value + resize[prop]);
|
||||
next = resize.el.next();
|
||||
oldValue = parseInt(panel.css(prop));
|
||||
}
|
||||
|
||||
// if (resize.type == 'vertical')
|
||||
value -= panel.position().top;
|
||||
// if (resize.type == 'horizontal')
|
||||
// value -= panel.position().left;
|
||||
|
||||
panel.css(prop, value + 'px');
|
||||
|
||||
if (resize.behaviour) {
|
||||
next.css(prop, parseInt(next.css(prop)) - (value - oldValue));
|
||||
}
|
||||
|
||||
if (resize.value != value) {
|
||||
this.doLayout();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
!Common.UI && (Common.UI = {});
|
||||
|
||||
Common.UI.VBoxLayout = function(options) {
|
||||
BaseLayout.apply(this, arguments);
|
||||
this.initialize.apply(this, arguments);
|
||||
};
|
||||
|
||||
Common.UI.VBoxLayout.prototype = _.extend(new BaseLayout(), {
|
||||
initialize: function(options){
|
||||
BaseLayout.prototype.initialize.call(this,options);
|
||||
|
||||
this.panels.forEach(function(panel){
|
||||
!panel.stretch && !panel.height && (panel.height = this.getElementHeight(panel.el));
|
||||
|
||||
if (panel.isresizer) {
|
||||
panel.el.on('mousedown', {type: 'vertical', panel: panel}, _.bind(this.resizeStart, this));
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.doLayout.call(this);
|
||||
},
|
||||
|
||||
doLayout: function() {
|
||||
var height = 0, stretchable, style;
|
||||
this.panels.forEach(function(panel){
|
||||
if ( !panel.stretch ) {
|
||||
style = panel.el.is(':visible');
|
||||
if ( style ) {
|
||||
height += (panel.rely!==true ? panel.height : this.getElementHeight(panel.el));
|
||||
}
|
||||
|
||||
if (panel.resize && panel.resize.autohide !== false && panel.resize.el) {
|
||||
if (style) {
|
||||
panel.resize.el.show();
|
||||
stretchable && (height += panel.resize.height);
|
||||
} else {
|
||||
panel.resize.el.hide();
|
||||
stretchable && (height -= panel.resize.height);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stretchable = panel;
|
||||
}
|
||||
}, this);
|
||||
|
||||
stretchable && (stretchable.height = this.$parent.height() - height);
|
||||
|
||||
height = 0;
|
||||
this.panels.forEach(function(panel){
|
||||
if (panel.el.is(':visible')) {
|
||||
style = {top: height};
|
||||
panel.rely!==true && (style.height = panel.height);
|
||||
panel.el.css(style);
|
||||
height += this.getElementHeight(panel.el);
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
});
|
||||
|
||||
Common.UI.HBoxLayout = function(options) {
|
||||
BaseLayout.apply(this, arguments);
|
||||
this.initialize.apply(this, arguments);
|
||||
};
|
||||
|
||||
Common.UI.HBoxLayout.prototype = _.extend(new BaseLayout(), {
|
||||
initialize: function(options){
|
||||
BaseLayout.prototype.initialize.call(this,options);
|
||||
|
||||
this.panels.forEach(function(panel){
|
||||
!panel.stretch && !panel.width && (panel.width = this.getElementWidth(panel.el));
|
||||
|
||||
if (panel.isresizer) {
|
||||
panel.el.on('mousedown', {type: 'horizontal', panel: panel}, _.bind(this.resizeStart, this));
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.doLayout.call(this);
|
||||
},
|
||||
|
||||
doLayout: function(event) {
|
||||
var width = 0, stretchable, style;
|
||||
this.panels.forEach(function(panel){
|
||||
if ( !panel.stretch ) {
|
||||
style = panel.el.is(':visible');
|
||||
if ( style ) {
|
||||
width += (panel.rely!==true ? panel.width : this.getElementWidth(panel.el));
|
||||
}
|
||||
|
||||
if (panel.resize && panel.resize.autohide !== false && panel.resize.el) {
|
||||
if (style) {
|
||||
panel.resize.el.show();
|
||||
stretchable && (width -= panel.resize.width);
|
||||
} else {
|
||||
panel.resize.el.hide();
|
||||
stretchable && (width -= panel.resize.width);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stretchable = panel;
|
||||
}
|
||||
}, this);
|
||||
|
||||
stretchable && (stretchable.width = this.$parent.width() - width);
|
||||
|
||||
width = 0;
|
||||
this.panels.forEach(function(panel){
|
||||
if (panel.el.is(':visible')) {
|
||||
style = {left: width};
|
||||
panel.rely!==true && (style.width = panel.width);
|
||||
panel.el.css(style);
|
||||
width += this.getElementWidth(panel.el);
|
||||
}
|
||||
},this);
|
||||
}
|
||||
});
|
||||
|
||||
Common.UI.VBoxLayout.prototype.constructor = Common.UI.VBoxLayout;
|
||||
Common.UI.HBoxLayout.prototype.constructor = Common.UI.HBoxLayout;
|
||||
});
|
||||
74
apps/common/main/lib/component/ListView.js
Normal file
74
apps/common/main/lib/component/ListView.js
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* ListView.js
|
||||
*
|
||||
* Created by Julia Radzhabova on 2/27/14
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
define([
|
||||
'common/main/lib/component/DataView'
|
||||
], function () {
|
||||
'use strict';
|
||||
|
||||
Common.UI.ListView = Common.UI.DataView.extend((function() {
|
||||
return {
|
||||
options: {
|
||||
handleSelect: true,
|
||||
enableKeyEvents: true,
|
||||
showLast: true,
|
||||
simpleAddMode: false,
|
||||
keyMoveDirection: 'vertical',
|
||||
itemTemplate: _.template('<div id="<%= id %>" class="list-item" style=""><%= value %></div>')
|
||||
},
|
||||
|
||||
template: _.template([
|
||||
'<div class="listview inner"></div>'
|
||||
].join('')),
|
||||
|
||||
onResetItems : function() {
|
||||
this.innerEl = null;
|
||||
Common.UI.DataView.prototype.onResetItems.call(this);
|
||||
},
|
||||
|
||||
onAddItem: function(record, index) {
|
||||
var view = new Common.UI.DataViewItem({
|
||||
template: this.itemTemplate,
|
||||
model: record
|
||||
});
|
||||
|
||||
if (!this.innerEl) {
|
||||
this.innerEl = $(this.el).find('.inner');
|
||||
this.innerEl.find('.empty-text').remove();
|
||||
}
|
||||
if (view && this.innerEl) {
|
||||
if (this.options.simpleAddMode) {
|
||||
this.innerEl.append(view.render().el)
|
||||
} else {
|
||||
var idx = _.indexOf(this.store.models, record);
|
||||
var innerDivs = this.innerEl.find('> div');
|
||||
|
||||
if (idx > 0)
|
||||
$(innerDivs.get(idx - 1)).after(view.render().el);
|
||||
else {
|
||||
(innerDivs.length > 0) ? $(innerDivs[idx]).before(view.render().el) : this.innerEl.append(view.render().el);
|
||||
}
|
||||
|
||||
}
|
||||
this.dataViewItems.push(view);
|
||||
this.listenTo(view, 'change', this.onChangeItem);
|
||||
this.listenTo(view, 'remove', this.onRemoveItem);
|
||||
this.listenTo(view, 'click', this.onClickItem);
|
||||
this.listenTo(view, 'dblclick',this.onDblClickItem);
|
||||
this.listenTo(view, 'select', this.onSelectItem);
|
||||
|
||||
if (!this.isSuspendEvents)
|
||||
this.trigger('item:add', this, view, record);
|
||||
}
|
||||
}
|
||||
}
|
||||
})());
|
||||
});
|
||||
131
apps/common/main/lib/component/LoadMask.js
Normal file
131
apps/common/main/lib/component/LoadMask.js
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/**
|
||||
* LoadMask.js
|
||||
*
|
||||
* Displays loading mask over selected element(s) or component. Accepts both single and multiple selectors.
|
||||
*
|
||||
* Created by Alexander Yuzhin on 2/7/14
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @example
|
||||
* new Common.UI.LoadMask({
|
||||
* owner: $('#viewport')
|
||||
* });
|
||||
*
|
||||
* @property {Object} owner
|
||||
*
|
||||
* Component or selector that will be masked.
|
||||
*
|
||||
*
|
||||
* @property {String} title
|
||||
*
|
||||
* @property {String} cls
|
||||
*
|
||||
* @property {String} style
|
||||
*
|
||||
*/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
define([
|
||||
'common/main/lib/component/BaseView'
|
||||
], function () {
|
||||
'use strict';
|
||||
|
||||
Common.UI.LoadMask = Common.UI.BaseView.extend((function() {
|
||||
var ownerEl,
|
||||
maskeEl,
|
||||
loaderEl;
|
||||
|
||||
return {
|
||||
options : {
|
||||
cls : '',
|
||||
style : '',
|
||||
title : 'Loading...',
|
||||
owner : document.body
|
||||
},
|
||||
|
||||
template: _.template([
|
||||
'<div id="<%= id %>" class="asc-loadmask-body <%= cls %>" role="presentation" tabindex="-1">',
|
||||
'<div class="asc-loadmask-image"></div>',
|
||||
'<div class="asc-loadmask-title"><%= title %></div>',
|
||||
'</div>'
|
||||
].join('')),
|
||||
|
||||
initialize : function(options) {
|
||||
Common.UI.BaseView.prototype.initialize.call(this, options);
|
||||
|
||||
this.template = this.options.template || this.template;
|
||||
this.cls = this.options.cls;
|
||||
this.style = this.options.style;
|
||||
this.title = this.options.title;
|
||||
this.owner = this.options.owner;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return this;
|
||||
},
|
||||
|
||||
show: function(){
|
||||
if (maskeEl || loaderEl)
|
||||
return;
|
||||
|
||||
ownerEl = (this.owner instanceof Common.UI.BaseView) ? $(this.owner.el) : $(this.owner);
|
||||
|
||||
// The owner is already masked
|
||||
if (ownerEl.hasClass('masked'))
|
||||
return this;
|
||||
|
||||
var me = this;
|
||||
|
||||
maskeEl = $('<div class="asc-loadmask"></div>');
|
||||
loaderEl = $(this.template({
|
||||
id : me.id,
|
||||
cls : me.cls,
|
||||
style : me.style,
|
||||
title : me.title
|
||||
}));
|
||||
|
||||
ownerEl.addClass('masked');
|
||||
ownerEl.append(maskeEl);
|
||||
ownerEl.append(loaderEl);
|
||||
|
||||
loaderEl.css({
|
||||
top : Math.round(ownerEl.height() / 2 - (loaderEl.height() + parseInt(loaderEl.css('padding-top')) + parseInt(loaderEl.css('padding-bottom'))) / 2) + 'px',
|
||||
left: Math.round(ownerEl.width() / 2 - (loaderEl.width() + parseInt(loaderEl.css('padding-left')) + parseInt(loaderEl.css('padding-right'))) / 2) + 'px'
|
||||
|
||||
});
|
||||
|
||||
Common.util.Shortcuts.suspendEvents();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
ownerEl && ownerEl.removeClass('masked');
|
||||
maskeEl && maskeEl.remove();
|
||||
loaderEl && loaderEl.remove();
|
||||
maskeEl = null;
|
||||
loaderEl = null;
|
||||
Common.util.Shortcuts.resumeEvents();
|
||||
},
|
||||
|
||||
setTitle: function(title) {
|
||||
this.title = title;
|
||||
|
||||
if (ownerEl && ownerEl.hasClass('masked') && loaderEl){
|
||||
$('.asc-loadmask-title', loaderEl).html(title);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
isVisible: function() {
|
||||
return !_.isEmpty(loaderEl);
|
||||
}
|
||||
}
|
||||
})())
|
||||
});
|
||||
|
||||
56
apps/common/main/lib/component/MaskedField.js
Normal file
56
apps/common/main/lib/component/MaskedField.js
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
define([
|
||||
'common/main/lib/component/BaseView'
|
||||
], function () {
|
||||
'use strict';
|
||||
|
||||
Common.UI.MaskedField = Common.UI.BaseView.extend({
|
||||
options : {
|
||||
maskExp: '',
|
||||
maxLength: 999
|
||||
},
|
||||
|
||||
initialize : function(options) {
|
||||
Common.UI.BaseView.prototype.initialize.call(this, options);
|
||||
|
||||
var me = this,
|
||||
el = $(this.el);
|
||||
|
||||
el.addClass('masked-field user-select');
|
||||
el.attr('maxlength', me.options.maxLength);
|
||||
el.on('keypress', function(e) {
|
||||
var charCode = String.fromCharCode(e.which);
|
||||
if(!me.options.maskExp.test(charCode) && !e.ctrlKey && e.keyCode !== Common.UI.Keys.DELETE && e.keyCode !== Common.UI.Keys.BACKSPACE &&
|
||||
e.keyCode !== Common.UI.Keys.LEFT && e.keyCode !== Common.UI.Keys.RIGHT && e.keyCode !== Common.UI.Keys.HOME &&
|
||||
e.keyCode !== Common.UI.Keys.END && e.keyCode !== Common.UI.Keys.ESC && e.keyCode !== Common.UI.Keys.INSERT &&
|
||||
e.keyCode !== Common.UI.Keys.TAB /* || el.val().length>=me.options.maxLength*/){
|
||||
if (e.keyCode==Common.UI.Keys.RETURN) me.trigger('changed', me, el.val());
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
});
|
||||
el.on('input', function(e) {
|
||||
me.trigger('change', me, el.val());
|
||||
});
|
||||
el.on('blur', function(e) {
|
||||
me.trigger('changed', me, el.val());
|
||||
});
|
||||
},
|
||||
|
||||
render : function() {
|
||||
return this;
|
||||
},
|
||||
|
||||
setValue: function(value) {
|
||||
if (this.options.maskExp.test(value) && value.length<=this.options.maxLength)
|
||||
$(this.el).val(value);
|
||||
},
|
||||
|
||||
getValue: function() {
|
||||
$(this.el).val();
|
||||
}
|
||||
});
|
||||
});
|
||||
545
apps/common/main/lib/component/Menu.js
Normal file
545
apps/common/main/lib/component/Menu.js
Normal file
|
|
@ -0,0 +1,545 @@
|
|||
/**
|
||||
* Menu.js
|
||||
*
|
||||
* A menu object. This is the container to which you may add {@link Common.UI.MenuItem menu items}.
|
||||
*
|
||||
* Created by Alexander Yuzhin on 1/28/14
|
||||
* Copyright (c) 2014 Ascensio System SIA. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default template
|
||||
*
|
||||
* <ul class="dropdown-menu" role="menu">
|
||||
* <li><a href="#">item 1</a></li>-->
|
||||
* <li><a href="#">item 2</a></li>-->
|
||||
* <li class="divider"></li>-->
|
||||
* <li><a href="#">item 3</a></li>
|
||||
* </ul>
|
||||
*
|
||||
* A useful classes of menu position
|
||||
*
|
||||
* - `'pull-right'` using for layout menu by right side of a parent
|
||||
*
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* new Common.UI.Menu({
|
||||
* items: [
|
||||
* { caption: 'item 1', value: 1 },
|
||||
* { caption: 'item 1', value: 2 },
|
||||
* { caption: '--' },
|
||||
* { caption: 'item 1', value: 3 },
|
||||
* ]
|
||||
* })
|
||||
*
|
||||
* @property {Object} itemTemplate
|
||||
*
|
||||
* Default template for items
|
||||
*
|
||||
*
|
||||
* @property {Array} items
|
||||
*
|
||||
* Arrow of the {Common.UI.MenuItem} menu items
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
if (Common === undefined)
|
||||
var Common = {};
|
||||
|
||||
define([
|
||||
'common/main/lib/extend/Bootstrap',
|
||||
'common/main/lib/component/BaseView',
|
||||
'common/main/lib/component/MenuItem',
|
||||
'common/main/lib/component/Scroller'
|
||||
], function () {
|
||||
'use strict';
|
||||
|
||||
Common.UI.Menu = (function(){
|
||||
var manager = (function(){
|
||||
var active = [],
|
||||
menus = {};
|
||||
|
||||
return {
|
||||
register: function(menu) {
|
||||
menus[menu.id] = menu;
|
||||
menu
|
||||
.on('show:after', function(m) {
|
||||
active.push(m);
|
||||
})
|
||||
.on('hide:after', function(m) {
|
||||
var index = active.indexOf(m);
|
||||
|
||||
if (index > -1)
|
||||
active.splice(index, 1);
|
||||
});
|
||||
},
|
||||
|
||||
unregister: function(menu) {
|
||||
var index = active.indexOf(menu);
|
||||
|
||||
delete menus[menu.id];
|
||||
|
||||
if (index > -1)
|
||||
active.splice(index, 1);
|
||||
|
||||
menu.off('show:after').off('hide:after');
|
||||
},
|
||||
|
||||
hideAll: function() {
|
||||
Common.NotificationCenter.trigger('menumanager:hideall');
|
||||
|
||||
if (active && active.length > 0) {
|
||||
_.each(active, function(menu) {
|
||||
menu.hide();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
return _.extend(Common.UI.BaseView.extend({
|
||||
options : {
|
||||
cls : '',
|
||||
style : '',
|
||||
itemTemplate: null,
|
||||
items : [],
|
||||
menuAlign : 'tl-bl',
|
||||
menuAlignEl : null,
|
||||
offset : [0, 0],
|
||||
cyclic : true
|
||||
},
|
||||
|
||||
template: _.template([
|
||||
'<ul class="dropdown-menu <%= options.cls %>" style="<%= options.style %>" role="menu"></ul>'
|
||||
].join('')),
|
||||
|
||||
initialize : function(options) {
|
||||
Common.UI.BaseView.prototype.initialize.call(this, options);
|
||||
|
||||
var me = this;
|
||||
|
||||
this.id = this.options.id || Common.UI.getId();
|
||||
this.itemTemplate = this.options.itemTemplate || Common.UI.MenuItem.prototype.template;
|
||||
this.rendered = false;
|
||||
this.items = [];
|
||||
this.offset = [0, 0];
|
||||
this.menuAlign = this.options.menuAlign;
|
||||
this.menuAlignEl = this.options.menuAlignEl;
|
||||
|
||||
if (!this.options.cyclic) this.options.cls += ' no-cyclic';
|
||||
|
||||
_.each(this.options.items, function(item) {
|
||||
if (item instanceof Common.UI.MenuItem) {
|
||||
me.items.push(item)
|
||||
} else {
|
||||
me.items.push(
|
||||
new Common.UI.MenuItem(_.extend({
|
||||
tagName : 'li',
|
||||
template: me.itemTemplate
|
||||
}, item))
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
if (this.options.el)
|
||||
this.render();
|
||||
|
||||
manager.register(this);
|
||||
},
|
||||
|
||||
remove: function() {
|
||||
manager.unregister(this);
|
||||
Common.UI.BaseView.prototype.remove.call(this);
|
||||
},
|
||||
|
||||
render: function(parentEl) {
|
||||
var me = this;
|
||||
|
||||
this.trigger('render:before', this);
|
||||
|
||||
this.cmpEl = $(this.el);
|
||||
|
||||
if (parentEl) {
|
||||
this.setElement(parentEl, false);
|
||||
|
||||
if (!me.rendered) {
|
||||
this.cmpEl = $(this.template({
|
||||
options : me.options
|
||||
}));
|
||||
|
||||
parentEl.append(this.cmpEl);
|
||||
}
|
||||
} else {
|
||||
if (!me.rendered) {
|
||||
this.cmpEl = this.template({
|
||||
options : me.options
|
||||
});
|
||||
$(this.el).append(this.cmpEl);
|
||||
}
|
||||
}
|
||||
|
||||
var rootEl = this.cmpEl.parent(),
|
||||
menuRoot = (rootEl.attr('role') === 'menu') ? rootEl : rootEl.find('[role=menu]');
|
||||
|
||||
if (menuRoot) {
|
||||
if (!me.rendered) {
|
||||
_.each(me.items || [], function(item) {
|
||||
menuRoot.append(item.render().el);
|
||||
|
||||
item.on('click', _.bind(me.onItemClick, me));
|
||||
item.on('toggle', _.bind(me.onItemToggle, me));
|
||||
});
|
||||
}
|
||||
|
||||
menuRoot.css({
|
||||
'max-height': me.options.maxHeight||'none',
|
||||
position : 'fixed',
|
||||
right : 'auto',
|
||||
left : -1000,
|
||||
top : -1000
|
||||
});
|
||||
|
||||
this.parentEl = menuRoot.parent();
|
||||
|
||||
this.parentEl.on('show.bs.dropdown', _.bind(me.onBeforeShowMenu, me));
|
||||
this.parentEl.on('shown.bs.dropdown', _.bind(me.onAfterShowMenu, me));
|
||||
this.parentEl.on('hide.bs.dropdown', _.bind(me.onBeforeHideMenu, me));
|
||||
this.parentEl.on('hidden.bs.dropdown', _.bind(me.onAfterHideMenu, me));
|
||||
this.parentEl.on('keydown.after.bs.dropdown', _.bind(me.onAfterKeydownMenu, me));
|
||||
menuRoot.on('scroll', _.bind(me.onScroll, me));
|
||||
|
||||
menuRoot.hover(
|
||||
function(e) { me.isOver = true;},
|
||||
function(e) { me.isOver = false; }
|
||||
);
|
||||
}
|
||||
|
||||
this.rendered = true;
|
||||
|
||||
this.trigger('render:after', this);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
isVisible: function() {
|
||||
return this.rendered && (this.cmpEl.is(':visible'));
|
||||
},
|
||||
|
||||
show: function() {
|
||||
if (this.rendered && this.parentEl && !this.parentEl.hasClass('open')) {
|
||||
this.cmpEl.dropdown('toggle');
|
||||
}
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
if (this.rendered && this.parentEl) {
|
||||
if ( this.parentEl.hasClass('open') )
|
||||
this.cmpEl.dropdown('toggle');
|
||||
else if (this.parentEl.hasClass('over'))
|
||||
this.parentEl.removeClass('over');
|
||||
}
|
||||
},
|
||||
|
||||
insertItem: function(index, item) {
|
||||
var me = this,
|
||||
el = this.cmpEl;
|
||||
|
||||
if (!(item instanceof Common.UI.MenuItem)) {
|
||||
item = new Common.UI.MenuItem(_.extend({
|
||||
tagName : 'li',
|
||||
template: me.itemTemplate
|
||||
}, item));
|
||||
}
|
||||
|
||||
if (index < 0 || index >= me.items.length)
|
||||
me.items.push(item);
|
||||
else
|
||||
me.items.splice(index, 0, item);
|
||||
|
||||
if (this.rendered) {
|
||||
var menuRoot = (el.attr('role') === 'menu')
|
||||
? el
|
||||
: el.find('[role=menu]');
|
||||
|
||||
if (menuRoot) {
|
||||
if (index < 0) {
|
||||
menuRoot.append(item.render().el);
|
||||
} else if (index === 0) {
|
||||
menuRoot.prepend(item.render().el);
|
||||
} else {
|
||||
$('li:nth-child(' + (index+1) + ')', menuRoot).before(item.render().el);
|
||||
}
|
||||
|
||||
item.on('click', _.bind(me.onItemClick, me));
|
||||
item.on('toggle', _.bind(me.onItemToggle, me));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
doLayout: function() {
|
||||
if (this.options.maxHeight > 0) {
|
||||
if (!this.rendered) {
|
||||
this.mustLayout = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var me = this,
|
||||
el = this.cmpEl;
|
||||
|
||||
var menuRoot = (el.attr('role') === 'menu') ? el : el.find('[role=menu]');
|
||||
|
||||
if (!menuRoot.is(':visible')) {
|
||||
var pos = [menuRoot.css('left'), menuRoot.css('top')];
|
||||
menuRoot.css({
|
||||
left : '-1000px',
|
||||
top : '-1000px',
|
||||
display : 'block'
|
||||
});
|
||||
}
|
||||
|
||||
var $items = menuRoot.find('li');
|
||||
|
||||
if ($items.height() * $items.length > this.options.maxHeight) {
|
||||
var scroll = '<div class="menu-scroll top"></div>';
|
||||
menuRoot.prepend(scroll);
|
||||
|
||||
scroll = '<div class="menu-scroll bottom"></div>';
|
||||
menuRoot.append(scroll);
|
||||
|
||||
menuRoot.css({
|
||||
'box-shadow' : 'none',
|
||||
'overflow-y' : 'hidden',
|
||||
'padding-top' : '18px'
|
||||
// 'padding-bottom' : '18px'
|
||||
});
|
||||
|
||||
menuRoot.find('> li:last-of-type').css('margin-bottom',18);
|
||||
|
||||
var addEvent = function( elem, type, fn ) {
|
||||
elem.addEventListener ? elem.addEventListener( type, fn, false ) : elem.attachEvent( "on" + type, fn );
|
||||
};
|
||||
|
||||
var eventname=(/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
|
||||
addEvent(menuRoot[0], eventname, _.bind(this.onMouseWheel,this) | ||||