diff --git a/src/static/js/ace.js b/src/static/js/ace.js index e08036fa9..ff3b32080 100644 --- a/src/static/js/ace.js +++ b/src/static/js/ace.js @@ -199,28 +199,7 @@ define(['ep_etherpad-lite/static/js/pluginfw/hooks', 'underscore'], function (ho ')); iframeHTML.push(''); - - iframeHTML.push(scriptTag('\n\ - var pathComponents = parent.parent.location.pathname.split("/");\n\ - var baseURL = pathComponents.slice(0,pathComponents.length-2).join("/") + "/";\n\ - requirejs.config({\n\ - baseUrl: baseURL + "static/plugins",\n\ - paths: {underscore: baseURL + "static/plugins/underscore/underscore"}\n\ - });\n\ - \n\ - requirejs(["ep_etherpad-lite/static/js/rjquery", "ep_etherpad-lite/static/js/pluginfw/client_plugins", "ep_etherpad-lite/static/js/ace2_inner"], function (j, plugins, Ace2Inner) {\n\ - jQuery = $ = window.jQuery = window.$ = j; // Expose jQuery #HACK\n\ - \n\ - plugins.adoptPluginsFromAncestorsOf(window, function () {\n\ - var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks");\n\ - hooks.plugins = plugins;\n\ - \n\ - plugins.ensure(function () {\n\ - Ace2Inner.init();\n\ - });\n\ - });\n\ - });\n\ - ')); + iframeHTML.push(''); iframeHTML.push(''); diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index f8c2565ea..8ed7f91b1 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -20,7 +20,9 @@ * limitations under the License. */ -define(["ep_etherpad-lite/static/js/rjquery", "underscore", 'ep_etherpad-lite/static/js/pluginfw/hooks'], function ($, _, hooks) { +define(["ep_etherpad-lite/static/js/rjquery", "underscore", 'ep_etherpad-lite/static/js/pluginfw/hooks', 'ep_etherpad-lite/static/js/linestylefilter', 'ep_etherpad-lite/static/js/domline'], function ($, _, hooks, linestylefilterMod, domlineMod) { + var linestylefilter = linestylefilterMod.linestylefilter; + var domline = domlineMod.domline; var exports = {}; var browser = require('./browser').browser; @@ -50,11 +52,9 @@ function Ace2Inner(){ var colorutils = require('./colorutils').colorutils; var makeContentCollector = require('./contentcollector').makeContentCollector; var makeCSSManager = require('./cssmanager').makeCSSManager; - var domline = require('./domline').domline; var AttribPool = require('./AttributePool'); var Changeset = require('./Changeset'); var ChangesetUtils = require('./ChangesetUtils'); - var linestylefilter = require('./linestylefilter').linestylefilter; var SkipList = require('./skiplist'); var undoModule = require('./undomodule').undoModule; var AttributeManager = require('./AttributeManager'); @@ -475,6 +475,7 @@ function Ace2Inner(){ //console.log("Just did action for: "+type); cleanExit = true; } +/* catch (e) { caughtErrors.push( @@ -485,6 +486,7 @@ function Ace2Inner(){ dmesg(e.toString()); throw e; } +*/ finally { var cs = currentCallStack; diff --git a/src/static/js/ace2_inner_main.js b/src/static/js/ace2_inner_main.js new file mode 100644 index 000000000..21b77a5b6 --- /dev/null +++ b/src/static/js/ace2_inner_main.js @@ -0,0 +1,26 @@ +var pathComponents = parent.parent.location.pathname.split("/"); +var baseURL = pathComponents.slice(0,pathComponents.length-2).join("/") + "/"; +requirejs.config({ + baseUrl: baseURL + "static/plugins", + paths: {underscore: baseURL + "static/plugins/underscore/underscore"} +}); + +requirejs( + [ + "ep_etherpad-lite/static/js/rjquery", + "ep_etherpad-lite/static/js/pluginfw/client_plugins", + "ep_etherpad-lite/static/js/pluginfw/hooks", + "ep_etherpad-lite/static/js/ace2_inner" + ], + function (j, plugins, hooks, Ace2Inner) { + jQuery = $ = window.jQuery = window.$ = j; // Expose jQuery #HACK + + plugins.adoptPluginsFromAncestorsOf(window, function () { + hooks.plugins = plugins; + + plugins.ensure(function () { + Ace2Inner.init(); + }); + }); + } +); diff --git a/src/static/js/broadcast.js b/src/static/js/broadcast.js index 983402683..75560a9ad 100644 --- a/src/static/js/broadcast.js +++ b/src/static/js/broadcast.js @@ -20,577 +20,580 @@ * limitations under the License. */ -var makeCSSManager = require('./cssmanager').makeCSSManager; -var domline = require('./domline').domline; -var AttribPool = require('./AttributePool'); -var Changeset = require('./Changeset'); -var linestylefilter = require('./linestylefilter').linestylefilter; -var colorutils = require('./colorutils').colorutils; -var _ = require('./underscore'); -var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks'); +define(['ep_etherpad-lite/static/js/pluginfw/hooks', 'ep_etherpad-lite/static/js/linestylefilter', 'ep_etherpad-lite/static/js/domline', 'underscore'], function (hooks, linetyleFilterMod, domlineMod, _) { + var exports = {}; + var makeCSSManager = require('./cssmanager').makeCSSManager; + var domline = domlineMod.domline; + var AttribPool = require('./AttributePool'); + var Changeset = require('./Changeset'); + var linestylefilter = linetyleFilterMod.linestylefilter; + var colorutils = require('./colorutils').colorutils; -// These parameters were global, now they are injected. A reference to the -// Timeslider controller would probably be more appropriate. -function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, BroadcastSlider) -{ - var changesetLoader = undefined; - - // Below Array#indexOf code was direct pasted by AppJet/Etherpad, licence unknown. Possible source: http://www.tutorialspoint.com/javascript/array_indexof.htm - if (!Array.prototype.indexOf) + // These parameters were global, now they are injected. A reference to the + // Timeslider controller would probably be more appropriate. + function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, BroadcastSlider) { - Array.prototype.indexOf = function(elt /*, from*/ ) + var changesetLoader = undefined; + + // Below Array#indexOf code was direct pasted by AppJet/Etherpad, licence unknown. Possible source: http://www.tutorialspoint.com/javascript/array_indexof.htm + if (!Array.prototype.indexOf) { - var len = this.length >>> 0; - - var from = Number(arguments[1]) || 0; - from = (from < 0) ? Math.ceil(from) : Math.floor(from); - if (from < 0) from += len; - - for (; from < len; from++) + Array.prototype.indexOf = function(elt /*, from*/ ) { - if (from in this && this[from] === elt) return from; - } - return -1; - }; - } + var len = this.length >>> 0; - function debugLog() - { - try - { - if (window.console) console.log.apply(console, arguments); - } - catch (e) - { - if (window.console) console.log("error printing: ", e); - } - } + var from = Number(arguments[1]) || 0; + from = (from < 0) ? Math.ceil(from) : Math.floor(from); + if (from < 0) from += len; - //var socket; - var channelState = "DISCONNECTED"; - - var appLevelDisconnectReason = null; - - var padContents = { - currentRevision: clientVars.collab_client_vars.rev, - currentTime: clientVars.collab_client_vars.time, - currentLines: Changeset.splitTextLines(clientVars.collab_client_vars.initialAttributedText.text), - currentDivs: null, - // to be filled in once the dom loads - apool: (new AttribPool()).fromJsonable(clientVars.collab_client_vars.apool), - alines: Changeset.splitAttributionLines( - clientVars.collab_client_vars.initialAttributedText.attribs, clientVars.collab_client_vars.initialAttributedText.text), - - // generates a jquery element containing HTML for a line - lineToElement: function(line, aline) - { - var element = document.createElement("div"); - var emptyLine = (line == '\n'); - var domInfo = domline.createDomLine(!emptyLine, true); - linestylefilter.populateDomLine(line, aline, this.apool, domInfo); - domInfo.prepareForAdd(); - element.className = domInfo.node.className; - element.innerHTML = domInfo.node.innerHTML; - element.id = Math.random(); - return $(element); - }, - - applySpliceToDivs: function(start, numRemoved, newLines) - { - // remove spliced-out lines from DOM - for (var i = start; i < start + numRemoved && i < this.currentDivs.length; i++) - { - debugLog("removing", this.currentDivs[i].attr('id')); - this.currentDivs[i].remove(); - } - - // remove spliced-out line divs from currentDivs array - this.currentDivs.splice(start, numRemoved); - - var newDivs = []; - for (var i = 0; i < newLines.length; i++) - { - newDivs.push(this.lineToElement(newLines[i], this.alines[start + i])); - } - - // grab the div just before the first one - var startDiv = this.currentDivs[start - 1] || null; - - // insert the div elements into the correct place, in the correct order - for (var i = 0; i < newDivs.length; i++) - { - if (startDiv) + for (; from < len; from++) { - startDiv.after(newDivs[i]); + if (from in this && this[from] === elt) return from; } - else - { - $("#padcontent").prepend(newDivs[i]); - } - startDiv = newDivs[i]; - } - - // insert new divs into currentDivs array - newDivs.unshift(0); // remove 0 elements - newDivs.unshift(start); - this.currentDivs.splice.apply(this.currentDivs, newDivs); - return this; - }, - - // splice the lines - splice: function(start, numRemoved, newLinesVA) - { - var newLines = _.map(Array.prototype.slice.call(arguments, 2), function(s) { - return s; - }); - - // apply this splice to the divs - this.applySpliceToDivs(start, numRemoved, newLines); - - // call currentLines.splice, to keep the currentLines array up to date - newLines.unshift(numRemoved); - newLines.unshift(start); - this.currentLines.splice.apply(this.currentLines, arguments); - }, - // returns the contents of the specified line I - get: function(i) - { - return this.currentLines[i]; - }, - // returns the number of lines in the document - length: function() - { - return this.currentLines.length; - }, - - getActiveAuthors: function() - { - var self = this; - var authors = []; - var seenNums = {}; - var alines = self.alines; - for (var i = 0; i < alines.length; i++) - { - Changeset.eachAttribNumber(alines[i], function(n) - { - if (!seenNums[n]) - { - seenNums[n] = true; - if (self.apool.getAttribKey(n) == 'author') - { - var a = self.apool.getAttribValue(n); - if (a) - { - authors.push(a); - } - } - } - }); - } - authors.sort(); - return authors; + return -1; + }; } - }; - function callCatchingErrors(catcher, func) - { - try - { - wrapRecordingErrors(catcher, func)(); - } - catch (e) - { /*absorb*/ - } - } - - function wrapRecordingErrors(catcher, func) - { - return function() + function debugLog() { try { - return func.apply(this, Array.prototype.slice.call(arguments)); + if (window.console) console.log.apply(console, arguments); } catch (e) { - // caughtErrors.push(e); - // caughtErrorCatchers.push(catcher); - // caughtErrorTimes.push(+new Date()); - // console.dir({catcher: catcher, e: e}); - debugLog(e); // TODO(kroo): added temporary, to catch errors - throw e; + if (window.console) console.log("error printing: ", e); + } + } + + //var socket; + var channelState = "DISCONNECTED"; + + var appLevelDisconnectReason = null; + + var padContents = { + currentRevision: clientVars.collab_client_vars.rev, + currentTime: clientVars.collab_client_vars.time, + currentLines: Changeset.splitTextLines(clientVars.collab_client_vars.initialAttributedText.text), + currentDivs: null, + // to be filled in once the dom loads + apool: (new AttribPool()).fromJsonable(clientVars.collab_client_vars.apool), + alines: Changeset.splitAttributionLines( + clientVars.collab_client_vars.initialAttributedText.attribs, clientVars.collab_client_vars.initialAttributedText.text), + + // generates a jquery element containing HTML for a line + lineToElement: function(line, aline) + { + var element = document.createElement("div"); + var emptyLine = (line == '\n'); + var domInfo = domline.createDomLine(!emptyLine, true); + linestylefilter.populateDomLine(line, aline, this.apool, domInfo); + domInfo.prepareForAdd(); + element.className = domInfo.node.className; + element.innerHTML = domInfo.node.innerHTML; + element.id = Math.random(); + return $(element); + }, + + applySpliceToDivs: function(start, numRemoved, newLines) + { + // remove spliced-out lines from DOM + for (var i = start; i < start + numRemoved && i < this.currentDivs.length; i++) + { + debugLog("removing", this.currentDivs[i].attr('id')); + this.currentDivs[i].remove(); + } + + // remove spliced-out line divs from currentDivs array + this.currentDivs.splice(start, numRemoved); + + var newDivs = []; + for (var i = 0; i < newLines.length; i++) + { + newDivs.push(this.lineToElement(newLines[i], this.alines[start + i])); + } + + // grab the div just before the first one + var startDiv = this.currentDivs[start - 1] || null; + + // insert the div elements into the correct place, in the correct order + for (var i = 0; i < newDivs.length; i++) + { + if (startDiv) + { + startDiv.after(newDivs[i]); + } + else + { + $("#padcontent").prepend(newDivs[i]); + } + startDiv = newDivs[i]; + } + + // insert new divs into currentDivs array + newDivs.unshift(0); // remove 0 elements + newDivs.unshift(start); + this.currentDivs.splice.apply(this.currentDivs, newDivs); + return this; + }, + + // splice the lines + splice: function(start, numRemoved, newLinesVA) + { + var newLines = _.map(Array.prototype.slice.call(arguments, 2), function(s) { + return s; + }); + + // apply this splice to the divs + this.applySpliceToDivs(start, numRemoved, newLines); + + // call currentLines.splice, to keep the currentLines array up to date + newLines.unshift(numRemoved); + newLines.unshift(start); + this.currentLines.splice.apply(this.currentLines, arguments); + }, + // returns the contents of the specified line I + get: function(i) + { + return this.currentLines[i]; + }, + // returns the number of lines in the document + length: function() + { + return this.currentLines.length; + }, + + getActiveAuthors: function() + { + var self = this; + var authors = []; + var seenNums = {}; + var alines = self.alines; + for (var i = 0; i < alines.length; i++) + { + Changeset.eachAttribNumber(alines[i], function(n) + { + if (!seenNums[n]) + { + seenNums[n] = true; + if (self.apool.getAttribKey(n) == 'author') + { + var a = self.apool.getAttribValue(n); + if (a) + { + authors.push(a); + } + } + } + }); + } + authors.sort(); + return authors; } }; - } - function loadedNewChangeset(changesetForward, changesetBackward, revision, timeDelta) - { - var broadcasting = (BroadcastSlider.getSliderPosition() == revisionInfo.latest); - debugLog("broadcasting:", broadcasting, BroadcastSlider.getSliderPosition(), revisionInfo.latest, revision); - revisionInfo.addChangeset(revision, revision + 1, changesetForward, changesetBackward, timeDelta); - BroadcastSlider.setSliderLength(revisionInfo.latest); - if (broadcasting) applyChangeset(changesetForward, revision + 1, false, timeDelta); - } - - /* - At this point, we must be certain that the changeset really does map from - the current revision to the specified revision. Any mistakes here will - cause the whole slider to get out of sync. - */ - - function applyChangeset(changeset, revision, preventSliderMovement, timeDelta) - { - // disable the next 'gotorevision' call handled by a timeslider update - if (!preventSliderMovement) + function callCatchingErrors(catcher, func) { - goToRevisionIfEnabledCount++; - BroadcastSlider.setSliderPosition(revision); + try + { + wrapRecordingErrors(catcher, func)(); + } + catch (e) + { /*absorb*/ + } } - try + function wrapRecordingErrors(catcher, func) { - // must mutate attribution lines before text lines - Changeset.mutateAttributionLines(changeset, padContents.alines, padContents.apool); - } - catch (e) - { - debugLog(e); + return function() + { + try + { + return func.apply(this, Array.prototype.slice.call(arguments)); + } + catch (e) + { + // caughtErrors.push(e); + // caughtErrorCatchers.push(catcher); + // caughtErrorTimes.push(+new Date()); + // console.dir({catcher: catcher, e: e}); + debugLog(e); // TODO(kroo): added temporary, to catch errors + throw e; + } + }; } - Changeset.mutateTextLines(changeset, padContents); - padContents.currentRevision = revision; - padContents.currentTime += timeDelta * 1000; + function loadedNewChangeset(changesetForward, changesetBackward, revision, timeDelta) + { + var broadcasting = (BroadcastSlider.getSliderPosition() == revisionInfo.latest); + debugLog("broadcasting:", broadcasting, BroadcastSlider.getSliderPosition(), revisionInfo.latest, revision); + revisionInfo.addChangeset(revision, revision + 1, changesetForward, changesetBackward, timeDelta); + BroadcastSlider.setSliderLength(revisionInfo.latest); + if (broadcasting) applyChangeset(changesetForward, revision + 1, false, timeDelta); + } + + /* + At this point, we must be certain that the changeset really does map from + the current revision to the specified revision. Any mistakes here will + cause the whole slider to get out of sync. + */ + + function applyChangeset(changeset, revision, preventSliderMovement, timeDelta) + { + // disable the next 'gotorevision' call handled by a timeslider update + if (!preventSliderMovement) + { + goToRevisionIfEnabledCount++; + BroadcastSlider.setSliderPosition(revision); + } + + try + { + // must mutate attribution lines before text lines + Changeset.mutateAttributionLines(changeset, padContents.alines, padContents.apool); + } + catch (e) + { + debugLog(e); + } + + Changeset.mutateTextLines(changeset, padContents); + padContents.currentRevision = revision; + padContents.currentTime += timeDelta * 1000; + + debugLog('Time Delta: ', timeDelta) + updateTimer(); + + var authors = _.map(padContents.getActiveAuthors(), function(name) + { + return authorData[name]; + }); + + BroadcastSlider.setAuthors(authors); + } + + function updateTimer() + { + var zpad = function(str, length) + { + str = str + ""; + while (str.length < length) + str = '0' + str; + return str; + } + + var date = new Date(padContents.currentTime); + var dateFormat = function() + { + var month = zpad(date.getMonth() + 1, 2); + var day = zpad(date.getDate(), 2); + var year = (date.getFullYear()); + var hours = zpad(date.getHours(), 2); + var minutes = zpad(date.getMinutes(), 2); + var seconds = zpad(date.getSeconds(), 2); + return (html10n.get("timeslider.dateformat", { + "day": day, + "month": month, + "year": year, + "hours": hours, + "minutes": minutes, + "seconds": seconds + })); + } + + + + + + $('#timer').html(dateFormat()); + var revisionDate = html10n.get("timeslider.saved", { + "day": date.getDate(), + "month": [ + html10n.get("timeslider.month.january"), + html10n.get("timeslider.month.february"), + html10n.get("timeslider.month.march"), + html10n.get("timeslider.month.april"), + html10n.get("timeslider.month.may"), + html10n.get("timeslider.month.june"), + html10n.get("timeslider.month.july"), + html10n.get("timeslider.month.august"), + html10n.get("timeslider.month.september"), + html10n.get("timeslider.month.october"), + html10n.get("timeslider.month.november"), + html10n.get("timeslider.month.december") + ][date.getMonth()], + "year": date.getFullYear() + }); + $('#revision_date').html(revisionDate) + + } - debugLog('Time Delta: ', timeDelta) updateTimer(); - - var authors = _.map(padContents.getActiveAuthors(), function(name) - { - return authorData[name]; - }); - - BroadcastSlider.setAuthors(authors); - } - function updateTimer() - { - var zpad = function(str, length) - { - str = str + ""; - while (str.length < length) - str = '0' + str; - return str; - } - - var date = new Date(padContents.currentTime); - var dateFormat = function() - { - var month = zpad(date.getMonth() + 1, 2); - var day = zpad(date.getDate(), 2); - var year = (date.getFullYear()); - var hours = zpad(date.getHours(), 2); - var minutes = zpad(date.getMinutes(), 2); - var seconds = zpad(date.getSeconds(), 2); - return (html10n.get("timeslider.dateformat", { - "day": day, - "month": month, - "year": year, - "hours": hours, - "minutes": minutes, - "seconds": seconds - })); - } - - - - - - $('#timer').html(dateFormat()); - var revisionDate = html10n.get("timeslider.saved", { - "day": date.getDate(), - "month": [ - html10n.get("timeslider.month.january"), - html10n.get("timeslider.month.february"), - html10n.get("timeslider.month.march"), - html10n.get("timeslider.month.april"), - html10n.get("timeslider.month.may"), - html10n.get("timeslider.month.june"), - html10n.get("timeslider.month.july"), - html10n.get("timeslider.month.august"), - html10n.get("timeslider.month.september"), - html10n.get("timeslider.month.october"), - html10n.get("timeslider.month.november"), - html10n.get("timeslider.month.december") - ][date.getMonth()], - "year": date.getFullYear() - }); - $('#revision_date').html(revisionDate) - - } - - updateTimer(); - - function goToRevision(newRevision) - { - padContents.targetRevision = newRevision; - var self = this; - var path = revisionInfo.getPath(padContents.currentRevision, newRevision); - debugLog('newRev: ', padContents.currentRevision, path); - if (path.status == 'complete') + function goToRevision(newRevision) { - var cs = path.changesets; - debugLog("status: complete, changesets: ", cs, "path:", path); - var changeset = cs[0]; - var timeDelta = path.times[0]; - for (var i = 1; i < cs.length; i++) + padContents.targetRevision = newRevision; + var self = this; + var path = revisionInfo.getPath(padContents.currentRevision, newRevision); + debugLog('newRev: ', padContents.currentRevision, path); + if (path.status == 'complete') { - changeset = Changeset.compose(changeset, cs[i], padContents.apool); - timeDelta += path.times[i]; - } - if (changeset) applyChangeset(changeset, path.rev, true, timeDelta); - } - else if (path.status == "partial") - { - debugLog('partial'); - var sliderLocation = padContents.currentRevision; - // callback is called after changeset information is pulled from server - // this may never get called, if the changeset has already been loaded - var update = function(start, end) + var cs = path.changesets; + debugLog("status: complete, changesets: ", cs, "path:", path); + var changeset = cs[0]; + var timeDelta = path.times[0]; + for (var i = 1; i < cs.length; i++) { - // if we've called goToRevision in the time since, don't goToRevision - goToRevision(padContents.targetRevision); - }; - - // do our best with what we have... - var cs = path.changesets; - - var changeset = cs[0]; - var timeDelta = path.times[0]; - for (var i = 1; i < cs.length; i++) - { - changeset = Changeset.compose(changeset, cs[i], padContents.apool); - timeDelta += path.times[i]; + changeset = Changeset.compose(changeset, cs[i], padContents.apool); + timeDelta += path.times[i]; + } + if (changeset) applyChangeset(changeset, path.rev, true, timeDelta); } - if (changeset) applyChangeset(changeset, path.rev, true, timeDelta); - - // Loading changeset history for new revision - loadChangesetsForRevision(newRevision, update); - // Loading changeset history for old revision (to make diff between old and new revision) - loadChangesetsForRevision(padContents.currentRevision - 1); - } - - var authors = _.map(padContents.getActiveAuthors(), function(name){ - return authorData[name]; - }); - BroadcastSlider.setAuthors(authors); - } - - function loadChangesetsForRevision(revision, callback) { - if (BroadcastSlider.getSliderLength() > 10000) - { - var start = (Math.floor((revision) / 10000) * 10000); // revision 0 to 10 - changesetLoader.queueUp(start, 100); - } - - if (BroadcastSlider.getSliderLength() > 1000) - { - var start = (Math.floor((revision) / 1000) * 1000); // (start from -1, go to 19) + 1 - changesetLoader.queueUp(start, 10); - } - - start = (Math.floor((revision) / 100) * 100); - - changesetLoader.queueUp(start, 1, callback); - } - - changesetLoader = { - running: false, - resolved: [], - requestQueue1: [], - requestQueue2: [], - requestQueue3: [], - reqCallbacks: [], - queueUp: function(revision, width, callback) - { - if (revision < 0) revision = 0; - // if(changesetLoader.requestQueue.indexOf(revision) != -1) - // return; // already in the queue. - if (changesetLoader.resolved.indexOf(revision + "_" + width) != -1) return; // already loaded from the server - changesetLoader.resolved.push(revision + "_" + width); - - var requestQueue = width == 1 ? changesetLoader.requestQueue3 : width == 10 ? changesetLoader.requestQueue2 : changesetLoader.requestQueue1; - requestQueue.push( + else if (path.status == "partial") { - 'rev': revision, - 'res': width, - 'callback': callback + debugLog('partial'); + var sliderLocation = padContents.currentRevision; + // callback is called after changeset information is pulled from server + // this may never get called, if the changeset has already been loaded + var update = function(start, end) + { + // if we've called goToRevision in the time since, don't goToRevision + goToRevision(padContents.targetRevision); + }; + + // do our best with what we have... + var cs = path.changesets; + + var changeset = cs[0]; + var timeDelta = path.times[0]; + for (var i = 1; i < cs.length; i++) + { + changeset = Changeset.compose(changeset, cs[i], padContents.apool); + timeDelta += path.times[i]; + } + if (changeset) applyChangeset(changeset, path.rev, true, timeDelta); + + // Loading changeset history for new revision + loadChangesetsForRevision(newRevision, update); + // Loading changeset history for old revision (to make diff between old and new revision) + loadChangesetsForRevision(padContents.currentRevision - 1); + } + + var authors = _.map(padContents.getActiveAuthors(), function(name){ + return authorData[name]; }); - if (!changesetLoader.running) - { - changesetLoader.running = true; - setTimeout(changesetLoader.loadFromQueue, 10); - } - }, - loadFromQueue: function() - { - var self = changesetLoader; - var requestQueue = self.requestQueue1.length > 0 ? self.requestQueue1 : self.requestQueue2.length > 0 ? self.requestQueue2 : self.requestQueue3.length > 0 ? self.requestQueue3 : null; + BroadcastSlider.setAuthors(authors); + } - if (!requestQueue) + function loadChangesetsForRevision(revision, callback) { + if (BroadcastSlider.getSliderLength() > 10000) { - self.running = false; - return; + var start = (Math.floor((revision) / 10000) * 10000); // revision 0 to 10 + changesetLoader.queueUp(start, 100); } - var request = requestQueue.pop(); - var granularity = request.res; - var callback = request.callback; - var start = request.rev; - var requestID = Math.floor(Math.random() * 100000); - - sendSocketMsg("CHANGESET_REQ", { - "start": start, - "granularity": granularity, - "requestID": requestID - }); - - self.reqCallbacks[requestID] = callback; - }, - handleSocketResponse: function(message) - { - var self = changesetLoader; - - var start = message.data.start; - var granularity = message.data.granularity; - var callback = self.reqCallbacks[message.data.requestID]; - delete self.reqCallbacks[message.data.requestID]; - - self.handleResponse(message.data, start, granularity, callback); - setTimeout(self.loadFromQueue, 10); - }, - handleResponse: function(data, start, granularity, callback) - { - debugLog("response: ", data); - var pool = (new AttribPool()).fromJsonable(data.apool); - for (var i = 0; i < data.forwardsChangesets.length; i++) + if (BroadcastSlider.getSliderLength() > 1000) { - var astart = start + i * granularity - 1; // rev -1 is a blank single line - var aend = start + (i + 1) * granularity - 1; // totalRevs is the most recent revision - if (aend > data.actualEndNum - 1) aend = data.actualEndNum - 1; - //debugLog("adding changeset:", astart, aend); - var forwardcs = Changeset.moveOpsToNewPool(data.forwardsChangesets[i], pool, padContents.apool); - var backwardcs = Changeset.moveOpsToNewPool(data.backwardsChangesets[i], pool, padContents.apool); - revisionInfo.addChangeset(astart, aend, forwardcs, backwardcs, data.timeDeltas[i]); + var start = (Math.floor((revision) / 1000) * 1000); // (start from -1, go to 19) + 1 + changesetLoader.queueUp(start, 10); } - if (callback) callback(start - 1, start + data.forwardsChangesets.length * granularity - 1); - }, - handleMessageFromServer: function (obj) - { - debugLog("handleMessage:", arguments); - if (obj.type == "COLLABROOM") + start = (Math.floor((revision) / 100) * 100); + + changesetLoader.queueUp(start, 1, callback); + } + + changesetLoader = { + running: false, + resolved: [], + requestQueue1: [], + requestQueue2: [], + requestQueue3: [], + reqCallbacks: [], + queueUp: function(revision, width, callback) { - obj = obj.data; + if (revision < 0) revision = 0; + // if(changesetLoader.requestQueue.indexOf(revision) != -1) + // return; // already in the queue. + if (changesetLoader.resolved.indexOf(revision + "_" + width) != -1) return; // already loaded from the server + changesetLoader.resolved.push(revision + "_" + width); - if (obj.type == "NEW_CHANGES") + var requestQueue = width == 1 ? changesetLoader.requestQueue3 : width == 10 ? changesetLoader.requestQueue2 : changesetLoader.requestQueue1; + requestQueue.push( { - debugLog(obj); - var changeset = Changeset.moveOpsToNewPool( - obj.changeset, (new AttribPool()).fromJsonable(obj.apool), padContents.apool); - - var changesetBack = Changeset.inverse( - obj.changeset, padContents.currentLines, padContents.alines, padContents.apool); - - var changesetBack = Changeset.moveOpsToNewPool( - changesetBack, (new AttribPool()).fromJsonable(obj.apool), padContents.apool); - - loadedNewChangeset(changeset, changesetBack, obj.newRev - 1, obj.timeDelta); - } - else if (obj.type == "NEW_AUTHORDATA") + 'rev': revision, + 'res': width, + 'callback': callback + }); + if (!changesetLoader.running) { - var authorMap = {}; - authorMap[obj.author] = obj.data; - receiveAuthorData(authorMap); - - var authors = _.map(padContents.getActiveAuthors(), function(name) { - return authorData[name]; - }); - - BroadcastSlider.setAuthors(authors); + changesetLoader.running = true; + setTimeout(changesetLoader.loadFromQueue, 10); } - else if (obj.type == "NEW_SAVEDREV") - { - var savedRev = obj.savedRev; - BroadcastSlider.addSavedRevision(savedRev.revNum, savedRev); - } - hooks.callAll('handleClientTimesliderMessage_' + obj.type, {payload: obj}); - } - else if(obj.type == "CHANGESET_REQ") + }, + loadFromQueue: function() { - changesetLoader.handleSocketResponse(obj); + var self = changesetLoader; + var requestQueue = self.requestQueue1.length > 0 ? self.requestQueue1 : self.requestQueue2.length > 0 ? self.requestQueue2 : self.requestQueue3.length > 0 ? self.requestQueue3 : null; + + if (!requestQueue) + { + self.running = false; + return; + } + + var request = requestQueue.pop(); + var granularity = request.res; + var callback = request.callback; + var start = request.rev; + var requestID = Math.floor(Math.random() * 100000); + + sendSocketMsg("CHANGESET_REQ", { + "start": start, + "granularity": granularity, + "requestID": requestID + }); + + self.reqCallbacks[requestID] = callback; + }, + handleSocketResponse: function(message) + { + var self = changesetLoader; + + var start = message.data.start; + var granularity = message.data.granularity; + var callback = self.reqCallbacks[message.data.requestID]; + delete self.reqCallbacks[message.data.requestID]; + + self.handleResponse(message.data, start, granularity, callback); + setTimeout(self.loadFromQueue, 10); + }, + handleResponse: function(data, start, granularity, callback) + { + debugLog("response: ", data); + var pool = (new AttribPool()).fromJsonable(data.apool); + for (var i = 0; i < data.forwardsChangesets.length; i++) + { + var astart = start + i * granularity - 1; // rev -1 is a blank single line + var aend = start + (i + 1) * granularity - 1; // totalRevs is the most recent revision + if (aend > data.actualEndNum - 1) aend = data.actualEndNum - 1; + //debugLog("adding changeset:", astart, aend); + var forwardcs = Changeset.moveOpsToNewPool(data.forwardsChangesets[i], pool, padContents.apool); + var backwardcs = Changeset.moveOpsToNewPool(data.backwardsChangesets[i], pool, padContents.apool); + revisionInfo.addChangeset(astart, aend, forwardcs, backwardcs, data.timeDeltas[i]); + } + if (callback) callback(start - 1, start + data.forwardsChangesets.length * granularity - 1); + }, + handleMessageFromServer: function (obj) + { + debugLog("handleMessage:", arguments); + + if (obj.type == "COLLABROOM") + { + obj = obj.data; + + if (obj.type == "NEW_CHANGES") + { + debugLog(obj); + var changeset = Changeset.moveOpsToNewPool( + obj.changeset, (new AttribPool()).fromJsonable(obj.apool), padContents.apool); + + var changesetBack = Changeset.inverse( + obj.changeset, padContents.currentLines, padContents.alines, padContents.apool); + + var changesetBack = Changeset.moveOpsToNewPool( + changesetBack, (new AttribPool()).fromJsonable(obj.apool), padContents.apool); + + loadedNewChangeset(changeset, changesetBack, obj.newRev - 1, obj.timeDelta); + } + else if (obj.type == "NEW_AUTHORDATA") + { + var authorMap = {}; + authorMap[obj.author] = obj.data; + receiveAuthorData(authorMap); + + var authors = _.map(padContents.getActiveAuthors(), function(name) { + return authorData[name]; + }); + + BroadcastSlider.setAuthors(authors); + } + else if (obj.type == "NEW_SAVEDREV") + { + var savedRev = obj.savedRev; + BroadcastSlider.addSavedRevision(savedRev.revNum, savedRev); + } + hooks.callAll('handleClientTimesliderMessage_' + obj.type, {payload: obj}); + } + else if(obj.type == "CHANGESET_REQ") + { + changesetLoader.handleSocketResponse(obj); + } + else + { + debugLog("Unknown message type: " + obj.type); + } + } + }; + + // to start upon window load, just push a function onto this array + //window['onloadFuncts'].push(setUpSocket); + //window['onloadFuncts'].push(function () + fireWhenAllScriptsAreLoaded.push(function() + { + // set up the currentDivs and DOM + padContents.currentDivs = []; + $("#padcontent").html(""); + for (var i = 0; i < padContents.currentLines.length; i++) + { + var div = padContents.lineToElement(padContents.currentLines[i], padContents.alines[i]); + padContents.currentDivs.push(div); + $("#padcontent").append(div); + } + debugLog(padContents.currentDivs); + }); + + // this is necessary to keep infinite loops of events firing, + // since goToRevision changes the slider position + var goToRevisionIfEnabledCount = 0; + var goToRevisionIfEnabled = function() { + if (goToRevisionIfEnabledCount > 0) + { + goToRevisionIfEnabledCount--; } else { - debugLog("Unknown message type: " + obj.type); + goToRevision.apply(goToRevision, arguments); } } - }; - // to start upon window load, just push a function onto this array - //window['onloadFuncts'].push(setUpSocket); - //window['onloadFuncts'].push(function () - fireWhenAllScriptsAreLoaded.push(function() - { - // set up the currentDivs and DOM - padContents.currentDivs = []; - $("#padcontent").html(""); - for (var i = 0; i < padContents.currentLines.length; i++) - { - var div = padContents.lineToElement(padContents.currentLines[i], padContents.alines[i]); - padContents.currentDivs.push(div); - $("#padcontent").append(div); - } - debugLog(padContents.currentDivs); - }); + BroadcastSlider.onSlider(goToRevisionIfEnabled); - // this is necessary to keep infinite loops of events firing, - // since goToRevision changes the slider position - var goToRevisionIfEnabledCount = 0; - var goToRevisionIfEnabled = function() { - if (goToRevisionIfEnabledCount > 0) - { - goToRevisionIfEnabledCount--; - } - else - { - goToRevision.apply(goToRevision, arguments); - } - } - - BroadcastSlider.onSlider(goToRevisionIfEnabled); + var dynamicCSS = makeCSSManager('dynamicsyntax'); + var authorData = {}; - var dynamicCSS = makeCSSManager('dynamicsyntax'); - var authorData = {}; - - function receiveAuthorData(newAuthorData) - { - for (var author in newAuthorData) + function receiveAuthorData(newAuthorData) { - var data = newAuthorData[author]; - var bgcolor = typeof data.colorId == "number" ? clientVars.colorPalette[data.colorId] : data.colorId; - if (bgcolor && dynamicCSS) + for (var author in newAuthorData) { - var selector = dynamicCSS.selectorStyle('.' + linestylefilter.getAuthorClassName(author)); - selector.backgroundColor = bgcolor - selector.color = (colorutils.luminosity(colorutils.css2triple(bgcolor)) < 0.5) ? '#ffffff' : '#000000'; //see ace2_inner.js for the other part + var data = newAuthorData[author]; + var bgcolor = typeof data.colorId == "number" ? clientVars.colorPalette[data.colorId] : data.colorId; + if (bgcolor && dynamicCSS) + { + var selector = dynamicCSS.selectorStyle('.' + linestylefilter.getAuthorClassName(author)); + selector.backgroundColor = bgcolor + selector.color = (colorutils.luminosity(colorutils.css2triple(bgcolor)) < 0.5) ? '#ffffff' : '#000000'; //see ace2_inner.js for the other part + } + authorData[author] = data; } - authorData[author] = data; } + + receiveAuthorData(clientVars.collab_client_vars.historicalAuthorData); + + return changesetLoader; } - receiveAuthorData(clientVars.collab_client_vars.historicalAuthorData); + exports.loadBroadcastJS = loadBroadcastJS; - return changesetLoader; -} - -exports.loadBroadcastJS = loadBroadcastJS; + return exports; +}); diff --git a/src/static/js/domline.js b/src/static/js/domline.js index c40c6e204..f97a5ca80 100644 --- a/src/static/js/domline.js +++ b/src/static/js/domline.js @@ -26,296 +26,300 @@ // requires: plugins // requires: undefined -var Security = require('./security'); -var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks'); -var _ = require('./underscore'); -var lineAttributeMarker = require('./linestylefilter').lineAttributeMarker; -var noop = function(){}; +define(['ep_etherpad-lite/static/js/pluginfw/hooks', 'ep_etherpad-lite/static/js/linestylefilter', 'underscore'], function(hooks, linestylefilterMod, _) { + var exports = {}; + + var Security = require('./security'); + var lineAttributeMarker = linestylefilterMod.lineAttributeMarker; + var noop = function(){}; -var domline = {}; + var domline = {}; -domline.addToLineClass = function(lineClass, cls) -{ - // an "empty span" at any point can be used to add classes to - // the line, using line:className. otherwise, we ignore - // the span. - cls.replace(/\S+/g, function(c) + domline.addToLineClass = function(lineClass, cls) { - if (c.indexOf("line:") == 0) + // an "empty span" at any point can be used to add classes to + // the line, using line:className. otherwise, we ignore + // the span. + cls.replace(/\S+/g, function(c) { - // add class to line - lineClass = (lineClass ? lineClass + ' ' : '') + c.substring(5); - } - }); - return lineClass; -} - -// if "document" is falsy we don't create a DOM node, just -// an object with innerHTML and className -domline.createDomLine = function(nonEmpty, doesWrap, optBrowser, optDocument) -{ - var result = { - node: null, - appendSpan: noop, - prepareForAdd: noop, - notifyAdded: noop, - clearSpans: noop, - finishUpdate: noop, - lineMarker: 0 - }; - - var document = optDocument; - - if (document) - { - result.node = document.createElement("div"); + if (c.indexOf("line:") == 0) + { + // add class to line + lineClass = (lineClass ? lineClass + ' ' : '') + c.substring(5); + } + }); + return lineClass; } - else + + // if "document" is falsy we don't create a DOM node, just + // an object with innerHTML and className + domline.createDomLine = function(nonEmpty, doesWrap, optBrowser, optDocument) { - result.node = { - innerHTML: '', - className: '' + var result = { + node: null, + appendSpan: noop, + prepareForAdd: noop, + notifyAdded: noop, + clearSpans: noop, + finishUpdate: noop, + lineMarker: 0 }; - } - var html = []; - var preHtml = '', - postHtml = ''; - var curHTML = null; + var document = optDocument; - function processSpaces(s) - { - return domline.processSpaces(s, doesWrap); - } - - var perTextNodeProcess = (doesWrap ? _.identity : processSpaces); - var perHtmlLineProcess = (doesWrap ? processSpaces : _.identity); - var lineClass = 'ace-line'; - - result.appendSpan = function(txt, cls) - { - - var processedMarker = false; - // Handle lineAttributeMarker, if present - if (cls.indexOf(lineAttributeMarker) >= 0) + if (document) { - var listType = /(?:^| )list:(\S+)/.exec(cls); - var start = /(?:^| )start:(\S+)/.exec(cls); + result.node = document.createElement("div"); + } + else + { + result.node = { + innerHTML: '', + className: '' + }; + } - _.map(hooks.callAll("aceDomLinePreProcessLineAttributes", { - domline: domline, - cls: cls - }), function(modifier) - { - preHtml += modifier.preHtml; - postHtml += modifier.postHtml; - processedMarker |= modifier.processedMarker; - }); + var html = []; + var preHtml = '', + postHtml = ''; + var curHTML = null; - if (listType) + function processSpaces(s) + { + return domline.processSpaces(s, doesWrap); + } + + var perTextNodeProcess = (doesWrap ? _.identity : processSpaces); + var perHtmlLineProcess = (doesWrap ? processSpaces : _.identity); + var lineClass = 'ace-line'; + + result.appendSpan = function(txt, cls) + { + + var processedMarker = false; + // Handle lineAttributeMarker, if present + if (cls.indexOf(lineAttributeMarker) >= 0) { - listType = listType[1]; + var listType = /(?:^| )list:(\S+)/.exec(cls); + var start = /(?:^| )start:(\S+)/.exec(cls); + + _.map(hooks.callAll("aceDomLinePreProcessLineAttributes", { + domline: domline, + cls: cls + }), function(modifier) + { + preHtml += modifier.preHtml; + postHtml += modifier.postHtml; + processedMarker |= modifier.processedMarker; + }); + if (listType) { - if(listType.indexOf("number") < 0) + listType = listType[1]; + if (listType) { - preHtml += '' + postHtml; - } - else - { - if(start){ // is it a start of a list with more than one item in? - if(start[1] == 1){ // if its the first one at this level? - lineClass = lineClass + " " + "list-start-" + listType; // Add start class to DIV node - } - preHtml += '
  1. '; - }else{ - preHtml += '
    1. '; // Handles pasted contents into existing lists + if(listType.indexOf("number") < 0) + { + preHtml += '
      • '; + postHtml = '
      ' + postHtml; } - postHtml += '
    '; - } + else + { + if(start){ // is it a start of a list with more than one item in? + if(start[1] == 1){ // if its the first one at this level? + lineClass = lineClass + " " + "list-start-" + listType; // Add start class to DIV node + } + preHtml += '
    1. '; + }else{ + preHtml += '
      1. '; // Handles pasted contents into existing lists + } + postHtml += '
      '; + } + } + processedMarker = true; + } + _.map(hooks.callAll("aceDomLineProcessLineAttributes", { + domline: domline, + cls: cls + }), function(modifier) + { + preHtml += modifier.preHtml; + postHtml += modifier.postHtml; + processedMarker |= modifier.processedMarker; + }); + if( processedMarker ){ + result.lineMarker += txt.length; + return; // don't append any text } - processedMarker = true; } - _.map(hooks.callAll("aceDomLineProcessLineAttributes", { + var href = null; + var simpleTags = null; + if (cls.indexOf('url') >= 0) + { + cls = cls.replace(/(^| )url:(\S+)/g, function(x0, space, url) + { + href = url; + return space + "url"; + }); + } + if (cls.indexOf('tag') >= 0) + { + cls = cls.replace(/(^| )tag:(\S+)/g, function(x0, space, tag) + { + if (!simpleTags) simpleTags = []; + simpleTags.push(tag.toLowerCase()); + return space + tag; + }); + } + + var extraOpenTags = ""; + var extraCloseTags = ""; + + _.map(hooks.callAll("aceCreateDomLine", { domline: domline, cls: cls }), function(modifier) { - preHtml += modifier.preHtml; - postHtml += modifier.postHtml; - processedMarker |= modifier.processedMarker; + cls = modifier.cls; + extraOpenTags = extraOpenTags + modifier.extraOpenTags; + extraCloseTags = modifier.extraCloseTags + extraCloseTags; }); - if( processedMarker ){ - result.lineMarker += txt.length; - return; // don't append any text - } - } - var href = null; - var simpleTags = null; - if (cls.indexOf('url') >= 0) - { - cls = cls.replace(/(^| )url:(\S+)/g, function(x0, space, url) - { - href = url; - return space + "url"; - }); - } - if (cls.indexOf('tag') >= 0) - { - cls = cls.replace(/(^| )tag:(\S+)/g, function(x0, space, tag) - { - if (!simpleTags) simpleTags = []; - simpleTags.push(tag.toLowerCase()); - return space + tag; - }); - } - var extraOpenTags = ""; - var extraCloseTags = ""; - - _.map(hooks.callAll("aceCreateDomLine", { - domline: domline, - cls: cls - }), function(modifier) - { - cls = modifier.cls; - extraOpenTags = extraOpenTags + modifier.extraOpenTags; - extraCloseTags = modifier.extraCloseTags + extraCloseTags; - }); - - if ((!txt) && cls) - { - lineClass = domline.addToLineClass(lineClass, cls); - } - else if (txt) - { - if (href) + if ((!txt) && cls) { - if(!~href.indexOf("://") && !~href.indexOf("mailto:")) // if the url doesn't include a protocol prefix, assume http + lineClass = domline.addToLineClass(lineClass, cls); + } + else if (txt) + { + if (href) { - href = "http://"+href; + if(!~href.indexOf("://") && !~href.indexOf("mailto:")) // if the url doesn't include a protocol prefix, assume http + { + href = "http://"+href; + } + extraOpenTags = extraOpenTags + ''; + extraCloseTags = '' + extraCloseTags; } - extraOpenTags = extraOpenTags + ''; - extraCloseTags = '' + extraCloseTags; + if (simpleTags) + { + simpleTags.sort(); + extraOpenTags = extraOpenTags + '<' + simpleTags.join('><') + '>'; + simpleTags.reverse(); + extraCloseTags = '' + extraCloseTags; + } + html.push('', extraOpenTags, perTextNodeProcess(Security.escapeHTML(txt)), extraCloseTags, ''); } - if (simpleTags) + }; + result.clearSpans = function() + { + html = []; + lineClass = ''; // non-null to cause update + result.lineMarker = 0; + }; + + function writeHTML() + { + var newHTML = perHtmlLineProcess(html.join('')); + if (!newHTML) { - simpleTags.sort(); - extraOpenTags = extraOpenTags + '<' + simpleTags.join('><') + '>'; - simpleTags.reverse(); - extraCloseTags = '' + extraCloseTags; + if ((!document) || (!optBrowser)) + { + newHTML += ' '; + } + else if (!optBrowser.msie) + { + newHTML += '
      '; + } } - html.push('', extraOpenTags, perTextNodeProcess(Security.escapeHTML(txt)), extraCloseTags, ''); + if (nonEmpty) + { + newHTML = (preHtml || '') + newHTML + (postHtml || ''); + } + html = preHtml = postHtml = ''; // free memory + if (newHTML !== curHTML) + { + curHTML = newHTML; + result.node.innerHTML = curHTML; + } + if (lineClass !== null) result.node.className = lineClass; + + hooks.callAll("acePostWriteDomLineHTML", { + node: result.node + }); } - }; - result.clearSpans = function() - { - html = []; - lineClass = ''; // non-null to cause update - result.lineMarker = 0; + result.prepareForAdd = writeHTML; + result.finishUpdate = writeHTML; + result.getInnerHTML = function() + { + return curHTML || ''; + }; + return result; }; - function writeHTML() + domline.processSpaces = function(s, doesWrap) { - var newHTML = perHtmlLineProcess(html.join('')); - if (!newHTML) + if (s.indexOf("<") < 0 && !doesWrap) { - if ((!document) || (!optBrowser)) - { - newHTML += ' '; - } - else if (!optBrowser.msie) - { - newHTML += '
      '; - } + // short-cut + return s.replace(/ /g, ' '); } - if (nonEmpty) + var parts = []; + s.replace(/<[^>]*>?| |[^ <]+/g, function(m) { - newHTML = (preHtml || '') + newHTML + (postHtml || ''); - } - html = preHtml = postHtml = ''; // free memory - if (newHTML !== curHTML) - { - curHTML = newHTML; - result.node.innerHTML = curHTML; - } - if (lineClass !== null) result.node.className = lineClass; - - hooks.callAll("acePostWriteDomLineHTML", { - node: result.node + parts.push(m); }); - } - result.prepareForAdd = writeHTML; - result.finishUpdate = writeHTML; - result.getInnerHTML = function() - { - return curHTML || ''; + if (doesWrap) + { + var endOfLine = true; + var beforeSpace = false; + // last space in a run is normal, others are nbsp, + // end of line is nbsp + for (var i = parts.length - 1; i >= 0; i--) + { + var p = parts[i]; + if (p == " ") + { + if (endOfLine || beforeSpace) parts[i] = ' '; + endOfLine = false; + beforeSpace = true; + } + else if (p.charAt(0) != "<") + { + endOfLine = false; + beforeSpace = false; + } + } + // beginning of line is nbsp + for (var i = 0; i < parts.length; i++) + { + var p = parts[i]; + if (p == " ") + { + parts[i] = ' '; + break; + } + else if (p.charAt(0) != "<") + { + break; + } + } + } + else + { + for (var i = 0; i < parts.length; i++) + { + var p = parts[i]; + if (p == " ") + { + parts[i] = ' '; + } + } + } + return parts.join(''); }; - return result; -}; -domline.processSpaces = function(s, doesWrap) -{ - if (s.indexOf("<") < 0 && !doesWrap) - { - // short-cut - return s.replace(/ /g, ' '); - } - var parts = []; - s.replace(/<[^>]*>?| |[^ <]+/g, function(m) - { - parts.push(m); - }); - if (doesWrap) - { - var endOfLine = true; - var beforeSpace = false; - // last space in a run is normal, others are nbsp, - // end of line is nbsp - for (var i = parts.length - 1; i >= 0; i--) - { - var p = parts[i]; - if (p == " ") - { - if (endOfLine || beforeSpace) parts[i] = ' '; - endOfLine = false; - beforeSpace = true; - } - else if (p.charAt(0) != "<") - { - endOfLine = false; - beforeSpace = false; - } - } - // beginning of line is nbsp - for (var i = 0; i < parts.length; i++) - { - var p = parts[i]; - if (p == " ") - { - parts[i] = ' '; - break; - } - else if (p.charAt(0) != "<") - { - break; - } - } - } - else - { - for (var i = 0; i < parts.length; i++) - { - var p = parts[i]; - if (p == " ") - { - parts[i] = ' '; - } - } - } - return parts.join(''); -}; + exports.domline = domline; -exports.domline = domline; + return exports; +}); diff --git a/src/static/js/linestylefilter.js b/src/static/js/linestylefilter.js index 82efe2d98..ff45fffd3 100644 --- a/src/static/js/linestylefilter.js +++ b/src/static/js/linestylefilter.js @@ -28,338 +28,342 @@ // requires: plugins // requires: undefined -var Changeset = require('./Changeset'); -var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks'); -var linestylefilter = {}; -var _ = require('./underscore'); -var AttributeManager = require('./AttributeManager'); +define(['ep_etherpad-lite/static/js/pluginfw/hooks', 'underscore'], function (hooks, _) { + var exports = {}; -linestylefilter.ATTRIB_CLASSES = { - 'bold': 'tag:b', - 'italic': 'tag:i', - 'underline': 'tag:u', - 'strikethrough': 'tag:s' -}; + var Changeset = require('./Changeset'); + var linestylefilter = {}; + var AttributeManager = require('./AttributeManager'); -var lineAttributeMarker = 'lineAttribMarker'; -exports.lineAttributeMarker = lineAttributeMarker; + linestylefilter.ATTRIB_CLASSES = { + 'bold': 'tag:b', + 'italic': 'tag:i', + 'underline': 'tag:u', + 'strikethrough': 'tag:s' + }; -linestylefilter.getAuthorClassName = function(author) -{ - return "author-" + author.replace(/[^a-y0-9]/g, function(c) + var lineAttributeMarker = 'lineAttribMarker'; + exports.lineAttributeMarker = lineAttributeMarker; + + linestylefilter.getAuthorClassName = function(author) { - if (c == ".") return "-"; - return 'z' + c.charCodeAt(0) + 'z'; - }); -}; - -// lineLength is without newline; aline includes newline, -// but may be falsy if lineLength == 0 -linestylefilter.getLineStyleFilter = function(lineLength, aline, textAndClassFunc, apool) -{ - - // Plugin Hook to add more Attrib Classes - hooks.aCallAll('aceAttribClasses', linestylefilter.ATTRIB_CLASSES, function(err, ATTRIB_CLASSES){ - if(ATTRIB_CLASSES.length >= 1){ - linestylefilter.ATTRIB_CLASSES = ATTRIB_CLASSES[0]; - } - }); - - if (lineLength == 0) return textAndClassFunc; - - var nextAfterAuthorColors = textAndClassFunc; - - var authorColorFunc = (function() - { - var lineEnd = lineLength; - var curIndex = 0; - var extraClasses; - var leftInAuthor; - - function attribsToClasses(attribs) + return "author-" + author.replace(/[^a-y0-9]/g, function(c) { - var classes = ''; - var isLineAttribMarker = false; - - Changeset.eachAttribNumber(attribs, function(n) + if (c == ".") return "-"; + return 'z' + c.charCodeAt(0) + 'z'; + }); + }; + + // lineLength is without newline; aline includes newline, + // but may be falsy if lineLength == 0 + linestylefilter.getLineStyleFilter = function(lineLength, aline, textAndClassFunc, apool) + { + + // Plugin Hook to add more Attrib Classes + hooks.aCallAll('aceAttribClasses', linestylefilter.ATTRIB_CLASSES, function(err, ATTRIB_CLASSES){ + if(ATTRIB_CLASSES.length >= 1){ + linestylefilter.ATTRIB_CLASSES = ATTRIB_CLASSES[0]; + } + }); + + if (lineLength == 0) return textAndClassFunc; + + var nextAfterAuthorColors = textAndClassFunc; + + var authorColorFunc = (function() + { + var lineEnd = lineLength; + var curIndex = 0; + var extraClasses; + var leftInAuthor; + + function attribsToClasses(attribs) { - var key = apool.getAttribKey(n); - if (key) + var classes = ''; + var isLineAttribMarker = false; + + Changeset.eachAttribNumber(attribs, function(n) { - var value = apool.getAttribValue(n); - if (value) + var key = apool.getAttribKey(n); + if (key) { - if (!isLineAttribMarker && _.indexOf(AttributeManager.lineAttributes, key) >= 0){ - isLineAttribMarker = true; - } - if (key == 'author') + var value = apool.getAttribValue(n); + if (value) { - classes += ' ' + linestylefilter.getAuthorClassName(value); + if (!isLineAttribMarker && _.indexOf(AttributeManager.lineAttributes, key) >= 0){ + isLineAttribMarker = true; + } + if (key == 'author') + { + classes += ' ' + linestylefilter.getAuthorClassName(value); + } + else if (key == 'list') + { + classes += ' list:' + value; + } + else if (key == 'start') + { + classes += ' start:' + value; + } + else if (linestylefilter.ATTRIB_CLASSES[key]) + { + classes += ' ' + linestylefilter.ATTRIB_CLASSES[key]; + } + else + { + classes += hooks.callAllStr("aceAttribsToClasses", { + linestylefilter: linestylefilter, + key: key, + value: value + }, " ", " ", ""); + } } - else if (key == 'list') - { - classes += ' list:' + value; - } - else if (key == 'start') - { - classes += ' start:' + value; - } - else if (linestylefilter.ATTRIB_CLASSES[key]) - { - classes += ' ' + linestylefilter.ATTRIB_CLASSES[key]; - } - else - { - classes += hooks.callAllStr("aceAttribsToClasses", { - linestylefilter: linestylefilter, - key: key, - value: value - }, " ", " ", ""); - } + } + }); + + if(isLineAttribMarker) classes += ' ' + lineAttributeMarker; + return classes.substring(1); + } + + var attributionIter = Changeset.opIterator(aline); + var nextOp, nextOpClasses; + + function goNextOp() + { + nextOp = attributionIter.next(); + nextOpClasses = (nextOp.opcode && attribsToClasses(nextOp.attribs)); + } + goNextOp(); + + function nextClasses() + { + if (curIndex < lineEnd) + { + extraClasses = nextOpClasses; + leftInAuthor = nextOp.chars; + goNextOp(); + while (nextOp.opcode && nextOpClasses == extraClasses) + { + leftInAuthor += nextOp.chars; + goNextOp(); } } - }); - - if(isLineAttribMarker) classes += ' ' + lineAttributeMarker; - return classes.substring(1); - } - - var attributionIter = Changeset.opIterator(aline); - var nextOp, nextOpClasses; - - function goNextOp() - { - nextOp = attributionIter.next(); - nextOpClasses = (nextOp.opcode && attribsToClasses(nextOp.attribs)); - } - goNextOp(); - - function nextClasses() - { - if (curIndex < lineEnd) - { - extraClasses = nextOpClasses; - leftInAuthor = nextOp.chars; - goNextOp(); - while (nextOp.opcode && nextOpClasses == extraClasses) - { - leftInAuthor += nextOp.chars; - goNextOp(); - } } - } - nextClasses(); + nextClasses(); - return function(txt, cls) - { - - var disableAuthColorForThisLine = hooks.callAll("disableAuthorColorsForThisLine", { - linestylefilter: linestylefilter, - text: txt, - "class": cls - }, " ", " ", ""); - var disableAuthors = (disableAuthColorForThisLine==null||disableAuthColorForThisLine.length==0)?false:disableAuthColorForThisLine[0]; - while (txt.length > 0) - { - if (leftInAuthor <= 0 || disableAuthors) - { - // prevent infinite loop if something funny's going on - return nextAfterAuthorColors(txt, cls); - } - var spanSize = txt.length; - if (spanSize > leftInAuthor) - { - spanSize = leftInAuthor; - } - var curTxt = txt.substring(0, spanSize); - txt = txt.substring(spanSize); - nextAfterAuthorColors(curTxt, (cls && cls + " ") + extraClasses); - curIndex += spanSize; - leftInAuthor -= spanSize; - if (leftInAuthor == 0) - { - nextClasses(); - } - } - }; - })(); - return authorColorFunc; -}; - -linestylefilter.getAtSignSplitterFilter = function(lineText, textAndClassFunc) -{ - var at = /@/g; - at.lastIndex = 0; - var splitPoints = null; - var execResult; - while ((execResult = at.exec(lineText))) - { - if (!splitPoints) - { - splitPoints = []; - } - splitPoints.push(execResult.index); - } - - if (!splitPoints) return textAndClassFunc; - - return linestylefilter.textAndClassFuncSplitter(textAndClassFunc, splitPoints); -}; - -linestylefilter.getRegexpFilter = function(regExp, tag) -{ - return function(lineText, textAndClassFunc) - { - regExp.lastIndex = 0; - var regExpMatchs = null; - var splitPoints = null; - var execResult; - while ((execResult = regExp.exec(lineText))) - { - if (!regExpMatchs) - { - regExpMatchs = []; - splitPoints = []; - } - var startIndex = execResult.index; - var regExpMatch = execResult[0]; - regExpMatchs.push([startIndex, regExpMatch]); - splitPoints.push(startIndex, startIndex + regExpMatch.length); - } - - if (!regExpMatchs) return textAndClassFunc; - - function regExpMatchForIndex(idx) - { - for (var k = 0; k < regExpMatchs.length; k++) - { - var u = regExpMatchs[k]; - if (idx >= u[0] && idx < u[0] + u[1].length) - { - return u[1]; - } - } - return false; - } - - var handleRegExpMatchsAfterSplit = (function() - { - var curIndex = 0; return function(txt, cls) { - var txtlen = txt.length; - var newCls = cls; - var regExpMatch = regExpMatchForIndex(curIndex); - if (regExpMatch) + + var disableAuthColorForThisLine = hooks.callAll("disableAuthorColorsForThisLine", { + linestylefilter: linestylefilter, + text: txt, + "class": cls + }, " ", " ", ""); + var disableAuthors = (disableAuthColorForThisLine==null||disableAuthColorForThisLine.length==0)?false:disableAuthColorForThisLine[0]; + while (txt.length > 0) { - newCls += " " + tag + ":" + regExpMatch; + if (leftInAuthor <= 0 || disableAuthors) + { + // prevent infinite loop if something funny's going on + return nextAfterAuthorColors(txt, cls); + } + var spanSize = txt.length; + if (spanSize > leftInAuthor) + { + spanSize = leftInAuthor; + } + var curTxt = txt.substring(0, spanSize); + txt = txt.substring(spanSize); + nextAfterAuthorColors(curTxt, (cls && cls + " ") + extraClasses); + curIndex += spanSize; + leftInAuthor -= spanSize; + if (leftInAuthor == 0) + { + nextClasses(); + } } - textAndClassFunc(txt, newCls); - curIndex += txtlen; }; })(); - - return linestylefilter.textAndClassFuncSplitter(handleRegExpMatchsAfterSplit, splitPoints); + return authorColorFunc; }; -}; - -linestylefilter.REGEX_WORDCHAR = /[\u0030-\u0039\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u1FFF\u3040-\u9FFF\uF900-\uFDFF\uFE70-\uFEFE\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFDC]/; -linestylefilter.REGEX_URLCHAR = new RegExp('(' + /[-:@a-zA-Z0-9_.,~%+\/\\?=&#!;()\[\]$]/.source + '|' + linestylefilter.REGEX_WORDCHAR.source + ')'); -linestylefilter.REGEX_URL = new RegExp(/(?:(?:https?|s?ftp|ftps|file|nfs):\/\/|mailto:|www\.)/.source + linestylefilter.REGEX_URLCHAR.source + '*(?![:.,;])' + linestylefilter.REGEX_URLCHAR.source, 'g'); -linestylefilter.getURLFilter = linestylefilter.getRegexpFilter( -linestylefilter.REGEX_URL, 'url'); - -linestylefilter.textAndClassFuncSplitter = function(func, splitPointsOpt) -{ - var nextPointIndex = 0; - var idx = 0; - - // don't split at 0 - while (splitPointsOpt && nextPointIndex < splitPointsOpt.length && splitPointsOpt[nextPointIndex] == 0) + linestylefilter.getAtSignSplitterFilter = function(lineText, textAndClassFunc) { - nextPointIndex++; - } - - function spanHandler(txt, cls) - { - if ((!splitPointsOpt) || nextPointIndex >= splitPointsOpt.length) + var at = /@/g; + at.lastIndex = 0; + var splitPoints = null; + var execResult; + while ((execResult = at.exec(lineText))) { - func(txt, cls); - idx += txt.length; + if (!splitPoints) + { + splitPoints = []; + } + splitPoints.push(execResult.index); } - else + + if (!splitPoints) return textAndClassFunc; + + return linestylefilter.textAndClassFuncSplitter(textAndClassFunc, splitPoints); + }; + + linestylefilter.getRegexpFilter = function(regExp, tag) + { + return function(lineText, textAndClassFunc) { - var splitPoints = splitPointsOpt; - var pointLocInSpan = splitPoints[nextPointIndex] - idx; - var txtlen = txt.length; - if (pointLocInSpan >= txtlen) + regExp.lastIndex = 0; + var regExpMatchs = null; + var splitPoints = null; + var execResult; + while ((execResult = regExp.exec(lineText))) + { + if (!regExpMatchs) + { + regExpMatchs = []; + splitPoints = []; + } + var startIndex = execResult.index; + var regExpMatch = execResult[0]; + regExpMatchs.push([startIndex, regExpMatch]); + splitPoints.push(startIndex, startIndex + regExpMatch.length); + } + + if (!regExpMatchs) return textAndClassFunc; + + function regExpMatchForIndex(idx) + { + for (var k = 0; k < regExpMatchs.length; k++) + { + var u = regExpMatchs[k]; + if (idx >= u[0] && idx < u[0] + u[1].length) + { + return u[1]; + } + } + return false; + } + + var handleRegExpMatchsAfterSplit = (function() + { + var curIndex = 0; + return function(txt, cls) + { + var txtlen = txt.length; + var newCls = cls; + var regExpMatch = regExpMatchForIndex(curIndex); + if (regExpMatch) + { + newCls += " " + tag + ":" + regExpMatch; + } + textAndClassFunc(txt, newCls); + curIndex += txtlen; + }; + })(); + + return linestylefilter.textAndClassFuncSplitter(handleRegExpMatchsAfterSplit, splitPoints); + }; + }; + + + linestylefilter.REGEX_WORDCHAR = /[\u0030-\u0039\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u1FFF\u3040-\u9FFF\uF900-\uFDFF\uFE70-\uFEFE\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFDC]/; + linestylefilter.REGEX_URLCHAR = new RegExp('(' + /[-:@a-zA-Z0-9_.,~%+\/\\?=&#!;()\[\]$]/.source + '|' + linestylefilter.REGEX_WORDCHAR.source + ')'); + linestylefilter.REGEX_URL = new RegExp(/(?:(?:https?|s?ftp|ftps|file|nfs):\/\/|mailto:|www\.)/.source + linestylefilter.REGEX_URLCHAR.source + '*(?![:.,;])' + linestylefilter.REGEX_URLCHAR.source, 'g'); + linestylefilter.getURLFilter = linestylefilter.getRegexpFilter( + linestylefilter.REGEX_URL, 'url'); + + linestylefilter.textAndClassFuncSplitter = function(func, splitPointsOpt) + { + var nextPointIndex = 0; + var idx = 0; + + // don't split at 0 + while (splitPointsOpt && nextPointIndex < splitPointsOpt.length && splitPointsOpt[nextPointIndex] == 0) + { + nextPointIndex++; + } + + function spanHandler(txt, cls) + { + if ((!splitPointsOpt) || nextPointIndex >= splitPointsOpt.length) { func(txt, cls); idx += txt.length; - if (pointLocInSpan == txtlen) - { - nextPointIndex++; - } } else { - if (pointLocInSpan > 0) + var splitPoints = splitPointsOpt; + var pointLocInSpan = splitPoints[nextPointIndex] - idx; + var txtlen = txt.length; + if (pointLocInSpan >= txtlen) { - func(txt.substring(0, pointLocInSpan), cls); - idx += pointLocInSpan; + func(txt, cls); + idx += txt.length; + if (pointLocInSpan == txtlen) + { + nextPointIndex++; + } + } + else + { + if (pointLocInSpan > 0) + { + func(txt.substring(0, pointLocInSpan), cls); + idx += pointLocInSpan; + } + nextPointIndex++; + // recurse + spanHandler(txt.substring(pointLocInSpan), cls); } - nextPointIndex++; - // recurse - spanHandler(txt.substring(pointLocInSpan), cls); } } - } - return spanHandler; -}; + return spanHandler; + }; -linestylefilter.getFilterStack = function(lineText, textAndClassFunc, abrowser) -{ - var func = linestylefilter.getURLFilter(lineText, textAndClassFunc); - - var hookFilters = hooks.callAll("aceGetFilterStack", { - linestylefilter: linestylefilter, - browser: abrowser - }); - _.map(hookFilters ,function(hookFilter) + linestylefilter.getFilterStack = function(lineText, textAndClassFunc, abrowser) { - func = hookFilter(lineText, func); - }); + var func = linestylefilter.getURLFilter(lineText, textAndClassFunc); - if (abrowser !== undefined && abrowser.msie) + var hookFilters = hooks.callAll("aceGetFilterStack", { + linestylefilter: linestylefilter, + browser: abrowser + }); + _.map(hookFilters ,function(hookFilter) + { + func = hookFilter(lineText, func); + }); + + if (abrowser !== undefined && abrowser.msie) + { + // IE7+ will take an e-mail address like and linkify it to foo@bar.com. + // We then normalize it back to text with no angle brackets. It's weird. So always + // break spans at an "at" sign. + func = linestylefilter.getAtSignSplitterFilter( + lineText, func); + } + return func; + }; + + // domLineObj is like that returned by domline.createDomLine + linestylefilter.populateDomLine = function(textLine, aline, apool, domLineObj) { - // IE7+ will take an e-mail address like and linkify it to foo@bar.com. - // We then normalize it back to text with no angle brackets. It's weird. So always - // break spans at an "at" sign. - func = linestylefilter.getAtSignSplitterFilter( - lineText, func); - } - return func; -}; + // remove final newline from text if any + var text = textLine; + if (text.slice(-1) == '\n') + { + text = text.substring(0, text.length - 1); + } -// domLineObj is like that returned by domline.createDomLine -linestylefilter.populateDomLine = function(textLine, aline, apool, domLineObj) -{ - // remove final newline from text if any - var text = textLine; - if (text.slice(-1) == '\n') - { - text = text.substring(0, text.length - 1); - } + function textAndClassFunc(tokenText, tokenClass) + { + domLineObj.appendSpan(tokenText, tokenClass); + } - function textAndClassFunc(tokenText, tokenClass) - { - domLineObj.appendSpan(tokenText, tokenClass); - } + var func = linestylefilter.getFilterStack(text, textAndClassFunc); + func = linestylefilter.getLineStyleFilter(text.length, aline, func, apool); + func(text, ''); + }; - var func = linestylefilter.getFilterStack(text, textAndClassFunc); - func = linestylefilter.getLineStyleFilter(text.length, aline, func, apool); - func(text, ''); -}; + exports.linestylefilter = linestylefilter; -exports.linestylefilter = linestylefilter; + return exports; +}); diff --git a/src/static/js/pluginfw/client_plugins.js b/src/static/js/pluginfw/client_plugins.js index 702f4f104..2934d8fa0 100644 --- a/src/static/js/pluginfw/client_plugins.js +++ b/src/static/js/pluginfw/client_plugins.js @@ -48,12 +48,12 @@ define(["ep_etherpad-lite/static/js/rjquery", "underscore", './shared'], functio } } - function adoptPluginsFromAncestorsOf(frame, cb) { + function adoptPluginsFromAncestorsOf(frame, cb) { // Bind plugins with parent; var parentRequire = null; try { while (frame = frame.parent) { - if (typeof (frame.require) !== "undefined") { + if (typeof (frame.requirejs) !== "undefined") { parentRequire = frame.requirejs; break; } diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index 0a524eabf..39b195c93 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -70,32 +70,30 @@ exports.flatten = function (lst) { exports.callAll = function (hook_name, args) { if (!args) args = {}; - if (exports.plugins){ - if (exports.plugins.hooks[hook_name] === undefined) return []; - return _.flatten(_.map(exports.plugins.hooks[hook_name], function (hook) { - return hookCallWrapper(hook, hook_name, args); - }), true); - } + if (exports.plugins === undefined || exports.plugins.hooks[hook_name] === undefined) return []; + return _.flatten(_.map(exports.plugins.hooks[hook_name], function (hook) { + return hookCallWrapper(hook, hook_name, args); + }), true); } exports.aCallAll = function (hook_name, args, cb) { if (!args) args = {}; if (!cb) cb = function () {}; - if (exports.plugins.hooks[hook_name] === undefined) return cb(null, []); + if (exports.plugins === undefined || exports.plugins.hooks[hook_name] === undefined) return cb(null, []); async.map( exports.plugins.hooks[hook_name], function (hook, cb) { hookCallWrapper(hook, hook_name, args, function (res) { cb(null, res); }); }, function (err, res) { - cb(null, _.flatten(res, true)); + cb(null, _.flatten(res, true)); } ); } exports.callFirst = function (hook_name, args) { if (!args) args = {}; - if (exports.plugins.hooks[hook_name] === undefined) return []; + if (exports.plugins === undefined || exports.plugins.hooks[hook_name] === undefined) return []; return exports.syncMapFirst(exports.plugins.hooks[hook_name], function (hook) { return hookCallWrapper(hook, hook_name, args); }); @@ -104,7 +102,7 @@ exports.callFirst = function (hook_name, args) { exports.aCallFirst = function (hook_name, args, cb) { if (!args) args = {}; if (!cb) cb = function () {}; - if (exports.plugins.hooks[hook_name] === undefined) return cb(null, []); + if (exports.plugins === undefined || exports.plugins.hooks[hook_name] === undefined) return cb(null, []); exports.mapFirst( exports.plugins.hooks[hook_name], function (hook, cb) { diff --git a/src/static/js/timeslider.js b/src/static/js/timeslider.js index d85b71e64..69eaa7c78 100644 --- a/src/static/js/timeslider.js +++ b/src/static/js/timeslider.js @@ -27,8 +27,9 @@ define([ 'ep_etherpad-lite/static/js/rjquery', 'ep_etherpad-lite/static/js/pluginfw/hooks', 'ep_etherpad-lite/static/js/pad_utils', - 'ep_etherpad-lite/static/js/broadcast_slider' -], function($, hooks, padUtilsMod, broadcastSliderMod) { + 'ep_etherpad-lite/static/js/broadcast_slider', + 'ep_etherpad-lite/static/js/broadcast', +], function($, hooks, padUtilsMod, broadcastSliderMod, broadcastMod) { var exports = {}; JSON = window.requireKernel('./json2'); @@ -36,6 +37,11 @@ define([ var createCookie = padUtilsMod.createCookie; var readCookie = padUtilsMod.readCookie; var randomString = padUtilsMod.randomString; + var broadcastRevisionsMod = require('./broadcast_revisions'); + var padimpexpMod = require('./pad_impexp'); + + //initialize export ui + require('./pad_impexp').padimpexp.init(); var token, padId, export_links; @@ -142,11 +148,11 @@ define([ //load all script that doesn't work without the clientVars BroadcastSlider = broadcastSliderMod.loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded); - require('./broadcast_revisions').loadBroadcastRevisionsJS(); - changesetLoader = require('./broadcast').loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, BroadcastSlider); + broadcastRevisionsMod.loadBroadcastRevisionsJS(); + changesetLoader = broadcastMod.loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, BroadcastSlider); //initialize export ui - require('./pad_impexp').padimpexp.init(); + padimpexpMod.padimpexp.init(); //change export urls when the slider moves BroadcastSlider.onSlider(function(revno) diff --git a/src/templates/pad.html b/src/templates/pad.html index 8766d774d..43a39a4d7 100644 --- a/src/templates/pad.html +++ b/src/templates/pad.html @@ -398,11 +398,9 @@ [ 'ep_etherpad-lite/static/js/rjquery', 'ep_etherpad-lite/static/js/pluginfw/client_plugins', - 'ep_etherpad-lite/static/js/pluginfw/hooks', - 'ep_etherpad-lite/static/js/pad', - 'ep_etherpad-lite/static/js/chat', - 'ep_etherpad-lite/static/js/pad_editbar', - ], function ($, plugins, hooks, padMod, chatMod, padEditbarMod) { + 'ep_etherpad-lite/static/js/pluginfw/hooks' + ], function ($, plugins, hooks) { + console.log("hooks & plugins modules loaded"); window.$ = $; // Expose jQuery #HACK window.jQuery = $; @@ -415,20 +413,32 @@ plugins.update(function () { hooks.plugins = plugins; + console.log("hooks.plugins initialized"); + // Call documentReady hook $(function() { hooks.aCallAll('documentReady'); }); - padMod.baseURL = baseURL; - padMod.init(); - }); + requirejs( + [ + 'ep_etherpad-lite/static/js/pad', + 'ep_etherpad-lite/static/js/chat', + 'ep_etherpad-lite/static/js/pad_editbar', + ], function (padMod, chatMod, padEditbarMod) { + console.log("pad loaded"); - /* TODO: These globals shouldn't exist. */ - pad = padMod.pad; - chat = chatMod.chat; - padeditbar = padEditbarMod.padeditbar; - padimpexp = window.requireKernel('ep_etherpad-lite/static/js/pad_impexp').padimpexp; + padMod.baseURL = baseURL; + padMod.init(); + + /* TODO: These globals shouldn't exist. */ + pad = padMod.pad; + chat = chatMod.chat; + padeditbar = padEditbarMod.padeditbar; + padimpexp = window.requireKernel('ep_etherpad-lite/static/js/pad_impexp').padimpexp; + } + ); + }); } ); }());