webapps added

This commit is contained in:
Maxim Kadushkin 2016-03-10 21:48:53 -03:00
parent a4bf803b7c
commit 741b10515d
9594 changed files with 879276 additions and 0 deletions

21
.hgignore Normal file
View 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
View 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);

View 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>

View 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>

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

54
apps/common/Analytics.js Normal file
View 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
View 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);
}
}
})();

View 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
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

View 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
View 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
};
})();

View 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
});
});

View 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;
}
});
});

View 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;
}
});
});

View 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});
}
});
});

View 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
});
});

View 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
}
}
})
});
});

View 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;
});
}
});
});

View 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");
}
});
});

View 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">&nbsp;</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">&nbsp;</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">&nbsp;</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 %>">&nbsp;</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 %>">&nbsp;</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 %>">&nbsp;</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);
}
}
}
}
});
});

View 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);
}
});
});

View 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>&nbsp;</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});
}
});
});

View 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);
}
}
}
});
});

View 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 || {}));
});

View 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
});
}
}
})());
});

View 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;
}
}
}
}
})());
});

View 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);
}
})
});

View 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);
});
});

View 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;
}
}
})())
});

View 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'
});
});

View 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');
}
}
}
})());
});

View 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;
});

View 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);
}
}
}
})());
});

View 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);
}
}
})())
});

View 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();
}
});
});

View 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)