version 2 of page view, complete rewrite for the most part

This commit is contained in:
John McLear 2013-12-01 23:10:12 +00:00
parent 4fb604d7c0
commit 8ead6b5ae7
9 changed files with 289 additions and 6 deletions

19
ep.json
View file

@ -3,12 +3,27 @@
{
"name": "page_view",
"client_hooks": {
"postAceInit": "ep_page_view/static/js/page_view:postAceInit"
"postAceInit": "ep_page_view/static/js/page_view",
"aceEditorCSS": "ep_page_view/static/js/page_view",
"aceCreateDomLine": "ep_page_view/static/js/page_view",
"aceAttribsToClasses": "ep_page_view/static/js/page_view",
"aceDomLineProcessLineAttributes": "ep_page_view/static/js/page_view",
"collectContentPre": "ep_page_view/static/js/shared",
"aceInitialized": "ep_page_view/static/js/page_view",
"aceKeyEvent": "ep_page_view/static/js/page_view",
"aceEditEvent": "ep_page_view/static/js/page_view"
},
"hooks": {
"eejsBlock_mySettings": "ep_page_view/page_view",
"eejsBlock_styles": "ep_page_view/page_view"
"eejsBlock_styles": "ep_page_view/page_view",
"collectContentPre": "ep_page_view/static/js/shared",
"collectContentPost": "ep_page_view/static/js/shared",
"getLineHTMLForExport": "ep_page_view/index",
"eejsBlock_dd_insert" : "ep_page_view/page_view",
"eejsBlock_dd_view" : "ep_page_view/page_view"
}
}
]
}

33
index.js Normal file
View file

@ -0,0 +1,33 @@
var eejs = require('ep_etherpad-lite/node/eejs/');
var Changeset = require("ep_etherpad-lite/static/js/Changeset");
exports.eejsBlock_editbarMenuLeft = function (hook_name, args, cb) {
args.content = args.content + eejs.require("ep_page_view/templates/editbarButtons.ejs");
return cb();
}
function getInlineStyle(pageBreak) {
return "pageBreak: "+pageBreak+";";
}
// line, apool,attribLine,text
exports.getLineHTMLForExport = function (hook, context) {
var header = _analyzeLine(context.attribLine, context.apool);
if (header) {
var inlineStyle = getInlineStyle(header);
return "<span style='page-break-before: always;page-break-inside: avoid;'>" + context.text.substring(1) + "</span>";
}
}
function _analyzeLine(alineAttrs, apool) {
var header = null;
if (alineAttrs) {
var opIter = Changeset.opIterator(alineAttrs);
if (opIter.hasNext()) {
var op = opIter.next();
header = Changeset.opAttributeValue(op, 'pageBreak', apool);
}
}
return header;
}

View file

@ -1,6 +1,6 @@
{
"name": "ep_page_view",
"version": "0.2.2",
"version": "0.3.1",
"keywords": ["page view", "pv", "preview", "overview"],
"description": "Add support to do 'page view', with a toggle on/off option in Settings",

View file

@ -12,3 +12,13 @@ exports.eejsBlock_styles = function (hook_name, args, cb)
{
args.content = args.content + '<link href="../static/plugins/ep_page_view/static/css/page_view.css" rel="stylesheet">';
}
exports.eejsBlock_dd_insert = function (hook_name, args, cb){
args.content = args.content + eejs.require('ep_page_view/templates/page_view_menu.ejs', {checked : checked_state});
}
exports.eejsBlock_dd_view = function (hook_name, args, cb){
args.content = args.content + "<li><a href='#' onClick='$(\"#options-pageview\").click();'>Page View</a></li>";
}

37
static/css/iframe.css Normal file
View file

@ -0,0 +1,37 @@
.pageBreak{
page-break-after: always;
-webkit-region-break-inside: avoid;
border-bottom: 1px dotted #AAA;
width:100%;
height:1px;
}
.pageBreakComputed{
page-break-after: always;
-webkit-region-break-inside: avoid;
border-bottom: 1px dotted #AAA;
}
#outerdocbody > iframe{
left:0px !important;
width:850px !important;
margin:auto;
}
#outerdocbody{
background-color:#f7f7f7;
margin:none;
border:none;
}
#innerdocbody{
padding:100px 100px 100px 100px;
background-color:#fff;
border-radius: 5px 5px 0 0;
border: 1px solid #ccc;
border-width: 1px 1px 0 1px;
position: relative;
box-shadow: 10px 20px 40px 20px #ddd;
}

View file

@ -4,15 +4,17 @@
overflow: hidden;
background-color: #f7f7f7;
text-align: center;
padding-top: 27px;
padding-top: 16px;
}
iframe.page_view {
/*
border-radius: 5px 5px 0 0;
border: 1px solid #ccc;
border-width: 1px 1px 0 1px;
position: relative;
max-width: 850px;
*/
/* max-width: 850px;*/
}
}
}

View file

@ -1,3 +1,7 @@
var _, $, jQuery;
var $ = require('ep_etherpad-lite/static/js/rjquery').$;
var _ = require('ep_etherpad-lite/static/js/underscore');
var isMobile = $.browser.mobile;
if (!isMobile) {
@ -33,6 +37,12 @@ if (!isMobile) {
$('#options-pageview').attr('checked',false);
pv.disable();
}
// Bind the event handler to the toolbar buttons
$('#insertPageBreak').on('click', function(){
context.ace.callWithAce(function(ace){
ace.ace_doInsertPageBreak();
},'insertPageBreak' , true);
});
};
exports.postAceInit = postAceInit;
} else {
@ -52,3 +62,149 @@ function getParam(sname){
  }
  return sval;
}
exports.aceEditorCSS = function(hook_name, cb){
return ["/ep_page_view/static/css/iframe.css"];
} // inner pad CSS
// Our PageBreak attribute will result in a PageBreak:1 class
exports.aceAttribsToClasses = function(hook, context){
if(context.key == 'pageBreak'){
return ['pageBreak:' + 1 ];
}
}
/***
*
* Add the Javascript to Ace inner head, this is for the onClick listener
*
***/
exports.aceDomLineProcessLineAttributes = function(name, context){
if( context.cls.indexOf("pageBreak") !== -1) { var type="pageBreak"; }
var tagIndex = context.cls.indexOf(type);
if (tagIndex !== undefined && type){
// NOTE THE INLINE CSS IS REQUIRED FOR IT TO WORK WITH PRINTING! Or is it?
var modifier = {
preHtml: '<div class="pageBreak" style="page-break-after:always;page-break-inside:avoid;-webkit-region-break-inside: avoid;">',
postHtml: '</div>',
processedMarker: true
};
return [modifier]; // return the modifier
}
return []; // or return nothing
};
// Here we convert the class pageBreak into a tag
exports.aceCreateDomLine = function(name, context){
var cls = context.cls;
var domline = context.domline;
var pageBreak = /(?:^| )pageBreak:([A-Za-z0-9]*)/.exec(cls);
var tagIndex;
if (pageBreak){
var modifier = {
extraOpenTags: '<div class=pageBreak>',
extraCloseTags: '</div>',
cls: cls
};
return [modifier];
}
return [];
};
function doInsertPageBreak(){
this.editorInfo.ace_doReturnKey();
var rep = this.rep;
var documentAttributeManager = this.documentAttributeManager;
if (!(rep.selStart && rep.selEnd)){ return; } // only continue if we have some caret position
var firstLine = rep.selStart[0]; // Get the first line
var lastLine = Math.max(firstLine, rep.selEnd[0] - ((rep.selEnd[1] === 0) ? 1 : 0)); // Get the last line
_(_.range(firstLine, lastLine + 1)).each(function(i){ // For each line, either turn on or off task list
var isPageBreak = documentAttributeManager.getAttributeOnLine(i, 'pageBreak');
if(!isPageBreak){ // if its already a PageBreak item
documentAttributeManager.setAttributeOnLine(i, 'pageBreak', 'pageBreak'); // make the line a task list
}else{
documentAttributeManager.removeAttributeOnLine(i, 'pageBreak'); // remove the task list from the line
}
});
this.editorInfo.ace_focus();
this.editorInfo.ace_doReturnKey();
}
// Once ace is initialized, we set ace_doInsertPageBreak and bind it to the context
exports.aceInitialized = function(hook, context){
var editorInfo = context.editorInfo;
editorInfo.ace_doInsertPageBreak = _(doInsertPageBreak).bind(context);
}
// Listen for Control Enter and if it is control enter then insert page break
exports.aceKeyEvent = function(hook, callstack, editorInfo, rep, documentAttributeManager, evt){
var evt = callstack.evt;
var k = evt.keyCode;
if(evt.ctrlKey && k == 13 && evt.type == "keyup" ){
callstack.editorInfo.ace_doInsertPageBreak();
evt.preventDefault();
return true;
}else{
return;
}
}
exports.aceEditEvent = function(hook, callstack, editorInfo, rep, documentAttributeManager){
if(!callstack.callstack.docTextChanged) return;
var lines = {};
var yHeight = 1122.5; // This is dirty and I feel bad for it..
var lineNumber = 0;
var HTMLLines = $('iframe[name="ace_outer"]').contents().find('iframe').contents().find("#innerdocbody").children("div");
$(HTMLLines).each(function(){ // For each line
var y = $(this).context.offsetTop;
var id = $(this)[0].id; // get the id of the link
var height = $(this).height();
// How many PX since last break?
var lastLine = lineNumber-1;
if(!lines[lastLine]){
var previousY = 0;
var pxSinceLastBreak = 0;
}else{
var previousY = lines[lastLine].pxSinceLastBreak;
var pxSinceLastBreak = previousY + height;
}
// Does it already have any children with teh class pageBreak?
var manualBreak = $(this).children().hasClass("pageBreak");
// If it's a manualBreak then reset pxSinceLastBreak to 0;
if(manualBreak) pxSinceLastBreak = 0;
// Should this be a line break?
var computedBreak = ((pxSinceLastBreak + height) >= yHeight);
if(computedBreak){
// console.log(id, "should be a page break");
$(this).addClass("pageBreakComputed");
pxSinceLastBreak = 0;
}else{
$(this).removeClass("pageBreakComputed");
}
lines[lineNumber] = {
pxSinceLastBreak : pxSinceLastBreak,
manualBreak : manualBreak,
computedBreak : computedBreak,
id : id,
y : y,
height : height
}
lineNumber++;
});
// console.log(lines);
}

28
static/js/shared.js Normal file
View file

@ -0,0 +1,28 @@
var _ = require('ep_etherpad-lite/static/js/underscore');
var collectContentPre = function(hook, context){
var tname = context.tname;
var state = context.state;
var lineAttributes = state.lineAttributes
var tagIndex = tname;
if(tagIndex >= 0){
lineAttributes['pageBreak'] = tagIndex;
}
};
var collectContentPost = function(hook, context){
var tname = context.tname;
var state = context.state;
var lineAttributes = state.lineAttributes
var tagIndex = tname;
if(tagIndex >= 0){
delete lineAttributes['pageBreak'];
}
};
exports.collectContentPre = collectContentPre;
exports.collectContentPost = collectContentPost;

View file

@ -0,0 +1,2 @@
<li><span id='insertPageBreak'>Page Break</span></li>