Mobile theme W.I.P:

- Fix view mode loads with wrong context
- Fix mail view actions
This commit is contained in:
Hadi Nategh 2016-03-03 14:10:08 +00:00
parent dee934e1f5
commit 784aa2c82f
16 changed files with 381 additions and 83 deletions

View File

@ -332,9 +332,11 @@ etemplate2.prototype.download = function(_url)
* @param {string} _url url to load template
* @param {object} _data object with attributes content, langRequire, etemplate_exec_id, ...
* @param {function} _callback called after tempalte is loaded
* @param {object} _app local app object
*/
etemplate2.prototype.load = function(_name, _url, _data, _callback)
etemplate2.prototype.load = function(_name, _url, _data, _callback, _app)
{
var app = _app || window.app;
this.name = _name; // store top-level template name to have it available in widgets
// store template base url, in case initial template is loaded via webdav, to use that for further loads too
// need to split off domain first, as it could contain app-name part of template eg. stylite.report.xet and https://my.stylite.de/egw/...

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -916,7 +916,7 @@ class mail_ui
'onExecute' => html::$ua_mobile?'javaScript:app.mail.mobileView':'javaScript:app.mail.mail_open',
'allowOnMultiple' => false,
'default' => true,
'mobileViewTemplate' => 'view.xet'
'mobileViewTemplate' => 'view'
),
'reply' => array(
'caption' => 'Reply',
@ -1976,13 +1976,7 @@ $filter['before']= date("d-M-Y", $cutoffdate2);
);
$actions['tracker']['toolbarDefault'] = true;
$actions['forward']['toolbarDefault'] = true;
if (html::$ua_mobile) {
foreach($actions as $key => $action)
{
if (in_array($key,array('calendar', 'infolog' ,'tracker' ))) $actions[$key]['toolbarDefault'] = false;
$actions['save']['children']['save2disk']['toolbarDefault'] = $actions['print']['toolbarDefault'] = false;
}
}
$compose = $actions['composeasnew'];
unset($actions['composeasnew']);
$actions = array_reverse($actions,true);

View File

@ -308,6 +308,15 @@ app.classes.mail = AppJS.extend(
break;
case 'mail.folder_management':
this.egw.message(this.egw.lang('If you would like to select multiple folders in one action, you can hold ctrl key then select a folder as start range and another folder within a same level as end range, all folders in between will be selected or unselected based on their current status.'),'info',true);
break;
case 'mail.view':
// we need to set mail_currentlyFocused var otherwise mail
// defined actions won't work
this.mail_currentlyFocussed = this.et2.mail_currentlyFocussed;
// a replacement for is_popup to distinguishe whether
// the view should be considered like popup and it does indicate
// we are in view mode
this.mail_viewMode = true;
}
},
@ -1574,7 +1583,14 @@ app.classes.mail = AppJS.extend(
//alert(_action.id+','+ msg);
if (!calledFromPopup) this.mail_setRowClass(_elems,'deleted');
this.mail_deleteMessages(msg,'no',calledFromPopup);
if (calledFromPopup && this.mail_isMainWindow==false) egw(window).close();
if (calledFromPopup && this.mail_isMainWindow==false)
{
egw(window).close();
}
else if (this.mail_viewMode)
{
this.close();
}
},
/**
@ -2077,7 +2093,7 @@ app.classes.mail = AppJS.extend(
data = {
msg: [this.et2.getArrayMgr("content").getEntry('mail_id')] || '',
all: _allMessagesChecked || false,
popup: egw(window).is_popup() || false,
popup: this.mail_viewMode || egw(window).is_popup() || false,
activeFilters: _action.id == 'readall'? false : this.mail_getActiveFilters(_action)
},
rowClass = _action.id;
@ -2101,7 +2117,8 @@ app.classes.mail = AppJS.extend(
rowClass = 'seen';
if (data.popup)
{
tree = opener.etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById(this.nm_index+'[foldertree]');
var et_2 = this.mail_viewMode? etemplate2:opener.etemplate2;
tree = et_2.getByApplication('mail')[0].widgetContainer.getWidgetById(this.nm_index+'[foldertree]');
}
else
{
@ -5148,21 +5165,36 @@ app.classes.mail = AppJS.extend(
*/
mobileView: function(_action, _sender)
{
// app id in nm
// row id in nm
var id = _sender[0].id;
var content = {};
if (id){
content = egw.dataGetUIDdata(id);
content.data['toolbar'] = etemplate2.getByApplication('mail')[0].widgetContainer.getArrayMgr('sel_options').data.toolbar;
this.et2.setArrayMgr('content', content);
}
// set the current selected row
this.mail_currentlyFocussed = id;
var defaultActions= {
actions:['delete', 'forward','reply','flagged'], // default actions to display
check:function(_action){
for (var i=0;i<= this.actions.length;i++)
{
if (_action == this.actions[i]) return true;
}
return false;
}
};
var content = {};
var self = this;
this.viewEntry(_action, _sender, function(etemplate){
if (id){
content = egw.dataGetUIDdata(id);
content.data['toolbar'] = this.et2.getArrayMgr('sel_options').getEntry('toolbar');
// Set default actions
for(var action in content.data['toolbar'])
{
content.data.toolbar[action]['toolbarDefault'] = defaultActions.check(action);
}
// update local storage with added toolbar actions
egw.dataStoreUID(id,content.data);
}
this.viewEntry(_action, _sender, true, function(etemplate){
// et2 object in view
var et2 = etemplate.widgetContainer;
// iframe to load message
@ -5176,6 +5208,9 @@ app.classes.mail = AppJS.extend(
// Content
var content = et2.getArrayMgr('content').data;
// set the current selected row
et2.mail_currentlyFocussed = id;
if (content.attachmentsBlock.length>0 && content.attachmentsBlock[0].filename)
{
$attachment.text(content.attachmentsBlock.length+' '+ egw.lang('attachments'));
@ -5197,7 +5232,6 @@ app.classes.mail = AppJS.extend(
// as we don't want to show content in iframe.
self.mail_prepare_print(jQuery(this));
});
});
}
});

8
mail/js/app.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -2499,9 +2499,6 @@ div.mailComposeHeaderSection > table {
padding: 1px 8px 0 8px;
background: none;
}
body #popupMainDiv .mobile-view-editBtn {
display: none;
}
body #popupMainDiv div.et2_toolbar.et2_head_toolbar {
padding: 1px 5px 5px 10px !important;
}

View File

@ -39,7 +39,6 @@
padding: 1px 8px 0 8px;
background: none;
.mobile-view-editBtn {display: none;}
div.et2_toolbar.et2_head_toolbar {
padding: 1px 5px 5px 10px !important;
button {

View File

@ -0,0 +1,48 @@
# Description
The Etherpad jQuery Plugin easily allows you to embed and access a pad from Etherpad in a web page. The plugin injects the pad contents into a div using iframes. It can also read the contents of a Pad and write it to a div.
# Usage & Examples
<p>Include jQuery.js, include etherpad.js, assign a pad to a div. If you get confused look at the examples in index.html</p>
### Sets the pad id and puts the pad in the div
`$('#examplePadBasic').pad({'padId':'test'});`
<div id="examplePadBasic"></div>
### Sets the pad id, some more parameters and puts the pad in the div
`$('#examplePadBasic').pad({'padId':'test','showChat':true});`
<div id="examplePadIntense"></div>
### Sets the pad id, some plugin parameters and puts the pad in the div
`$('#examplePadPlugins').pad({'padId':'test','plugins':{'pageview':'true'}});`
<div id="examplePadPlugins"></div>
### Gets the padContents from Example #2 and writes it to the target div "exampleGetContents"
`$('#examplePadBasic').pad({'getContents':'exampleGetContents'});`
# Available options and parameters
<pre>
'host' : 'http://beta.etherpad.org', // the host and port of the Etherpad instance, by default the foundation will host your pads for you
'baseUrl' : '/p/', // The base URL of the pads
'showControls' : false, // If you want to show controls IE bold, italic, etc.
'showChat' : false, // If you want to show the chat button or not
'showLineNumbers' : false, // If you want to show the line numbers or not
'userName' : 'unnamed', // The username you want to pass to the pad
'useMonospaceFont' : false, // Use monospaced fonts
'noColors' : false, // Disable background colors on author text
'userColor' : false, // The background color of this authors text in hex format IE #000
'hideQRCode' : false, // Hide QR code
'alwaysShowChat' : false, // Always show the chat on the UI
'width' : 100, // The width of the embedded IFrame
'height' : 100, // The height of the embedded IFrame
'border' : 0, // The width of the border (make sure to append px to a numerical value)
'borderStyle' : 'solid', // The CSS style of the border [none, dotted, dashed, solid, double, groove, ridge, inset, outset]
'plugins' : {}, // The options related to the plugins, not to the basic Etherpad configuration
'rtl' : false // Show text from right to left
</pre>
# Copyright
jQuery Etherpad plugin written by John McLear (c) Primary Technology 2011<br/>
Development funded by the Etherpad Foundation.
Feel free to re-use, distribute, butcher, edit and whatever else you want.
It's under the Apache licence.

View File

@ -0,0 +1,25 @@
{
"name": "etherpad",
"title": "jQuery Etherpad",
"description": "jQuery plugin for embedding Etherpad",
"keywords": [
"color",
"animation"
],
"version": "1.0.2",
"author": {
"name": "John McLear",
"url": "https://github.com/ether/etherpad-lite-jquery-plugin"
},
"licenses": [
{
"type": "Apache 2",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
}
],
"bugs": "https://github.com/ether/etherpad-lite-jquery-plugin/issues/",
"homepage": "https://github.com/ether/etherpad-lite-jquery-plugin",
"dependencies": {
"jquery": ">=1.5"
}
}

View File

@ -0,0 +1,67 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Etherpad jQuery Plugin Example</title>
<script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
<script src="js/etherpad.js"></script>
</head>
<body id="home">
<h1>Etherpad jQuery Plugin Example</h1>
<h2>Usage:</h2>
<p>Include jQuery.js, include etherpad.js</p>
<h2>Example #1: Sets the pad id and puts the pad in the div</h2>
<pre>$('#examplePadBasic').pad({'padId':'test'});</pre>
<div id="examplePadBasic"></div>
<h2>Example #2: Sets the pad id, some more parameters and puts the pad in the div</h2>
<pre>$('#examplePadIntense').pad({'padId':'test2','showChat':'true'});</pre>
<div id="examplePadIntense"></div>
<h2>Example #3: Sets the pad id, some plugin parameters and puts the pad in the div</h2>
<pre>$('#examplePadPlugins').pad({'padId':'test3','plugins':{'pageview':'true'}});</pre>
<div id="examplePadPlugins"></div>
<h2>Example #4: Gets the padContents from Example #2</h2>
<pre>$('#examplePadIntense').pad({'getContents':'exampleGetContents'});</pre>
<div id="exampleGetContents"><a id="contents" onClick="$('#examplePadIntense').pad({'getContents':'exampleGetContents'});">Click me to Replace me with the pad contents</a></div>
<h2>Available options and parameters</h2>
<pre>
'host' : 'http://beta.etherpad.org', // the host and port of the Etherpad instance, by default the foundation will host your pads for you
'baseUrl' : '/p/', // The base URL of the pads
'showControls' : false, // If you want to show controls IE bold, italic, etc.
'showChat' : false, // If you want to show the chat button or not
'showLineNumbers' : false, // If you want to show the line numbers or not
'userName' : 'unnamed', // The username you want to pass to the pad
'useMonospaceFont' : false, // Use monospaced fonts
'noColors' : false, // Disable background colors on author text
'userColor' : false, // The background color of this authors text in hex format IE #000
'hideQRCode' : false, // Hide QR code
'alwaysShowChat' : false, // Always show the chat on the UI
'width' : 100, // The width of the embedded IFrame
'height' : 100, // The height of the embedded IFrame
'border' : 0, // The width of the border (make sure to append px to a numerical value)
'borderStyle' : 'solid' // The CSS style of the border [none, dotted, dashed, solid, double, groove, ridge, inset, outset]
'plugins' : {}, // The options related to the plugins, not to the basic Etherpad configuration
'rtl' : false // Show right to left text
</pre>
<script type="text/javascript">
// The most basic example
$('#examplePadBasic').pad({'padId':'test'}); // sets the pad id and puts the pad in the div
// A slightly more intense example
$('#examplePadIntense').pad({'padId':'test2','showChat':'true'}); // sets the pad id and puts the pad in the div
// An example with plugin parameters
$('#examplePadPlugins').pad({'padId':'test3','plugins':{'pageview':'true'}}); // sets the pad id, some plugin parameters, and puts the pad in the div
</script>
<h3>If you are confused, view the source code for examples</h3>
</body>
</html>

View File

@ -0,0 +1,113 @@
(function( $ ){
$.fn.pad = function( options ) {
var settings = {
'host' : 'http://localhost:9001',
'baseUrl' : '/p/',
'showControls' : false,
'showChat' : false,
'showLineNumbers' : false,
'userName' : 'unnamed',
'lang' : '',
'useMonospaceFont' : false,
'noColors' : false,
'userColor' : false,
'hideQRCode' : false,
'alwaysShowChat' : false,
'width' : 100,
'height' : 100,
'border' : 0,
'borderStyle' : 'solid',
'toggleTextOn' : 'Disable Rich-text',
'toggleTextOff' : 'Enable Rich-text',
'plugins' : {},
'rtl' : false
};
var $self = this;
if (!$self.length) return;
if (!$self.attr('id')) throw new Error('No "id" attribute');
var useValue = $self[0].tagName.toLowerCase() == 'textarea';
var selfId = $self.attr('id');
var epframeId = 'epframe'+ selfId;
// This writes a new frame if required
if ( !options.getContents ) {
if ( options ) {
$.extend( settings, options );
}
var pluginParams = '';
for(var option in settings.plugins) {
pluginParams += '&' + option + '=' + settings.plugins[option]
}
var iFrameLink = '<iframe id="'+epframeId;
iFrameLink = iFrameLink +'" name="' + epframeId;
iFrameLink = iFrameLink +'" src="' + settings.host+settings.baseUrl+settings.padId;
iFrameLink = iFrameLink + '?showControls=' + settings.showControls;
iFrameLink = iFrameLink + '&showChat=' + settings.showChat;
iFrameLink = iFrameLink + '&showLineNumbers=' + settings.showLineNumbers;
iFrameLink = iFrameLink + '&useMonospaceFont=' + settings.useMonospaceFont;
iFrameLink = iFrameLink + '&userName=' + settings.userName;
if (settings.lang) {
iFrameLink = iFrameLink + '&lang=' + settings.lang;
}
iFrameLink = iFrameLink + '&noColors=' + settings.noColors;
iFrameLink = iFrameLink + '&userColor=' + settings.userColor;
iFrameLink = iFrameLink + '&hideQRCode=' + settings.hideQRCode;
iFrameLink = iFrameLink + '&alwaysShowChat=' + settings.alwaysShowChat;
iFrameLink = iFrameLink + '&rtl=' + settings.rtl;
iFrameLink = iFrameLink + pluginParams;
iFrameLink = iFrameLink +'" style="border:' + settings.border;
iFrameLink = iFrameLink +'; border-style:' + settings.borderStyle;
iFrameLink = iFrameLink +';" width="' + '100%';//settings.width;
iFrameLink = iFrameLink +'" height="' + settings.height;
iFrameLink = iFrameLink +'"></iframe>';
var $iFrameLink = $(iFrameLink);
if (useValue) {
var $toggleLink = $('<a href="#'+ selfId +'">'+ settings.toggleTextOn +'</a>').click(function(){
var $this = $(this);
$this.toggleClass('active');
if ($this.hasClass('active')) $this.text(settings.toggleTextOff);
$self.pad({getContents: true});
return false;
});
$self
.hide()
.after($toggleLink)
.after($iFrameLink)
;
}
else {
$self.html(iFrameLink);
}
}
// This reads the etherpad contents if required
else {
var frameUrl = $('#'+ epframeId).attr('src').split('?')[0];
var contentsUrl = frameUrl + "/export/html";
var target = $('#'+ options.getContents);
// perform an ajax call on contentsUrl and write it to the parent
$.get(contentsUrl, function(data) {
if (target.is(':input')) {
target.val(data).show();
}
else {
target.html(data);
}
$('#'+ epframeId).remove();
});
}
return $self;
};
})( jQuery );

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -28,7 +28,7 @@
*
* @type object
*/
window.app = {classes: {}};
app = {classes: {}};
/**
* Common base class for application javascript
@ -145,13 +145,14 @@ var AppJS = (function(){ "use strict"; return Class.extend(
/**
* Clean up any created objects & references
* @param {pbject} _app local app object
*/
destroy: function() {
destroy: function(_app) {
delete this.et2;
if (this.sidebox)
this.sidebox.off();
delete this.sidebox;
delete window.app[this.appname];
if (!_app) delete window.app[this.appname];
},
/**
@ -387,28 +388,45 @@ var AppJS = (function(){ "use strict"; return Class.extend(
*
* @param {object} _action
* @param {object} _senders
* @param {boolean} _noEdit defines whether to set edit button or not default is false
* @param {function} callback function to run after et2 is loaded
*/
viewEntry: function(_action, _senders)
viewEntry: function(_action, _senders, _noEdit, et2_callback)
{
// app id in nm
//full id in nm
var id = _senders[0].id;
// entry id
var id_app = '';
// flag for edit button
var noEdit = _noEdit || false;
// nm row id
var rowID = '';
// content to feed to etemplate2
var content = {};
var self = this;
if (id){
id_app = id.split('::');
var parts = id.split('::');
rowID = parts[1];
content = egw.dataGetUIDdata(id);
if (content.data) content = content.data;
}
// create a new app object with just constructors for our new etemplate2 object
var app = { classes: window.app.classes };
/* destroy generated etemplate for view mode in DOM*/
var destroy = function(){
self.viewContainer.remove();
delete self.viewTemplate;
delete self.viewContainer;
delete self.et2_view;
this.destroy(app);
// we need to reference back into parent context this
for (var v in self)
{
this[v] = self[v];
}
app = null;
};
// view container
@ -432,39 +450,40 @@ var AppJS = (function(){ "use strict"; return Class.extend(
// close button
var close = jQuery(document.createElement('span'))
.addClass('egw_fw_mobile_popup_close loaded')
.click(function(){destroy();})
.click(function(){destroy.call(app[self.appname]);})
.appendTo(this.viewContainer);
// edit button
var edit = jQuery(document.createElement('span'))
.addClass('mobile-view-editBtn')
.click(function(){
egw.open(id_app[1], self.appname);
})
.text(egw.lang('Edit'))
.appendTo(this.viewContainer);
if (!noEdit)
{
// edit button
var edit = jQuery(document.createElement('span'))
.addClass('mobile-view-editBtn')
.click(function(){
egw.open(rowID, self.appname);
})
.text(egw.lang('Edit'))
.appendTo(this.viewContainer);
}
// view template main container (content)
this.viewTemplate = jQuery(document.createElement('div'))
.attr('id', this.appname+'-view')
.addClass('et2_mobile-view-container')
.appendTo(this.viewContainer);
var templateName = _action.data.mobileViewTemplate || 'edit.xet';
var etemplate = new etemplate2 (this.viewTemplate[0], false);
var template = egw.webserverUrl+ '/' + this.appname + '/templates/mobile/'+templateName+'?1';
var data = {content:content, readonlys:{'__ALL__':true,'link_to':false}, currentapp:id_app[0]};
if(template.indexOf('.xet') > 0)
var templateName = _action.data.mobileViewTemplate || 'edit';
var templateURL = egw.webserverUrl+ '/' + this.appname + '/templates/mobile/'+templateName+'.xet'+'?1';
var data = {content:content, readonlys:{'__ALL__':true,'link_to':false}, currentapp:this.appname};
// etemplate2 object for view
this.et2_view = new etemplate2 (this.viewTemplate[0], false);
if(templateName)
{
// File name provided, fetch from server
etemplate.load("",template, data, function() {});
}
else
{
// Just template name, it better be loaded already
etemplate.load(template,'',data);
this.et2_view.load(this.appname+'.'+templateName,templateURL, data, typeof et2_callback == 'function'?et2_callback:function(){}, app);
}
// define a global close function for view template
// in order to be able to destroy view on action
app[this.appname]['close'] = destroy;
},
/**