diff --git a/ep.json b/ep.json index 33c2dbd..6c5aa79 100644 --- a/ep.json +++ b/ep.json @@ -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" } } ] } + + diff --git a/index.js b/index.js new file mode 100644 index 0000000..8eb4d2c --- /dev/null +++ b/index.js @@ -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 "" + context.text.substring(1) + ""; + } +} + +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; +} + + diff --git a/package.json b/package.json index cf33e8d..a2a23f0 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/page_view.js b/page_view.js index cdd79d0..4c3bfac 100644 --- a/page_view.js +++ b/page_view.js @@ -12,3 +12,13 @@ exports.eejsBlock_styles = function (hook_name, args, cb) { args.content = args.content + ''; } + +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 + "
  • Page View
  • "; +} + + diff --git a/static/css/iframe.css b/static/css/iframe.css new file mode 100644 index 0000000..d7b90a6 --- /dev/null +++ b/static/css/iframe.css @@ -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; +} + diff --git a/static/css/page_view.css b/static/css/page_view.css index 64499e0..1c782ee 100644 --- a/static/css/page_view.css +++ b/static/css/page_view.css @@ -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;*/ } -} \ No newline at end of file +} diff --git a/static/js/page_view.js b/static/js/page_view.js index 8f85900..3ebbd00 100644 --- a/static/js/page_view.js +++ b/static/js/page_view.js @@ -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: '
    ', + postHtml: '
    ', + 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: '
    ', + extraCloseTags: '
    ', + 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); +} + diff --git a/static/js/shared.js b/static/js/shared.js new file mode 100644 index 0000000..1cbf3bc --- /dev/null +++ b/static/js/shared.js @@ -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; + + diff --git a/templates/page_view_menu.ejs b/templates/page_view_menu.ejs new file mode 100644 index 0000000..96d9be6 --- /dev/null +++ b/templates/page_view_menu.ejs @@ -0,0 +1,2 @@ +
  • Page Break
  • +