Commit 741b1051 authored by Maxim Kadushkin's avatar Maxim Kadushkin

webapps added

parent a4bf803b

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

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
This diff is collapsed.
<!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>
This diff is collapsed.
<!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>
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]);
}
}
})();
\ No newline at end of file
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);
}
}
})();
\ No newline at end of file
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
}
};
\ No newline at end of file
This diff is collapsed.
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
};
})();
/**
* 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
});
});
/**
* 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;
}
});
});
/**
* 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;
}
});
});
/**
* 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});
}
});
});
/**
* 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
});
});
/**
* 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
}
}
})
});
});
/**
* 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;
});
}
});
});
/**
* 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");
}
});
});
\ No newline at end of file
This diff is collapsed.
/**
* 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);
}
});
});
\ No newline at end of file
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});
}
});
});
\ No newline at end of file
/**
* 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);
}
}
}
});
});
\ No newline at end of file
/**
* 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 || {}));
});
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/**
* 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;
}
}
})())
});
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<div id="header-container">
<div id="header-logo"></div>
<div id="header-caption"><div><%= headerCaption %></div></div>
<div id="header-documentcaption"><%= documentCaption %></div>
<div id="header-back" style="display: <%= canBack ? 'table-cell' : 'none' %>;"><div><%= textBack %></div></div>
</div>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment