123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015 |
- /*
- SpacedeckSections
- This module contains functions dealing with Space Sections UI.
- */
- var SpacedeckSections = {
- data: {
- MAX_COLUMNS: 20,
- redo_stack: [],
- undo_stack: [],
- opened_dialog: "none", // which property panel to display
- color_options_picker: false,
- advanced_properties: false,
- embed_code_html: "",
- active_tool: "pointer",
- lightbox_artifact: {},
- snap_ruler_y: -1000,
- snap_ruler_x: -1000,
- minimap_width: 100,
- minimap_height: 200,
- minimap_scale: 10,
- scroll_left: 0,
- scroll_top: 0,
- window_width: 800,
- window_height: 600,
- bounds_margin_horiz: 0,
- bounds_margin_vert: 0,
- editing_artifact_id: null,
- selected_artifacts_dict: {},
- first_selected_artifact: null,
- selection_metrics: {
- contains_text: false,
- contains_images: false,
- contains_audio: false,
- contains_vectors: false,
- contains_shapes: false,
- borders_stylable: true,
- count: 0,
- x: 0,
- y: 0,
- w: 0,
- h: 0,
- x1: 0,
- y1: 0,
- x2: 0,
- y2: 0,
- style: "display:none",
- vector_points: [{},{}],
- vector_selection: false
- },
- selected_artifacts_json: "",
- zones: [],
- user_cursors: [],
- default_style: {}, // will be copied from active_style on startup
- active_style: {
- border_radius: 0,
- stroke: 0,
- font_family: "Avenir W01",
- font_size: 18,
- line_height: 1.5,
- letter_spacing: 0,
- stroke_color: "#000000",
- fill_color: "#00000000",
- text_color: "#000000",
- background_color: "#ffffff",
- padding: 0,
- padding_horz: 0,
- padding_vert: 0,
- padding_top: 0,
- padding_left: 0,
- padding_right: 0,
- padding_bottom: 0,
- margin: 0,
- margin_horz: 0,
- margin_vert: 0,
- margin_top: 0,
- margin_left: 0,
- margin_right: 0,
- margin_bottom: 0,
- brightness: 100,
- contrast: 100,
- opacity: 100,
- saturation: 100,
- blur: 0,
- hue: 0,
- columns: 1,
- column_width: 900,
- row_height: 0,
- gutter: 0,
- },
- color_picker_target: "fill_color",
- color_picker_saturation: 255,
- color_picker_value: 255,
- color_picker_hue: 127,
- color_picker_opacity: 255,
- swatches: [
- {id:0, hex:"#4a2f7e"},
- {id:1, hex:"#9b59b6"},
- {id:2, hex:"#3498db"},
- {id:3, hex:"#2ecc71"},
- {id:4, hex:"#f1c40f"},
- {id:5, hex:"#e67e22"},
- {id:6, hex:"#d55c4b"},
- {id:7, hex:"#6f4021"},
- {id:8, hex:"#ffffff"},
- {id:9, hex:"#95a5a6"},
- {id:10, hex:"#252525"},
- {id:11, hex:"rgba(0,0,0,0)"},
- ],
-
- swatches_text: [
- {id:1, hex:"#9b59b6"},
- {id:2, hex:"#3498db"},
- {id:3, hex:"#2ecc71"},
- {id:4, hex:"#f1c40f"},
- {id:5, hex:"#e67e22"},
- {id:6, hex:"#d55c4b"},
- {id:8, hex:"#ffffff"},
- {id:10, hex:"#252525"},
- ],
- fonts: [
- "Arial",
- "Courier",
- "Georgia",
- "Verdana",
- "Comic Sans MS",
- "Montserrat",
- "Lato",
- "Roboto",
- "Crimson Text",
- "EB Garamond",
- "Vollkorn",
- "Avenir W01"
- ],
- detected_text_formats: {},
- active_text_format_name: "Paragraph",
- image_search_results: [],
- video_search_results: [],
- audio_search_results: [],
- generic_search_query: "",
- media_search_target: "google",
- search_loading: false,
- viewport_zoom: 1,
- viewport_zoom_percent: 100,
- bounds_zoom: 1,
- current_zone_idx: -1,
- margin_mode: "global",
- padding_mode: "global",
- delete_artifact: "unconfirmed",
- color_mode: "palette",
- background_mode: "image",
- layout_mode: "layout",
- follow_mode: true,
- space_background_uploading: false,
- toolbar_props_x: 0,
- toolbar_props_y: 0,
- toolbar_props_in: false,
- toolbar_artifacts_x: "-1000px",
- toolbar_artifacts_y: "-1000px",
- toolbar_artifacts_in: false
- },
- methods: {
- setup_section_module: function() {
- // defaults -----------------------------------------------------------------------------
- this.default_style = _.clone(this.active_style);
- // keybindings --------------------------------------------------------------------------
- Mousetrap.bind('del', function(evt) { this.if_editable(function() {this.delete_selected_artifacts(evt);}) }.bind(this));
- Mousetrap.bind('backspace', function(evt) { this.if_editable(function() {this.delete_selected_artifacts(evt);}) }.bind(this));
- Mousetrap.bind(['command+d', 'ctrl+d' ], function(evt) { evt.preventDefault(); evt.stopPropagation(); this.if_editable(function() {this.duplicate_selected_artifacts();}) }.bind(this));
- Mousetrap.bind(['command+z', 'ctrl+z' ], function(evt) { this.if_editable(function() {this.undo();}) }.bind(this));
- Mousetrap.bind(['command+shift+z','ctrl+shift+z'], function(evt) { this.if_editable(function() {this.redo();}) }.bind(this));
- Mousetrap.bind(['command+a', 'ctrl+a' ], function(evt) { this.if_editable(function() {this.select_all_artifacts();}) }.bind(this));
- Mousetrap.bind(['command+e', 'ctrl+e' ], function(evt) { this.if_editable(function() {this.toggle_full_width();}) }.bind(this));
- Mousetrap.bind(['command+=', 'ctrl+=' ], function(evt) { evt.preventDefault(); evt.stopPropagation(); this.zoom_in(); }.bind(this));
- Mousetrap.bind(['command+-', 'ctrl+-' ], function(evt) { evt.preventDefault(); evt.stopPropagation(); this.zoom_out(); }.bind(this));
- Mousetrap.bind('+', function(evt) { evt.preventDefault(); evt.stopPropagation(); this.zoom_in(); }.bind(this));
- Mousetrap.bind('-', function(evt) { evt.preventDefault(); evt.stopPropagation(); this.zoom_out(); }.bind(this));
- Mousetrap.bind('up', function(evt) { this.nudge_selected_artifacts(0,-1,evt);}.bind(this));
- Mousetrap.bind('down', function(evt) { this.nudge_selected_artifacts(0,1,evt);}.bind(this));
- Mousetrap.bind('left', function(evt) { this.nudge_selected_artifacts(-1,0,evt);}.bind(this));
- Mousetrap.bind('right', function(evt) { this.nudge_selected_artifacts(1,0,evt);}.bind(this));
- Mousetrap.bind('shift+up', function(evt) { this.if_editable(function() {this.nudge_selected_artifacts(0,-10,evt);}) }.bind(this));
- Mousetrap.bind('shift+down', function(evt) { this.if_editable(function() {this.nudge_selected_artifacts(0,10,evt);}) }.bind(this));
- Mousetrap.bind('shift+left', function(evt) { this.if_editable(function() {this.nudge_selected_artifacts(-10,0,evt);}) }.bind(this));
- Mousetrap.bind('shift+right', function(evt) { this.if_editable(function() {this.nudge_selected_artifacts(10,0,evt);}) }.bind(this));
- Mousetrap.bind('space', function(evt) { this.activate_pan_tool(evt); }.bind(this));
-
- $(document).bind("beforecopy", this.handle_onbeforecopy.bind(this));
- $(window).bind("beforeunload", this.handle_onunload.bind(this));
- $(window).bind("resize", this.handle_window_resize.bind(this));
- },
- setup_watches: function() {
- this.$watch('active_style.stroke', function (value, mutation) {
- this.set_artifact_style_prop("stroke",parseInt(this.active_style.stroke));
- }.bind(this));
- this.$watch('active_style.border_radius', function (value, mutation) {
- this.set_artifact_style_prop("border_radius",parseInt(this.active_style.border_radius));
- }.bind(this));
- this.$watch('active_style.padding', function (value, mutation) {
- this.active_style.padding_horz = this.active_style.padding;
- this.active_style.padding_vert = this.active_style.padding;
- }.bind(this));
- this.$watch('active_style.padding_horz', function (value, mutation) {
- this.active_style.padding_left = this.active_style.padding_horz;
- this.active_style.padding_right = this.active_style.padding_horz;
- }.bind(this));
- this.$watch('active_style.padding_vert', function (value, mutation) {
- this.active_style.padding_top = this.active_style.padding_vert;
- this.active_style.padding_bottom = this.active_style.padding_vert;
- }.bind(this));
- this.$watch('active_style.padding_top', function (value, mutation) {
- this.set_artifact_style_prop("padding_top",parseInt(this.active_style.padding_top));
- }.bind(this));
- this.$watch('active_style.padding_bottom', function (value, mutation) {
- this.set_artifact_style_prop("padding_bottom",parseInt(this.active_style.padding_bottom));
- }.bind(this));
- this.$watch('active_style.padding_left', function (value, mutation) {
- this.set_artifact_style_prop("padding_left",parseInt(this.active_style.padding_left));
- }.bind(this));
- this.$watch('active_style.padding_right', function (value, mutation) {
- this.set_artifact_style_prop("padding_right",parseInt(this.active_style.padding_right));
- }.bind(this));
- this.$watch('active_style.margin', function (value, mutation) {
- this.active_style.margin_horz = this.active_style.margin;
- this.active_style.margin_vert = this.active_style.margin;
- }.bind(this));
- this.$watch('active_style.margin_horz', function (value, mutation) {
- this.active_style.margin_left = this.active_style.margin_horz;
- this.active_style.margin_right = this.active_style.margin_horz;
- }.bind(this));
- this.$watch('active_style.margin_vert', function (value, mutation) {
- this.active_style.margin_top = this.active_style.margin_vert;
- this.active_style.margin_bottom = this.active_style.margin_vert;
- }.bind(this));
- this.$watch('active_style.margin_top', function (value, mutation) {
- this.set_artifact_style_prop("margin_top",parseInt(this.active_style.margin_top));
- }.bind(this));
- this.$watch('active_style.margin_bottom', function (value, mutation) {
- this.set_artifact_style_prop("margin_bottom",parseInt(this.active_style.margin_bottom));
- }.bind(this));
- this.$watch('active_style.margin_left', function (value, mutation) {
- this.set_artifact_style_prop("margin_left",parseInt(this.active_style.margin_left));
- }.bind(this));
- this.$watch('active_style.margin_right', function (value, mutation) {
- this.set_artifact_style_prop("margin_right",parseInt(this.active_style.margin_right));
- }.bind(this));
- this.$watch('active_style.stroke_color', function (value, mutation) {
- this.set_artifact_style_prop("stroke_color",this.active_style.stroke_color);
- var rgba = hex_to_rgba(this.active_style.stroke_color);
- var hsv = rgb_to_hsv(rgba.r, rgba.g, rgba.b);
- this.active_style.stroke_color_hsv = hsv;
- }.bind(this));
- this.$watch('active_style.fill_color', function (value, mutation) {
- this.set_artifact_style_prop("fill_color",this.active_style.fill_color);
- var rgba = hex_to_rgba(this.active_style.fill_color);
- var hsv = rgb_to_hsv(rgba.r, rgba.g, rgba.b);
- this.active_style.fill_color_hsv = hsv;
- }.bind(this));
- this.$watch('active_style.text_color', function (value, mutation) {
- this.set_artifact_style_prop("text_color",this.active_style.text_color);
- this.apply_formatting(null,"forecolor",this.active_style.text_color);
- var rgba = hex_to_rgba(this.active_style.text_color);
- var hsv = rgb_to_hsv(rgba.r, rgba.g, rgba.b);
- this.active_style.text_color_hsv = hsv;
- }.bind(this));
- this.$watch('active_style.font_size', function (value, mutation) {
- this.apply_formatting(null,"preciseFontSize",this.active_style.font_size+"px");
- }.bind(this));
- this.$watch('active_style.line_height', function (value, mutation) {
- this.apply_formatting(null,"lineHeight",this.active_style.line_height+"em");
- }.bind(this));
- this.$watch('active_style.letter_spacing', function (value, mutation) {
- this.apply_formatting(null,"letterSpacing",this.active_style.letter_spacing+"px");
- }.bind(this));
- // color picker
- this.$watch('color_picker_hue', function (value, mutation) {
- this.apply_color_picker();
- }.bind(this));
- this.$watch('color_picker_value', function (value, mutation) {
- this.apply_color_picker();
- }.bind(this));
- this.$watch('color_picker_saturation', function (value, mutation) {
- this.apply_color_picker();
- }.bind(this));
- this.$watch('color_picker_opacity', function (value, mutation) {
- this.apply_color_picker();
- }.bind(this));
- // filters
- this.$watch('active_style.brightness', function (value, mutation) {
- this.set_artifact_style_prop("brightness",parseInt(this.active_style.brightness));
- }.bind(this));
- this.$watch('active_style.blur', function (value, mutation) {
- this.set_artifact_style_prop("blur",parseInt(this.active_style.blur));
- }.bind(this));
- this.$watch('active_style.contrast', function (value, mutation) {
- this.set_artifact_style_prop("contrast",parseInt(this.active_style.contrast));
- }.bind(this));
- this.$watch('active_style.saturation', function (value, mutation) {
- this.set_artifact_style_prop("saturation",parseInt(this.active_style.saturation));
- }.bind(this));
- this.$watch('active_style.hue', function (value, mutation) {
- this.set_artifact_style_prop("hue",parseInt(this.active_style.hue));
- }.bind(this));
- this.$watch('active_style.opacity', function (value, mutation) {
- this.set_artifact_style_prop("opacity",parseInt(this.active_style.opacity));
- }.bind(this));
- this.throttled_save_active_space = _.throttle(function(){
- save_space(this.active_space);
- }.bind(this), 2000);
- // canvas
- this.$watch('active_style.background_color', function (value, mutation) {
- if (this.active_style.background_color != this.active_space.background_color) {
- this.$set("active_space.background_color",this.active_style.background_color);
- this.throttled_save_active_space();
- }
- var rgba = hex_to_rgba(this.active_style.background_color);
- var hsv = rgb_to_hsv(rgba.r, rgba.g, rgba.b);
- this.active_style.background_color_hsv = hsv;
- }.bind(this));
- },
- if_editable: function(fn) {
- // call given closure if space is editable
- // used by key bindings
- if (this.active_space_role!="viewer") fn.bind(this)();
- },
- background_image_style: function(images) {
- if (!images) return null;
- if (isNaN(images.length)) images = [images];
- for (var i=0; i<images.length; i++) {
- if (images[i] && images[i].length>0) {
- return "background-image: url("+images[i]+")";
- }
- }
- },
- space_thumbnail_style: function(space) {
- if (space.avatar_thumb_uri && space.avatar_thumb_uri.length>0) {
- return "background-image:url('"+space.avatar_thumb_uri+"')";
- }
- if (space.space_type == "folder") return "";
- return "background-image:url('/api/spaces/"+space._id+"/png')";
- },
- reset_artifact_filters: function() {
- this.active_style.brightness = this.default_style.brightness;
- this.active_style.contrast = this.default_style.contrast;
- this.active_style.opacity = this.default_style.opacity;
- this.active_style.saturation = this.default_style.saturation;
- this.active_style.blur = this.default_style.blur;
- this.active_style.hue = this.default_style.hue;
- },
- increase_columns: function() {
- if (this.active_style.columns<this.MAX_COLUMNS) this.active_style.columns++;
- },
- decrease_columns: function() {
- if (this.active_style.columns>1) this.active_style.columns--;
- },
- extract_properties_from_selection: function() {
- // stop extract->apply feedback loop
- this.skip_formatting = true;
-
- var arts = this.selected_artifacts();
- window.setTimeout(function() {
- this.skip_formatting = false;
- }.bind(this),10);
- if (!arts.length) return;
- if (arts.length == 1) {
- var a = arts[0];
- var props = [
- "stroke",
- "border_radius",
- "letter_spacing",
- "stroke_color",
- "fill_color",
- "text_color"
- ];
- for (var i=0; i<props.length; i++) {
- var prop = props[i];
- this.active_style[prop]=a[prop];
- }
- // defaults
- //this.active_style.padding = this.default_style.padding;
- this.active_style.font_size = this.default_style.font_size;
- this.active_style.line_height = this.default_style.line_height;
- this.active_style.letter_spacing = this.default_style.letter_spacing;
- this.active_style.padding_top = a.padding_top || 0;
- this.active_style.padding_bottom = a.padding_bottom || 0;
- this.active_style.padding_left = a.padding_left || 0;
- this.active_style.padding_right = a.padding_right || 0;
- if (this.active_style.padding_top == this.active_style.padding_bottom) {
- this.active_style.padding_vert = this.active_style.padding_top;
- }
- if (this.active_style.padding_left == this.active_style.padding_right) {
- this.active_style.padding_horz = this.active_style.padding_left;
- }
- if (this.active_style.padding_top == this.active_style.padding_bottom &&
- this.active_style.padding_left == this.active_style.padding_right &&
- this.active_style.padding_left == this.active_style.padding_top) {
- this.active_style.padding = this.active_style.padding_top;
- }
- this.active_style.margin_top = a.margin_top || 0;
- this.active_style.margin_bottom = a.margin_bottom || 0;
- this.active_style.margin_left = a.margin_left || 0;
- this.active_style.margin_right = a.margin_right || 0;
- if (this.active_style.margin_top == this.active_style.margin_bottom) {
- this.active_style.margin_vert = this.active_style.margin_top;
- }
- if (this.active_style.margin_left == this.active_style.margin_right) {
- this.active_style.margin_horz = this.active_style.margin_left;
- }
- if (this.active_style.margin_top == this.active_style.margin_bottom &&
- this.active_style.margin_left == this.active_style.margin_right &&
- this.active_style.margin_left == this.active_style.margin_top) {
- this.active_style.margin = this.active_style.margin_top;
- }
- }
- this.update_selection_metrics();
- // extract text styles
- this.selection_metrics.contains_text = false;
- this.selection_metrics.contains_images = false;
- this.selection_metrics.contains_audio = false;
- this.selection_metrics.contains_embeds = false;
- this.selection_metrics.contains_vectors = false;
- this.selection_metrics.contains_shapes = false;
- this.selection_metrics.borders_stylable = false;
- var notes = _.filter(arts, function(a) { return (a.mime=="text/html" || a.mime=="x-spacedeck/shape") });
- if (notes.length>=1) {
- this.selection_metrics.contains_text = true;
- if (notes.length==1) {
- var a = notes[0];
- var dom = $("<div>"+a.description+"</div>")[0];
- var el = dom.firstChild;
- do {
- if (el && el.style) {
- if (el.style.fontSize) this.active_style.font_size = parseInt(el.style.fontSize);
- if (el.style.fontFamily) this.active_style.font_family = el.style.fontFamily;
- if (el.style.letterSpacing) this.active_style.letter_spacing = parseInt(el.style.letterSpacing);
- if (el.style.lineHeight) this.active_style.line_height = parseFloat(el.style.lineHeight);
- if (el.style.color) this.active_style.text_color = el.style.color;
- }
- } while (el && (el = dom.nextSibling));
- }
- }
- if (arts.length == 1) {
- this.extract_color_picker_from_selection();
- }
- var images = _.filter(arts, function(a) { return a.mime.match("image") });
- if (images.length>=1) {
- this.selection_metrics.contains_images = true;
- }
- var audio = _.filter(arts, function(a) { return a.mime.match("audio") });
- if (audio.length>=1) {
- this.selection_metrics.contains_audio = true;
- }
- var embeds = _.filter(arts, function(a) { return a.mime.match("embed") });
- if (embeds.length>=1) {
- this.selection_metrics.contains_embeds = true;
- }
- var embeds = _.filter(arts, function(a) { return a.mime=="x-spacedeck/vector" });
- if (embeds.length>=1) {
- this.selection_metrics.contains_vectors = true;
- }
- var embeds = _.filter(arts, function(a) { return a.mime=="x-spacedeck/shape"; });
- if (embeds.length>=1) {
- this.selection_metrics.contains_shapes = true;
- }
- var sm = this.selection_metrics;
- this.selection_metrics.borders_stylable = !(sm.contains_vectors||sm.contains_shapes);
- },
- increase_letter_spacing: function(evt) {
- this.active_style.letter_spacing++;
- },
- decrease_letter_spacing: function(evt) {
- this.active_style.letter_spacing--;
- },
- apply_font: function(evt, font) {
- this.apply_formatting(evt,'fontName',font);
- this.active_style.font_family = font;
- },
- toggle_advanced_properties: function() {
- this.advanced_properties = !this.advanced_properties;
- },
- open_dialog: function(id, evt) {
- if (evt) {
- evt.stopPropagation();
- evt.preventDefault();
- }
- this.active_tool = "pointer";
- if (this.opened_dialog == id) {
- this.opened_dialog = "none";
- return;
- }
- if (_.contains(["mobile","shapes","zones"],id)) {
- this.deselect();
- }
-
- this.opened_dialog=id;
- if (id.match("color") || id.match("background")) {
- this.color_picker_target = id.replace("color-","")+"_color";
- this.color_mode = "palette";
- this.extract_color_picker_from_selection();
- }
- if (_.contains(["audio","video","image","search"],id)) {
- if ($("#"+id+" input")[0]) {
- $("#"+id+" input")[0].focus();
- }
- }
- if (this.opened_dialog == "background") {
- this.color_picker_target = "background_color";
- this.background_mode='color';
- }
- if (this.opened_dialog == "info") {
- this.access_settings_space = this.active_space;
- this.access_settings_memberships = this.active_space_memberships;
- this.editors_section = "list";
- if (this.active_space_is_readonly || this.embedded) {
- this.space_info_section = "info";
- } else if (this.active_space_role == "admin") {
- this.space_info_section = "access";
- }
- }
- },
- toggle_color_options: function() {
- this.color_options_picker = !this.color_options_picker;
- },
- close_lightbox: function() {
- this.lightbox_artifact = {};
- this.close_modal();
- },
- /* --------------- artifact manipulation ------------------------- */
- prepare_clipboard: function() {
- if ('ontouchstart' in window) return; // don't do this on touch devices
- this.selected_artifacts_json = JSON.stringify(this.selected_artifacts());
- //$("#space-clipboard > textarea")[0].blur();
- this.prepare_clipboard_step2();
- },
- prepare_clipboard_step2: function() {
- if ('ontouchstart' in window) return; // don't do this on touch devices
- setTimeout(function() {
- if (!$("#space-clipboard > textarea").length) return; // not ready yet
- $("#space-clipboard > textarea")[0].focus();
- $("#space-clipboard > textarea")[0].select();
- },100);
- },
- handle_section_keydown: function(evt) {
- if (evt.keyCode == 67 && (evt.ctrlKey || evt.metaKey)) { // c key
- this.prepare_clipboard();
- this.prepare_clipboard_step2();
- }
- return true;
- },
- handle_onbeforecopy: function(evt) {
- if (this.editing_artifact_id) return;
- var focused_tag = evt.target.nodeName.toLowerCase();
- if (focused_tag != "body") return;
- this.prepare_clipboard_step2();
- window.setTimeout(function() {
- if (!$("#space-clipboard > textarea").length) return; // not ready yet
- $("#space-clipboard > textarea")[0].blur();
- },10);
- },
- handle_onunload: function(evt) {
- if (!window.artifact_save_queue) return;
- var changes = Object.keys(window.artifact_save_queue).length;
- if (changes>0) {
- var message = "There are "+changes+" changes that are still being saved. Discard them?";
- evt.returnValue = message;
- return message;
- }
- window._spacedeck_location_change = true;
- },
- handle_window_resize: function(evt) {
- this.adjust_bounds_zoom();
- },
- handle_scroll: function(evt) {
- if (this.active_view!="space") return;
- if (!$("#space").length) return;
- el = $("#space")[0];
- this.scroll_left = el.scrollLeft/this.viewport_zoom;
- this.scroll_top = el.scrollTop/this.viewport_zoom;
- this.window_width = window.innerWidth/this.viewport_zoom;
- this.window_height = window.innerHeight/this.viewport_zoom;
- this.resize_minimap();
- // follow presenter mode: send viewport rectangle to viewers
- if (this.logged_in && this.present_mode) {
- if (this.active_space_role!="viewer") {
- this.presenter_send_viewport();
- }
- }
- },
- presenter_send_viewport: function() {
- name = this.user.nickname || this.user.email;
-
- var msg = {
- action: "viewport",
- x: this.scroll_left,
- y: this.scroll_top,
- w: this.window_width,
- h: this.window_height,
- zoom: this.viewport_zoom,
- name: name,
- id: this.user._id
- };
- var packed = JSON.stringify(msg);
- if (packed==this._old_viewport_msg) return;
- this._old_viewport_msg = packed;
-
- if (this.present_mode && this.active_space_role!="viewer")
- this.websocket_send(msg);
- },
- presenter_send_media_action: function(artifact_id,type,cmd,time) {
- name = this.user.nickname || this.user.email;
-
- var msg = {
- action: "media",
- artifact_id: artifact_id,
- type: type,
- command: cmd,
- time: time,
- name: name,
- id: this.user._id
- };
- if (this.present_mode && this.active_space_role!="viewer")
- this.websocket_send(msg);
- },
- resize_minimap: function() {
- if (!this.active_space) return;
- this.minimap_scale = this.active_space.width/100.0;
- },
- handle_minimap_mouseup: function(evt) {
- this.minimap_mouse_state = "idle";
- },
- handle_minimap_mousemove: function(evt) {
- if (this.minimap_mouse_state=="pressed") {
- this.handle_minimap_mousedown(evt);
- }
- },
- handle_minimap_mousedown: function(evt) {
- if (!$("#space").length) return;
- this.minimap_mouse_state = "pressed";
- el = $("#space")[0];
- evt = fixup_touches(evt);
- var ofs = $(evt.target).offset();
- var x = evt.pageX - ofs.left;
- var y = evt.pageY - ofs.top;
- el.scrollLeft = (x-this.window_width/(this.minimap_scale*2))*this.minimap_scale*this.viewport_zoom;
- el.scrollTop = (y-this.window_height/(this.minimap_scale*2))*this.minimap_scale*this.viewport_zoom;
- this.handle_scroll();
- },
- handle_user_cursor_update: function(msg) {
- // console.log("handle cursor", msg);
- var now = new Date().getTime();
- msg.t = now;
- var existing = false;
- for (var i=0; i<this.user_cursors.length; i++) {
- var u = this.user_cursors[i];
- if (u.id == msg.id) {
- u.x = msg.x;
- u.y = msg.y;
- u.t = now;
- u.name = msg.name;
- // console.log("updated cursor "+i);
- existing = true;
- } else {
- // hide if no updates since 2sec
- if ((now-u.t)>5000) {
- u.x=-10000;
- }
- }
- }
- if (!existing) {
- this.user_cursors.push(_.clone(msg));
- }
- },
- handle_presenter_viewport_update: function(msg) {
- this.zoom_to_rect({
- x1: msg.x,
- y1: msg.y,
- x2: msg.x+msg.w,
- y2: msg.y+msg.h
- });
- },
-
- handle_presenter_media_update: function(msg) {
- if(this.follow_mode) {
- if (msg.type=="audio") {
- var sel="#artifact-"+msg.artifact_id+" .audio";
- try {
- $(sel)[0].dispatchEvent(new Event("remote_"+msg.command));
- console.log("event dispatched");
- } catch (e) {
- }
- }
- if (msg.type=="video") {
- var sel="#artifact-"+msg.artifact_id+" .video";
- try {
- $(sel)[0].dispatchEvent(new Event("remote_"+msg.command));
- console.log("event dispatched");
- } catch (e) {
- }
- }
- } else {
- console.log("ignore media update, muted");
- }
- },
- may_select: function(a) {
- if (!a) return false;
- if (!this.active_space) return false;
-
- if (this.active_space_role=="viewer" || (a.locked && this.active_space_role!="admin")) {
- return false;
- }
- if (this.active_space.editors_locking && !this.logged_in && this.guest_nickname!=a.editor_name) {
- return false;
- }
- return true;
- },
- select: function(evt, a) {
- if (!this.may_select(a)) return;
- if (evt && !evt.shiftKey && this.is_selected(a)) return; // already selected
- if (!evt || !evt.shiftKey) {
- this.deselect();
- }
- if (evt && evt.shiftKey) {
- if (this.selected_artifacts_dict[a._id]) {
- delete this.selected_artifacts_dict[a._id];
- } else {
- this.selected_artifacts_dict[a._id] = true;
- }
- } else {
- this.selected_artifacts_dict[a._id] = true;
- }
- this.update_board_artifact_viewmodel(a);
- this.extract_properties_from_selection();
- this.update_selection_metrics();
- this.prepare_clipboard();
- this.show_toolbar_props();
- },
- select_all_artifacts: function(evt) {
- this.deselect();
- for (var i=0; i<this.active_space_artifacts.length; i++) {
- var a = this.active_space_artifacts[i];
- if (this.may_select(a)) {
- this.selected_artifacts_dict[a._id] = true;
- this.update_board_artifact_viewmodel(a);
- }
- }
- this.update_selection_metrics();
- this.extract_properties_from_selection();
- this.prepare_clipboard();
- this.show_toolbar_props();
- },
- multi_select: function(arts) {
- for (var i=0; i<arts.length; i++) {
- var a = arts[i];
- if (this.may_select(a)) {
- this.selected_artifacts_dict[a._id] = true;
- this.update_board_artifact_viewmodel(a);
- }
- }
- this.extract_properties_from_selection();
- this.update_selection_metrics();
- this.prepare_clipboard();
- this.show_toolbar_props();
- },
- discover_zones: function() {
- this.zones = _.sortBy(_.filter(this.active_space_artifacts, function(a) { return (a.mime=="x-spacedeck/zone") }),
- function(z){return z.order});
- },
- artifact_plaintext: function(a) {
- if (!a) return "";
- var txt = $("<div>"+a.description+"</div>").text();
- return txt || "";
- },
- deselect: function(hard) {
- if (window._sd_fader_moving) {
- window._sd_fader_moving = false; // signal from fader directive
- return;
- }
- this.hide_toolbar_props();
- document.getSelection().removeAllRanges();
- blur();
- //this.prepare_clipboard();
- this.prepare_clipboard_step2();
- this.discover_zones();
- var prev_selected = this.selected_artifacts();
- this.selected_artifacts_dict = {};
- // nuke empty notes
- for (var i=0; i<prev_selected.length; i++) {
- var a = prev_selected[i];
- var keep = true;
- if (a && a.mime == "text/html") {
- var txt = this.artifact_plaintext(a);
- if (txt.length == 0) {
- keep = true; //Quick Fix For yassin, complains about buggy behaviour
- }
- }
- if (!keep) {
- this.selected_artifacts_dict[a._id] = a;
- }
- }
- this.delete_selected_artifacts(null, true); // delete all selected in loop
- this.selected_artifacts_dict = {};
- this.editing_artifact_id = null;
- this.opened_dialog = "none";
- for (var i=0; i<prev_selected.length; i++) {
- this.update_board_artifact_viewmodel(prev_selected[i]);
- }
- /*this.selection_metrics.x=0;
- this.selection_metrics.y=0;
- this.selection_metrics.w=0;
- this.selection_metrics.h=0;
- this.selection_metrics.style="display:none";*/
- this.selection_metrics.contains_text=false;
- this.selection_metrics.count=0;
- if (hard) {
- this.active_tool = "pointer";
- this.mouse_state = "idle";
- }
- this.update_selection_metrics();
- },
- is_selected: function(a) {
- if (!a) return;
- return (!!this.selected_artifacts_dict[a._id]);
- },
- unselected_artifacts: function() {
- return this.active_space_artifacts.filter(function(a){return !this.is_selected(a)}.bind(this));
- },
- selection_rect_style: function() {
- var r = this.selection_rect();
- if (r==null) return "display:none";
- return "left:"+r.x1+"px;top:"+r.y1+"px;width:"+(r.x2-r.x1)+"px;height:"+(r.y2-r.y1)+"px;";
- },
- selection_rect: function() {
- return this.enclosing_rect(this.selected_artifacts());
- },
- enclosing_rect: function(arts) {
- if (arts.length==0) return null;
- arts = _.filter(arts); // remove any nulls
- return {
- x1: parseInt(_.min(arts.map(function(a){return ((!a || !a.x)?0:a.x)}))),
- y1: parseInt(_.min(arts.map(function(a){return ((!a || !a.y)?0:a.y)}))),
- x2: parseInt(_.max(arts.map(function(a){return (!a?0:a.x+a.w)}))),
- y2: parseInt(_.max(arts.map(function(a){return (!a?0:a.y+a.h)})))
- };
- },
- update_selection_metrics: function(arts) {
- if (this.active_tool == "scribble") {
- this.selection_metrics.count = 1;
- return;
- }
-
- var sr = this.selection_rect() || {x:0,y:0,w:0,h:0,style:"display:none"};
- if (sr.x1 || sr.x2) {
- sr.w = sr.x2-sr.x1;
- sr.h = sr.y2-sr.y1;
- sr.style = this.selection_rect_style();
- var pp = this.space_point_to_window(sr.x1+sr.w/2,sr.y2);
- var pp2 = this.space_point_to_window(sr.x1+sr.w/2,sr.y1);
- pp.x-=260;
- pp.y-=10;
- if (pp.y>=window.innerHeight-300) {
- pp.y = pp2.y-100;
- }
- if (pp.x<0) {
- pp.x=0;
- }
- if (pp.y<0) {
- pp.y=0;
- }
- // FIXME make sure that menus fit in window
- this.toolbar_props_x = pp.x+"px";
- this.toolbar_props_y = pp.y+"px";
-
- this.hide_toolbar_artifacts();
- }
- this.selection_metrics.x1 = sr.x1;
- this.selection_metrics.x2 = sr.x2;
- this.selection_metrics.y1 = sr.y1;
- this.selection_metrics.y2 = sr.y2;
- this.selection_metrics.x = sr.x;
- this.selection_metrics.y = sr.y;
- this.selection_metrics.w = sr.w;
- this.selection_metrics.h = sr.h;
- this.selection_metrics.style = sr.style;
- if (!arts) arts = this.selected_artifacts();
- this.first_selected_artifact = arts[0];
- this.selection_metrics.count=arts.length;
- this.selection_metrics.scribble_selection = false;
- if (arts.length == 1 && arts[0].mime == "x-spacedeck/vector") {
- if (arts[0].shape == "scribble") {
- this.selection_metrics.scribble_selection = true;
- }
- this.selection_metrics.vector_points = arts[0].control_points;
- this.selection_metrics.vector_selection = true;
- } else {
- this.selection_metrics.vector_points = [{},{}];
- this.selection_metrics.vector_selection = false;
- }
- this.selection_metrics.has_link=false;
- this.insert_link_url="";
- if (arts.length == 1 && arts[0].meta && arts[0].meta.link_uri && arts[0].meta.link_uri.length>0) {
- this.selection_metrics.has_link=true;
- this.insert_link_url = arts[0].meta.link_uri;
- }
- },
- begin_transaction: function() {
- this.transaction_running = true;
- if (!this.undo_stack.length || this.undo_stack[this.undo_stack.length-1].action!="empty") {
- this.undo_stack.push({action:"empty"});
- } else {
- //console.log("undo slot is already empty.");
- }
- this.redo_stack = [];
- this.artifacts_before_transaction = this.active_space_artifacts.map(function(a) {
- return _.cloneDeep(a);
- });
- },
- fixup_space_size: function() {
- if (!this.active_space) return;
- this.active_space.width =Math.max(this.active_space.width, window.innerWidth);
- this.active_space.height=Math.max(this.active_space.height, window.innerHeight);
- },
- end_transaction: function() {
- this.transaction_running = false;
- this.throttled_process_artifact_save_queue();
- if (!this.active_space) return;
- var er = this.enclosing_rect(this.active_space_artifacts);
- if (!er) return;
- this.active_space.width =Math.max(er.x2+100, window.innerWidth);
- this.active_space.height=Math.max(er.y2+100, window.innerHeight);
- if (this._last_bounds_width != this.active_space.width ||
- this._last_bounds_height != this.active_space.height) {
- this._last_bounds_width = this.active_space.width;
- this._last_bounds_height = this.active_space.height;
- save_space(this.active_space);
- }
- this.resize_minimap();
- this.discover_zones();
- },
- find_artifact_before_transaction: function(needle) {
- return this.find_artifact_in_array(this.artifacts_before_transaction, needle);
- },
- find_artifact_in_array: function(haystack, needle) {
- var res = _.find(haystack, function(a) {
- return (needle._id && (a._id == needle._id));
- });
- return res;
- },
- unsaved_transactions: function() {
- if (!window.artifact_save_queue) return 0;
- return Object.keys(window.artifact_save_queue).length;
- },
- process_artifact_save_queue: function() {
- if (!window.artifact_save_queue) {
- return;
- }
- if (this.transaction_running) {
- console.log("not saving, transaction still in progress.");
- return;
- }
- var ids = Object.keys(window.artifact_save_queue);
- for (var i=0; i<ids.length; i++) {
- var id = ids[i];
- var a = window.artifact_save_queue[id];
- if (this.guest_nickname) {
- a.editor_name = this.guest_nickname;
- }
- save_artifact(a, function() {
- delete window.artifact_save_queue[id];
- }.bind(this), function(req) {
- if (req && req.status == 404) {
- // artifact was already deleted, ignore
- delete window.artifact_save_queue[id];
- } else {
- console.log("could not save artifact, will try again:",a,req);
- }
- });
- }
- // mark version dirty locally
- if (this.active_space) {
- this.active_space.updated_at = (new Date()).getTime();
- }
- //window.artifact_save_queue = {};
- },
- throttled_process_artifact_save_queue: function() {
- if (!this._throttled_process_artifact_save_queue) {
- this._throttled_process_artifact_save_queue = _.throttle(this.process_artifact_save_queue, 500);
- }
- this._throttled_process_artifact_save_queue();
- },
- queue_artifact_for_save: function(a) {
- if (!window.artifact_save_queue) {
- window.artifact_save_queue = {};
- }
- if (!a._id) {
- console.log("warning: illegal artifact queued for save");
- }
- // this is a bit hacky, but might be the smartest place to do it
- if (a.view && a.view.vector_svg) {
- a.shape_svg = a.view.vector_svg;
- }
- window.artifact_save_queue[a._id] = a;
- },
- update_properties: function(artifact_ids, changes) {
- for (var i=0; i<artifact_ids.length; i++) {
- var id = artifact_ids[i];
- var a = this.find_artifact_by_id(id);
- if (a) {
- var changed = false;
- for (k in changes[i]) {
- //console.log("change: ",k,": ",changes[i][k],"<-",a[k])
- a[k] = changes[i][k];
- changed = true;
- }
- this.update_board_artifact_viewmodel(a);
- // TODO: throttle, bundle etc
- if (changed) {
- this.queue_artifact_for_save(a);
- }
- }
- }
- },
- update_artifacts: function(artifacts, change_func) {
- var artifact_ids = [];
- var changes = [];
- for (var i=0; i<artifacts.length; i++) {
- var a = artifacts[i];
- var c = change_func(a);
- if (c) {
- artifact_ids.push(a._id);
- changes.push(c);
- }
- }
- if (changes.length) {
- this.push_to_undo({
- action: "update",
- artifact_ids: artifact_ids,
- changes: changes,
- snapshot: this.artifacts_before_transaction
- });
- }
- if (changes.length) {
- this.update_properties(artifact_ids, changes);
- }
- },
- push_to_undo: function(transaction) {
- // begin_transaction opens new undo slot
- // push_to_undo replaces the current undo slot
- this.undo_stack[this.undo_stack.length-1] = transaction;
- //console.log(transaction.action+"; undo_stack len: ",this.undo_stack.length);
- },
- undo: function() {
- if (!this.undo_stack.length || this.undo_stack[this.undo_stack.length-1].action=="empty") {
- console.log("nothing to undo!");
- return;
- }
- var step = this.undo_stack.pop();
- console.log("undo popped: ",step);
- this.redo_stack.push(step);
- for (var i=0; i<step.artifact_ids.length; i++) {
- var id = step.artifact_ids[i];
- var old_version = this.find_artifact_in_array(step.snapshot, {_id:id});
- if (step.action == "update") {
- if (old_version) {
- this.update_properties([id], [old_version]);
- }
- } else {
- delete old_version._id;
- save_artifact(old_version, function(restored_a) {
- this.update_board_artifact_viewmodel(restored_a);
- this.active_space_artifacts.push(restored_a);
- // TODO: rewrite undo history's artifact ids
- }.bind(this));
- }
- }
- this.update_selection_metrics();
- },
- redo: function() {
- if (!this.redo_stack.length) {
- console.log("nothing to redo!");
- return;
- }
- var step = this.redo_stack.pop();
- console.log("redo popped: ",step);
- this.undo_stack.push(step);
- this.update_properties(step.artifact_ids, step.changes);
- this.update_selection_metrics();
- },
- set_artifact_prop: function(prop, val) {
- this.begin_transaction();
- this.update_selected_artifacts(function(a) {
- var c = {};
- if (a[prop] != val) {
- //console.log("set_artifact_prop: ",c,val);
- c[prop]=val;
- return c;
- }
- return null;
- });
- },
- set_artifact_style_prop: function(prop, val) {
- this.begin_transaction();
- this.update_selected_artifacts(function(a) {
- var c = {};
-
- if (a[prop] != val) {
- //console.log("set_artifact_style_prop: ",c,val);
- c[prop]=val;
- return c;
- }
- return null;
- });
- },
- activate_color_mode: function(mode) {
- this.color_mode = mode;
- if (mode == 'picker') {
- // default to full alpha if color is 0,0,0,0
- if (this.color_picker_hue == 0 &&
- this.color_picker_saturation == 0 &&
- this.color_picker_value == 0 &&
- this.color_picker_opacity == 0) {
- this.color_picker_opacity = 255;
- this.color_picker_value = 255;
- }
- }
- },
- reset_stroke: function() {
- this.active_style.stroke = 0;
- this.active_style.border_radius = 0;
- this.active_style.stroke_style = "solid";
- },
- apply_font_size: function(px) {
- this.apply_formatting(null,"preciseFontSize",px+"px");
- },
- apply_swatch_color: function(swatch) {
- var rgba = hex_to_rgba(swatch.hex);
- var hsv = rgb_to_hsv(rgba.r, rgba.g, rgba.b);
- this.color_picker_hue = parseFloat(hsv.h*255);
- this.color_picker_saturation = parseFloat(hsv.s*255);
- this.color_picker_value = parseFloat(hsv.v*255);
- this.color_picker_opacity = rgba.a*255;
- this.color_picker_rgb = rgb_to_hex(rgba.r,rgba.g,rgba.b);
- //console.log("swatch hex: ",swatch.hex);
- this.active_style[this.color_picker_target] = swatch.hex;
- if (this.color_picker_target == "stroke_color") {
- if (!this.active_style.stroke) {
- // set a default stroke for convenience
- this.active_style.stroke = 2;
- }
- }
- },
- apply_color_picker: function() {
- var rgb = hsv_to_rgb(this.color_picker_hue/255,
- this.color_picker_saturation/255,
- this.color_picker_value/255);
- var alpha = this.color_picker_opacity/255;
- //console.log("apply_color_picker: ",rgb,alpha);
- this.active_style[this.color_picker_target] = "rgba("+[rgb.r,rgb.g,rgb.b,alpha].join(",")+")";
- },
- extract_color_picker_from_selection: function() {
- if (this.selected_artifacts().length!=1 && this.opened_dialog!="background") return;
- if (this.opened_dialog=="background") {
- this.active_style[this.color_picker_target] = this.active_space.background_color;
- } else {
- if (!this.active_style[this.color_picker_target]) {
- this.active_style[this.color_picker_target] = this.default_style[this.color_picker_target];
- }
- }
- //console.log("active_style for "+this.color_picker_target+": ",this.active_style[this.color_picker_target]);
- var rgba = hex_to_rgba(this.active_style[this.color_picker_target]);
- var hsv = rgb_to_hsv(rgba.r, rgba.g, rgba.b);
- this.color_picker_hue = parseFloat(hsv.h*255);
- this.color_picker_saturation = parseFloat(hsv.s*255);
- this.color_picker_value = parseFloat(hsv.v*255);
- this.color_picker_opacity = parseInt(rgba.a);
- this.color_picker_rgb = rgb_to_hex(rgba.r,rgba.g,rgba.b);
- },
- update_selected_artifacts: function(change_func, override_locked) {
- var artifacts = this.selected_artifacts(!override_locked);
- if (!artifacts.length) return;
- this.update_artifacts(artifacts, change_func);
- this.update_selection_metrics();
- },
- nudge_selected_artifacts: function(dx, dy, event) {
- if (this.present_mode) {
- if (dx>0 || dy>0) {
- this.go_to_next_zone();
- return;
- }
- if (dx<0 || dy<0) {
- this.go_to_previous_zone();
- return;
- }
- }
- if (!this.selected_artifacts().length) {
- if (!$("#space").length) return;
- var el = $("#space")[0];
- el.scrollLeft+=dx*100;
- el.scrollTop +=dy*100;
- return;
- }
- if (this.active_space_is_readonly) return;
- if (event) {
- event.preventDefault();
- event.stopPropagation();
- }
- this.begin_transaction();
- this.update_selected_artifacts(function(a) {
- return {
- x: a.x+dx,
- y: a.y+dy
- };
- });
- },
- /* -------------------------------------------------------------------- */
- highest_z: function() {
- var z = _.max(this.active_space_artifacts.map(function(a){return a.z||0}));
- if (z<0) z=0;
- if (z>999) z=999;
- return z;
- },
- find_place_for_item: function(width, height) {
- var arts = this.active_space_artifacts;
- var tw = window.innerWidth;
- var th = window.innerHeight;
- var el = $("#space")[0];
-
- if (!el) return {x:0,y:0,z:1}; // FIXME
- var wrap = $(".wrapper");
- var wx = parseInt(wrap.css("margin-left"));
- var wy = parseInt(wrap.css("margin-top"));
- var x = parseInt((el.scrollLeft + tw/2)/this.viewport_zoom - width/2 - wx/this.viewport_zoom);
- var y = parseInt((el.scrollTop + th/2)/this.viewport_zoom - height/2 - wy/this.viewport_zoom);
- /*
- if (this.opened_dialog!="none") {
- // we have less visible space if a dialog is obscuring sight
- y/=2;
- }
- */
- var z = this.highest_z()+1;
- if (arts.length==0) return {x:x,y:y};
- x += parseInt(Math.random()*20)-10;
- y += parseInt(Math.random()*20)-10;
- return {x:x,y:y,z:z};
- },
- save_audio_edit: function(a) { // just a helper to be called from view model
- this.opened_dialog = "none";
- this.update_board_artifact_viewmodel(a);
- save_artifact(a);
- },
- save_artifact: function(a, on_success) { // helper to be called from view model
- if (this.guest_nickname) {
- a.editor_name = this.guest_nickname;
- }
- this.update_board_artifact_viewmodel(a);
- save_artifact(a, on_success);
- },
- add_artifact: function (space, item_type, url, evt) {
- this.active_tool = "pointer";
- this.mouse_state = "idle";
- this.hide_toolbar_artifacts();
-
- if (!url && (item_type == 'image' || item_type == 'video' || item_type == 'embed')) {
- url = prompt("URL?");
- if (!url || !url.length) return;
- }
- //this.opened_dialog = "none";
- var w=300,h=200;
- var z=this.highest_z()+1;
- // TODO: find solution for legacy types
- mimes = {
- "text": "text/html",
- "note": "text/html",
- "image": "image/jpg",
- "video": "video/mp4"
- };
- var new_item = {
- mime: mimes[item_type],
- description: "",
- payload_uri: url,
- payload_thumbnail_medium_uri: url || null,
- payload_thumbnail_web_uri: url || null,
- space_id: space._id,
- order: this.active_space_artifacts.length+1,
- valign: "middle",
- align: "center"
- //fill_color: "#f8f8f8"
- };
- if (mimes[item_type] == "text/html") {
- new_item.padding_left = 10;
- new_item.padding_top = 10;
- new_item.padding_right = 10;
- new_item.padding_bottom = 10;
- new_item.fill_color = "rgba(255,255,255,1)";
- new_item.description = "<p>Text</p>";
- }
- if (evt) {
- var point = this.cursor_point_to_space(evt);
- point.x-=100;
- point.y-=100;
- } else {
- var point = this.find_place_for_item(w,h);
- z = point.z;
- }
- new_item.x = parseInt(point.x);
- new_item.y = parseInt(point.y);
- new_item.z = z;
- new_item.w = w;
- new_item.h = h;
- if (this.guest_nickname) {
- new_item.editor_name = this.guest_nickname;
- }
- // console.log("new artifact", new_item);
- save_artifact(new_item, function(saved_item) {
- // console.log("saved artifact", saved_item);
- this.update_board_artifact_viewmodel(saved_item);
- this.active_space_artifacts.push(saved_item);
- if (!url) {
- this.select(null, saved_item);
- }
- if (item_type.match("text")) {
- this.editing_artifact_id = saved_item._id;
- window.setTimeout(function() {
- // FIXME: replace hack
- var el = $("#artifact-"+saved_item._id+" .text-editing");
- focus_contenteditable(el[0], false);
- },400);
- }
- }.bind(this));
- },
- go_to_first_zone: function() {
- this.discover_zones();
- if (!this.zones.length) return;
- this.zoom_to_zone(this.zones[0]);
- },
- go_to_previous_zone: function() {
- this.discover_zones();
- if (!this.zones.length) return;
- var prev_idx = (this.current_zone_idx-1);
- if (prev_idx<0) prev_idx = this.zones.length-1;
- this.current_zone_idx = prev_idx;
- this.zoom_to_zone(this.zones[this.current_zone_idx]);
- },
- go_to_next_zone: function() {
- this.discover_zones();
- if (!this.zones.length) return;
- var next_idx = ((this.current_zone_idx+1) % this.zones.length);
- this.current_zone_idx = next_idx;
- this.zoom_to_zone(this.zones[this.current_zone_idx]);
- },
- sort_zone_up: function(z) {
- var idx = this.zones.indexOf(z);
- if (idx<1) return;
- var new_zones = _.flatten([this.zones.slice(0,idx-1),[z],this.zones[idx-1],this.zones.slice(idx+1,this.zones.length)]);
- for (var i=0; i<new_zones.length; i++) {
- if (new_zones[i]) {
- if (!new_zones[i].style) new_zones[i].style = {};
- new_zones[i].order = i;
- save_artifact(new_zones[i]);
- }
- }
- this.discover_zones();
- },
- sort_zone_down: function(z) {
- var idx = this.zones.indexOf(z);
- if (idx>=this.zones.length) return;
- var new_zones = _.flatten([this.zones.slice(0,idx),this.zones[idx+1],[z],this.zones.slice(idx+2,this.zones.length)]);
- for (var i=0; i<new_zones.length; i++) {
- if (new_zones[i]) {
- if (!new_zones[i].style) new_zones[i].style = {};
- new_zones[i].order = i;
- save_artifact(new_zones[i]);
- }
- }
- this.discover_zones();
- },
- add_zone: function() {
- var w = 600;
- var h = 600;
- var point = this.find_place_for_item(w,h);
- var a = {
- space_id: this.active_space._id,
- mime: "x-spacedeck/zone",
- description: "Zone "+(this.zones.length+1),
- x: point.x,
- y: point.y,
- w: w,
- h: h,
- z: 0,
- valign: "middle",
- align: "center"
- };
- if (this.guest_nickname) {
- a.editor_name = this.guest_nickname;
- }
- save_artifact(a, function(saved_item) {
- this.update_board_artifact_viewmodel(saved_item);
- this.active_space_artifacts.push(saved_item);
- this.select(null, saved_item);
- }.bind(this));
- },
- add_shape: function(shape_type, evt) {
- var w = 200;
- var h = 200;
- if (shape_type=="cloud") {
- w = 400;
- }
- //var point = this.find_place_for_item(w,h);
- var point = this.cursor_point_to_space(evt);
-
- var a = {
- space_id: this.active_space._id,
- mime: "x-spacedeck/shape",
- description: "Text",
- x: point.x,
- y: point.y,
- z: point.z,
- w: w,
- h: h,
- stroke_color: "#ffffff",
- text_color: "#ffffff",
- stroke: 0,
- fill_color: "#000000",
- shape: shape_type,
- valign: "middle",
- align: "center"
- };
- if (this.guest_nickname) {
- a.editor_name = this.guest_nickname;
- }
- save_artifact(a, function(saved_item) {
- this.update_board_artifact_viewmodel(saved_item);
- this.active_space_artifacts.push(saved_item);
- this.select(null, saved_item);
- }.bind(this));
- },
- cursor_point_to_space: function(evt) {
- if (!evt) return {x:0,y:0};
- if (!$("#space").length) return {x:0,y:0};
- var el = $("#space")[0];
- var pt = parseInt($("#space").css("padding-top"));
- var ml = 0;
- var mt = 0;
- var px = evt.pageX;
- var py = evt.pageY;
- if (!("pageX" in evt) && ("originalEvent" in evt)) {
- px = evt.originalEvent.pageX;
- py = evt.originalEvent.pageY;
- }
- var ox = ((px + el.scrollLeft) - this.bounds_margin_horiz)/this.viewport_zoom;
- var oy = ((py + el.scrollTop) - pt - this.bounds_margin_vert)/this.viewport_zoom;
- return {x: ox, y: oy};
- },
- space_point_to_window: function(x,y) {
- var rx = 0;
- var ry = 0;
-
- var el = $("#space")[0];
- rx = x*this.viewport_zoom-el.scrollLeft+this.bounds_margin_horiz;
- ry = y*this.viewport_zoom-el.scrollTop+this.bounds_margin_vert;
- return {x:rx,y:ry};
- },
- create_artifact_via_upload: function(evt, file, multiple) {
- if (this.active_space_role=="viewer") {
- return false;
- }
-
- this.hide_toolbar_artifacts();
-
- // 1. create placeholder artifact
- var w=300,h=150;
- var fill="transparent";
- if (file.type.match("audio")) {
- w=600;
- h=150;
- fill="#ffffff";
- }
- var point = this.cursor_point_to_space(evt);
- point.x-=w/2;
- point.y-=h/2;
- if (multiple) {
- point = this.find_place_for_item(w,h);
- }
- var a = {
- space_id: this.active_space._id,
- mime: file.type,
- description: "Uploading…",
- state: "uploading",
- payload_thumbnail_medium_uri: null,
- payload_thumbnail_web_uri: null,
- x: point.x,
- y: point.y,
- w: w,
- h: h,
- z: point.z,
- order: this.active_space_artifacts.length+1,
- fill_color: fill
- }
- this.update_board_artifact_viewmodel(a);
- // 2. post file
- if (this.guest_nickname) {
- a.editor_name = this.guest_nickname;
- }
- save_artifact(a, function(updated_a) {
- a = updated_a;
- this.update_board_artifact_viewmodel(a);
- this.active_space_artifacts.push(a);
- save_artifact_file(a, file, file.name, function(updated_a) {
- console.log("file saved. result: ",updated_a);
- // TODO: generify
- a.payload_uri = updated_a.payload_uri;
- a.payload_thumbnail_web_uri = updated_a.payload_thumbnail_web_uri;
- a.payload_thumbnail_medium_uri = updated_a.payload_thumbnail_medium_uri;
- a.payload_thumbnail_big_uri = updated_a.payload_thumbnail_big_uri;
- a.payload_alternatives = updated_a.payload_alternatives;
- a.mime = updated_a.mime;
- a.x = updated_a.x;
- a.y = updated_a.y;
- a.w = updated_a.w;
- a.h = updated_a.h;
- a.z = updated_a.z;
- a.state = updated_a.state;
- this.update_board_artifact_viewmodel(a);
- }.bind(this), null, function(e) {
- // upload progress
- var progress = e.loaded/e.total;
- if (progress=1) {
- a.description = "Converting Media…";
- } else {
- a.description = "Upload "+parseInt(progress*100)+"%";
- }
- this.update_board_artifact_viewmodel(a);
- a.view.progress = parseInt(progress*100);
- }.bind(this));
- }.bind(this), this.display_saving_error);
- },
- delete_selected_artifacts: function(evt, skip_deselect) {
- if (!this.active_space) return;
- if (evt) {
- evt.preventDefault();
- evt.stopPropagation();
- }
- this.begin_transaction();
- var ids = this.selected_artifacts().map(function(a){return a._id});
- var backup = [];
- var backup_ids = [];
- if (ids.length>1 && !skip_deselect) {
- if (!confirm("Delete "+ids.length+" items?")) return;
- }
- for (var i=0; i<ids.length; i++) {
- if (this.selected_artifacts_dict[ids[i]]) {
- var id = ids[i];
- var a = this.find_artifact_by_id(id);
- if (a) {
- backup.push(a);
- backup_ids.push(id);
- delete_artifact(a);
- }
- var idx = this.active_space_artifacts.indexOf(a);
- this.active_space_artifacts.splice(idx, 1);
- }
- }
- this.push_to_undo({
- action: "delete",
- artifact_ids: backup_ids,
- snapshot: backup
- });
- if (!skip_deselect) {
- this.deselect();
- }
- },
- find_artifact_by_id: function(id) {
- var ars = this.active_space_artifacts;
- for (var i=0; i<ars.length; i++) {
- var a = ars[i];
- if (a._id==id) return a;
- }
- return null;
- },
- selected_artifacts: function(exclude_locked) {
- if (!this.active_space || !this.active_space_artifacts) return [];
- return this.active_space_artifacts.filter(function(a) {
- var sel = this.artifact_is_selected(a);
- if (sel && a.locked) return !exclude_locked;
- return sel;
- }.bind(this));
- },
- delayed_edit_artifact: function(evt) {
- evt.stopPropagation();
- evt.preventDefault();
- var a = this.selected_artifacts()[0];
- var el = $("#ios-focuser-"+a._id);
- el.focus();
- el.select();
- this.toggle_selected_artifact_editing(true, true);
- },
- toggle_selected_artifact_editing: function(force_on, delayed) {
- var a = this.selected_artifacts()[0];
- if (!a) {
- this.editing_artifact_id = null;
- return;
- }
- if (this.editing_artifact_id == a._id && !force_on) {
- this.editing_artifact_id = null;
- return;
- }
- if (a.locked) return;
- if (!_.include(["text/html","x-spacedeck/shape","x-spacedeck/zone"],a.mime)) return;
- if (this.editing_artifact_id == a._id) return;
- this.editing_artifact_id = a._id;
- var ms = 100;
- if (delayed) ms = 500; // wait for slow devices
- window.setTimeout(function(){
- var el = $("#artifact-"+a._id+" .text-editing");
- if (el[0]) {
- // tuned weirdness for firefox, chrome + ios safari
- //el.select();
- focus_contenteditable(el[0], true);
- } else {
- // one more try (slow device)
- window.setTimeout(function(){
- var el = $("#artifact-"+a._id+" .text-editing");
- //el.select();
- focus_contenteditable(el[0], true);
- },ms);
- }
- },ms);
- },
- clear_formatting_walk: function(el,cmd,arg1,arg2) {
- if (el && el.style) {
- if (cmd == "preciseFontSize") {
- el.fontSize = null;
- } else if (cmd == "letterSpacing") {
- el.letterSpacing = null;
- } else if (cmd == "lineHeight") {
- el.lineHeight = null;
- } else if (cmd == "fontName") {
- el.fontFamily = null;
- } else if (cmd == "fontWeight") {
- el.fontWeight = null;
- el.fontStyle = null;
- } else if (cmd == "bold") {
- el.fontWeight = null;
- } else if (cmd == "italic") {
- el.fontStyle = null;
- } else if (cmd == "underline") {
- el.textDecoration = null;
- } else if (cmd == "strikeThrough") {
- el.textDecoration = null;
- } else if (cmd == "forecolor") {
- el.color = null;
- }
- }
- if (el && el.childNodes) {
- for (var i=0; i<el.childNodes.length; i++) {
- this.clear_formatting_walk(el.childNodes[i],cmd,arg1,arg2);
- }
- }
- },
- apply_formatting: function(evt,cmd,arg1,arg2) {
- if (evt) {
- evt.preventDefault();
- evt.stopPropagation();
- }
- if (this.skip_formatting) return;
- if (cmd=='createlink') {
- arg1 = prompt("Link URL?");
- if (!arg1) return;
- }
- var selected = this.selected_artifacts();
- var collapsed = false;
- if (!window.selection || window.selection.type == "Caret" || window.selection.type == "None") {
- collapsed = true;
- }
- // (selected.length==1 && (!this.editing_artifact_id))
- if (!this.editing_artifact_id || cmd == "preciseFontSize" || cmd == "forecolor") {
- for (var i=0; i<selected.length; i++) {
- var a = selected[i];
- var dom = $("<div>"+a.description+"</div>")[0];
- var el = dom.firstChild;
- do {
- // clear nested styles first
- if (el && el.childNodes) {
- for (var j=0; j<el.childNodes.length; j++) {
- this.clear_formatting_walk(el.childNodes[j],cmd,arg1,arg2);
- }
- }
- // toggle new style
- if (el && el.style) {
- if (cmd == "preciseFontSize") {
- if (arg1 == this.default_style.font_size+"px") {
- el.style.fontSize = null;
- } else {
- el.style.fontSize = arg1;
- }
- } else if (cmd == "letterSpacing") {
- if (arg1 == this.default_style.letter_spacing+"px") {
- el.style.letterSpacing = null;
- } else {
- el.style.letterSpacing = arg1;
- }
- } else if (cmd == "lineHeight") {
- if (arg1 == this.default_style.line_height+"em") {
- el.style.lineHeight = null;
- } else {
- el.style.lineHeight = arg1;
- }
- } else if (cmd == "fontName") {
- el.style.fontFamily = arg1;
- } else if (cmd == "fontWeight") {
- el.style.fontWeight = arg1;
- el.style.fontStyle = arg2;
- } else if (cmd == "bold") {
- el.style.fontWeight = (el.style.fontWeight!="bold"?"bold":"normal");
- } else if (cmd == "italic") {
- el.style.fontStyle = (el.style.fontStyle!="italic"?"italic":"normal");
- } else if (cmd == "underline") {
- el.style.textDecoration = (el.style.textDecoration!="underline"?"underline":"none");
- } else if (cmd == "strikeThrough") {
- el.style.textDecoration = (el.style.textDecoration!="line-through"?"line-through":"none");
- } else if (cmd == "forecolor") {
- el.style.color = arg1;
- }
- }
- } while (el && (el = el.nextSibling));
- if (a.description!=dom.innerHTML) {
- a.description = dom.innerHTML;
- console.log("new DOM:",dom.innerHTML);
-
- this.update_board_artifact_viewmodel(a);
- this.queue_artifact_for_save(a);
- if (this.editing_artifact_id) {
- var a = this.find_artifact_by_id(this.editing_artifact_id);
- var medium = this.medium_for_object[a._id];
- if (medium && a) {
- medium.value(a.description);
- }
- }
- }
- }
- } else if (this.editing_artifact_id) {
- // text level selection
- var a = this.find_artifact_by_id(this.editing_artifact_id);
- var medium = this.medium_for_object[a._id];
-
- if (medium && a) {
- medium.focus();
- medium.element.focus();
- medium.invokeElement(cmd);
-
- a.description = medium.value();
- this.queue_artifact_for_save(a);
- }
- }
- this.extract_text_format_from_selection();
- },
- remove_link_from_selected_artifacts: function() {
- this.update_selected_artifacts(function(a) {
- return {link_uri: ""};
- });
- },
- create_link_on_selected_artifacts: function() {
- var def = "";
- var sa = this.selected_artifacts();
- if (sa.length>=1) {
- if (sa[0].meta && sa[0].meta.link_uri) {
- def = sa[0].meta.link_uri;
- }
- }
- var insert_link_url = prompt("URL:",def);
- this.update_selected_artifacts(function(a) {
- var update = {link_uri: insert_link_url};
- if (a.payload_uri && a.payload_uri.match("webgrabber")) {
- var enc_uri = encodeURIComponent(btoa(insert_link_url));
- var thumb_uri = ENV.apiEndpoint + "/api/webgrabber/"+enc_uri;
- update.payload_uri = thumb_uri;
- update.payload_thumbnail_web_uri = thumb_uri;
- update.payload_thumbnail_medium_uri = thumb_uri;
- update.payload_thumbnail_big_uri = thumb_uri;
- }
-
- return update;
- });
- this.opened_dialog = "none";
- },
- clone_artifact: function(a,dx,dy,on_success) {
- var copy = _.cloneDeep(a);
- delete copy["$index"];
- delete copy["_id"];
- if (dx) copy.x += dx;
- if (dy) copy.y += dy;
- copy.order = this.active_space_artifacts.length+1;
- if (this.guest_nickname) {
- copy.editor_name = this.guest_nickname;
- }
- copy.space_id = this.active_space._id;
- save_artifact(copy, function(saved) {
- this.update_board_artifact_viewmodel(saved);
- this.active_space_artifacts.push(saved);
- if (on_success) {
- on_success(saved);
- } else {
- this.select(null,saved);
- }
- }.bind(this));
- return copy;
- },
- toggle_lock_of_selected_artifacts: function() {
- this.update_selected_artifacts(function(a) {
- return {locked: !a.locked};
- }, true);
- },
- duplicate_selected_artifacts: function() {
- var arts = this.selected_artifacts();
- for (var i=0; i<arts.length; i++) {
- var a = arts[i];
- var cloned = this.clone_artifact(a,50,50);
- }
- },
- copy_selected_artifacts_to_clipboard: function() {
- if ('ontouchstart' in window) return; // don't do this on touch devices
- $("#space-clipboard").focus();
- $("#space-clipboard").select();
- },
- handle_section_click: function(evt) {
- if (evt.target == evt.currentTarget) {
- this.deselect();
- }
- },
- handle_space_doubleclick: function(evt) {
- if (this.selected_artifacts().length) return;
- if (this.guest_nickname) return;
- if (this.active_space && this.active_space.access_mode == "public") return;
- //this.add_artifact(this.active_space, "text", null, evt);
- },
- handle_body_click: function(evt) {
- if (this.active_view == "space") {
- this.handle_section_click(evt);
- }
- this.close_dropdown(evt);
- },
- extract_text_format_from_selection: function() {
- if (!window.selection) return;
- var parents = $(window.selection.baseNode).parents().toArray();
- this.detected_text_formats = {};
- var formats = {
- "p":"Paragraph",
- "h1":"Headline 1",
- "h2":"Headline 2",
- "h3":"Headline 3",
- "h4":"Headline 4",
- "h5":"Headline 5",
- "h6":"Headline 6",
- "ul":"Bullet List",
- "ol":"Numbered List",
- "blockquote":"Blockquote"
- };
- for (var i=0; i<parents.length; i++) {
- var p = parents[i];
- if (p.contentEditable=="true") break;
- var nn = p.nodeName.toLowerCase();
- if (formats[nn]) {
- this.detected_text_formats[nn] = true;
- this.active_text_format_name = formats[nn];
- }
- }
- },
- // called on artifact keyup
- save_edited_artifact_text: function(evt) {
- // FIXME
- if (this.editing_artifact_id) {
- //var scribe = _scribe_handle_for_object[this.editing_artifact_id];
- var artifact = this.find_artifact_by_id(this.editing_artifact_id);
- if (artifact) {
- //artifact.description = scribe.getHTML();
- this.queue_artifact_for_save(artifact);
- }
- this.extract_text_format_from_selection();
- }
- },
- handle_section_paste: function(evt) {
- if (this.editing_artifact_id) return;
- var pastedText = null;
- try {
- pastedText = evt.clipboardData.getData('text/plain');
- } catch (e) {
- }
- if (!pastedText) return;
-
- if (!pastedText.match(/<[a-zA-Z]+>/g)) {
- // crappy heuristic if this is actually HTML
- pastedText = pastedText.replace(/\n/g,"<br>");
- }
-
- this.insert_embedded_artifact(pastedText);
- },
- insert_embedded_artifact: function(text) {
- var space = this.active_space;
- if (!space) return;
- if (text[0]=='[' || text[0]=='{') {
- // might be json
- try {
- parsed = JSON.parse(text);
- if (text[0]=='{') parsed = [parsed];
-
- this.deselect();
- for (var i=0; i<parsed.length; i++) {
- if (parsed[i].mime) {
- var z = this.highest_z()+1;
- if (parsed.length==1) {
- var w = parsed[i].w;
- var h = parsed[i].h;
- var point = this.find_place_for_item(w,h);
- parsed[i].x = point.x;
- parsed[i].y = point.y;
- parsed[i].z = point.z;
- } else {
- parsed[i].x = parsed[i].x+50;
- parsed[i].y = parsed[i].y+50;
- parsed[i].y = parsed[i].z+z;
- }
- this.clone_artifact(parsed[i], 0,0, function(a) {
- this.multi_select([a]);
- }.bind(this));
- }
- }
- return;
- } catch(e) {
- // not json
- }
- }
- if (text.match(/^http[s]*\:\/\//)) {
- // crude url matching
- this.create_artifact_via_embed_url(text);
- return;
- }
- var new_item = {
- mime: "text/html",
- description: text.replace("\n", "<br />"),
- title: "",
- space_id: space._id
- };
- var w = 400;
- var h = 300;
- var point = this.find_place_for_item(w,h);
- new_item.x = point.x;
- new_item.y = point.y;
- new_item.w = w;
- new_item.h = h;
- new_item.z = point.z;
- if (this.guest_nickname) {
- new_item.editor_name = this.guest_nickname;
- }
- save_artifact(new_item, function(saved_item) {
- this.update_board_artifact_viewmodel(saved_item);
- this.active_space_artifacts.push(saved_item);
- }.bind(this));
- },
- create_artifact_via_embed_url: function(url) {
- this.close_modal();
-
- var point = this.find_place_for_item(200,200);
- var z = this.highest_z()+1;
- var a = {
- space_id: this.active_space._id,
- mime: "image/png",
- description: url,
- state: "uploading",
- x: point.x,
- y: point.y,
- w: 200,
- h: 200,
- z: z,
- order: this.active_space_artifacts.length
- }
- var metadata = parse_link(url)
-
- if (!metadata) {
- return;
- }
- if (metadata.type == "unknown") {
- var enc_uri = encodeURIComponent(btoa(url));
- a.meta = {
- link_uri: url
- }
- if (this.guest_nickname) {
- a.editor_name = this.guest_nickname;
- }
- // step 1: create placeholder
- save_artifact(a, function(saved_a) {
- this.update_board_artifact_viewmodel(saved_a);
- this.active_space_artifacts.push(saved_a);
- var thumb_uri = ENV.apiEndpoint + "/api/webgrabber/"+enc_uri;
- // step 2: push payload_uri for processing
- saved_a.state = "idle";
- saved_a.payload_uri = thumb_uri;
- saved_a.payload_thumbnail_web_uri = thumb_uri;
- saved_a.payload_thumbnail_medium_uri = thumb_uri;
- saved_a.payload_thumbnail_big_uri = thumb_uri;
- save_artifact(saved_a, function(saved_a2) {
- this.update_board_artifact_viewmodel(saved_a);
- }.bind(this));
- }.bind(this));
- return;
- }
- var w = metadata.thumbnail_width || 200;
- var h = metadata.thumbnail_height || 200;
- if (w<200) w = 200;
- if (h<200) h = 200;
- if (metadata.provider_name == "soundcloud") {
- w = 500;
- h = 150;
- }
- a = _.extend(a, {
- mime: "oembed/"+metadata.type+"-"+metadata.provider_name,
- description: metadata.url || url,
- //payload_uri: metadata.url || url,
- payload_thumbnail_medium_uri: metadata.thumbnail_url,
- payload_thumbnail_web_uri: metadata.thumbnail_url,
- state: "idle",
- title: metadata.title,
- link_uri: metadata.url || url,
- x: point.x - w/2,
- y: point.y - h/2,
- w: w,
- h: h
- });
- if (this.guest_nickname) {
- a.editor_name = this.guest_nickname;
- }
- save_artifact(a, function(saved_a) {
- this.update_board_artifact_viewmodel(saved_a);
- this.active_space_artifacts.push(saved_a);
- }.bind(this));
- },
- create_artifact_via_payload_url: function(type, url) {
- this.add_artifact(this.active_space, type, url, null);
- },
- handle_touch_select_background_image: function() {
- $('#background-uploader').click();
- },
- handle_insert_image_url: function(url) {
- if (!url || !url.length) {
- $("#image_file_upload").click(); // redirect to file upload
- return;
- }
- this.create_artifact_via_payload_url("image", url);
- this.insert_image_url = "";
- // this.opened_dialog = "none";
- },
- handle_insert_video_url: function(url) {
- if (!url.length) {
- $("#video_file_upload").click(); // redirect to file upload
- return;
- }
- var object = parse_link(url);
- if (object) {
- this.create_artifact_via_embed_url(url);
- } else {
- this.create_artifact_via_payload_url("video", url);
- }
- this.insert_video_url = "";
- //this.opened_dialog = "none";
- },
- handle_insert_audio_url: function(url) {
- if (!url.length) {
- $("#audio_file_upload").click(); // redirect to file upload
- return;
- }
- var object = parse_link(url);
- if (object) {
- this.create_artifact_via_embed_url(url);
- } else {
- this.create_artifact_via_payload_url("audio", url);
- }
- this.insert_audio_url = "";
- },
- handle_generic_file_upload: function(evt) {
- var files = evt.target.files;
- this.opened_dialog = "none";
- if (files && files.length) {
- console.log("file: ",files[0]);
- for (var i=0; i<files.length; i++) {
- var file = files[i];
- if (file.type === "application/pdf") {
- var point = {x: 100, y: 100}; //fixme, center upload?
- this.dropped_point = point;
- this.pending_pdf_file = file;
- this.activate_modal('pdfoptions');
- } else {
- this.create_artifact_via_upload(null, file, true);
- }
- }
- }
- },
- handle_image_file_upload: function(evt) {
- this.handle_generic_file_upload(evt);
- },
- handle_video_file_upload: function(evt) {
- this.handle_generic_file_upload(evt);
- },
- handle_audio_file_upload: function(evt) {
- this.handle_generic_file_upload(evt);
- },
- handle_section_background_upload: function(evt) {
- var f = evt.target.files[0];
- this.space_background_uploading = true;
- save_space_background_file(this.active_space, f, function(space) {
- this.active_space = space;
- this.space_background_uploading = false;
- }.bind(this));
- },
- remove_section_background: function() {
- this.active_space.background_uri = null;
- save_space(this.active_space);
- },
- show_toolbar_props: function() {
- if (this.selection_metrics.count==0) return;
- arts = this.selected_artifacts();
- for (var i=0;i<arts.length; i++) {
- if (arts[i].mime=="x-spacedeck/zone") return;
- }
- this.toolbar_props_in = true;
- },
-
- hide_toolbar_props: function() {
- this.toolbar_props_in = false;
- },
-
- show_toolbar_artifacts: function(x,y) {
- this.toolbar_artifacts_x = (x-175)+"px";
- this.toolbar_artifacts_y = y+"px";
- this.toolbar_artifacts_in = true;
- },
-
- hide_toolbar_artifacts: function() {
- this.toolbar_artifacts_in = false;
- },
- start_adding_artifact: function(evt) {
- evt = fixup_touches(evt);
-
- // toggle
- if (this.toolbar_artifacts_in) {
- this.hide_toolbar_artifacts();
- return;
- }
- this.show_toolbar_artifacts(evt.pageX,evt.pageY);
- },
- start_drawing_scribble: function(evt) {
- this.hide_toolbar_artifacts();
- this.active_tool = "scribble";
- this.opened_dialog = "none";
- },
- start_drawing_arrow: function(evt) {
- this.hide_toolbar_artifacts();
- this.active_tool = "arrow";
- this.opened_dialog = "none";
- },
- start_drawing_line: function(evt) {
- this.hide_toolbar_artifacts();
- this.active_tool = "line";
- this.opened_dialog = "none";
- },
- adjust_bounds_zoom: function() {
- if (!this.active_space) return;
- this.bounds_zoom = this.viewport_zoom;
- var eff_w = this.active_space.width*this.viewport_zoom;
- var eff_h = this.active_space.height*this.viewport_zoom;
- if (window.innerWidth>eff_w) {
- // horizontal centering
- this.bounds_margin_horiz = (window.innerWidth-eff_w)/2;
- } else {
- this.bounds_margin_horiz = 0;
- }
- if (window.innerHeight-80>eff_h) {
- // horizontal centering
- this.bounds_margin_vert = (window.innerHeight-eff_h)/2-80;
- } else {
- this.bounds_margin_vert = 0;
- }
- },
- zoom_to_original: function() {
- var old_zoom = this.viewport_zoom;
- this.viewport_zoom = 1;
- this.viewport_zoom_percent = parseInt(this.viewport_zoom*100);
- this.adjust_bounds_zoom();
- this.zoom_adjust_scroll(this.viewport_zoom/old_zoom);
- },
- zoom_to_fit: function() {
- var er = this.enclosing_rect(this.active_space_artifacts);
- if (!er) return;
- var pad = 200;
- er.x1-=pad;
- er.y1-=pad-100;
- er.x2+=pad;
- er.y2+=pad+100;
- this.zoom_to_rect(er, 1);
- },
- zoom_to_zone: function(z) {
- if (!$("#space").length) return;
- var er = this.enclosing_rect([z]);
- var el = $("#space")[0];
- var cur_r = {
- x1: el.scrollLeft/this.viewport_zoom,
- y1: el.scrollTop/this.viewport_zoom,
- x2: (el.scrollLeft+window.innerWidth)/this.viewport_zoom,
- y2: (el.scrollTop+window.innerHeight)/this.viewport_zoom
- };
-
- var pad = 10;
- er.x1-=pad;
- er.y1-=pad;
- er.x2+=pad;
- er.y2+=pad;
- if (!this.animation_running) {
- this.animation_running = true;
- this.animate_zoom_to_rect(er, 200, cur_r);
- this.current_zone_idx = this.zones.indexOf(z);
- }
- },
- zoom_to_rect: function(er, max_zoom) {
- if (!$("#space").length) return;
- var el = $("#space")[0];
- var w = er.x2-er.x1;
- var h = er.y2-er.y1;
- if (w>h) {
- this.viewport_zoom = window.innerWidth/w;
- if (window.innerHeight < h*this.viewport_zoom) {
- this.viewport_zoom = window.innerHeight/h;
- }
- } else {
- this.viewport_zoom = window.innerHeight/h;
- if (window.innerWidth < w*this.viewport_zoom) {
- this.viewport_zoom = window.innerWidth/w;
- }
- }
- if (max_zoom) {
- if (this.viewport_zoom>max_zoom) this.viewport_zoom = max_zoom;
- }
- if (this.viewport_zoom<0.05) this.viewport_zoom = 0.05;
- this.viewport_zoom_percent = parseInt(this.viewport_zoom*100);
- this.adjust_bounds_zoom();
- if (!el) return;
- var animate = function() {
- el.scrollTop = (er.y1+(h/2))*this.viewport_zoom-window.innerHeight/2;
- el.scrollLeft = (er.x1+(w/2))*this.viewport_zoom-window.innerWidth/2;
- this.handle_scroll();
- }.bind(this);
- if ("requestAnimationFrame" in window) {
- window.requestAnimationFrame(animate);
- } else {
- animate();
- }
- },
- animate_zoom_to_rect: function(target_r, duration, cur_r, elapsed) {
- if (!$("#space").length) return;
- var el = $("#space")[0];
- var anim_res = 20;
- if (!elapsed) elapsed = 0;
-
- if (duration>elapsed) {
- window.setTimeout(function() {
- this.animate_zoom_to_rect(target_r, duration, cur_r, elapsed+anim_res);
- }.bind(this), anim_res);
- /*var dx = (el.scrollLeft-ncx)/anim_res;
- var dy = (el.scrollLeft-ncy)/anim_res;
- el.scrollLeft += dx;
- el.scrollTop += dy;*/
- // interpolate
- var dx1 = ((target_r.x1-cur_r.x1)/duration)*elapsed;
- var dx2 = ((target_r.x2-cur_r.x2)/duration)*elapsed;
- var dy1 = ((target_r.y1-cur_r.y1)/duration)*elapsed;
- var dy2 = ((target_r.y2-cur_r.y2)/duration)*elapsed;
- var step_r = {
- x1: cur_r.x1+dx1,
- x2: cur_r.x2+dx2,
- y1: cur_r.y1+dy1,
- y2: cur_r.y2+dy2
- };
- /*console.log("cur_r: ",cur_r);
- console.log("target_r: ",target_r);
- console.log("step_r: ",step_r);*/
- this.zoom_to_rect(step_r);
- } else {
- // done
- this.zoom_to_rect(target_r);
- this.animation_running = false;
- }
- },
- zoom_to_point: function(p,amount) {
- var el = $("#space")[0];
-
- var sx = el.scrollLeft/this.viewport_zoom;
- var sy = el.scrollTop/this.viewport_zoom;
- var ww = window.innerWidth/(this.viewport_zoom);
- var wh = window.innerHeight/(this.viewport_zoom);
- var oxx = (p.x-(sx+ww/2))*amount;
- var oyy = (p.y-(sy+wh/2))*amount;
- var ox = -oxx;
- var oy = -oyy;
-
- var r = {
- x1: p.x-(ww/2)*amount + ox,
- y1: p.y-(wh/2)*amount + oy,
- x2: p.x+(ww/2)*amount + ox,
- y2: p.y+(wh/2)*amount + oy
- };
- this.zoom_to_rect(r,2);
- },
- throttled_zoom_to_point: _.throttle(function(p,a){
- this.zoom_to_point(p,a);
- }, 50),
- zoom_to_cursor: function(evt,amount) {
- var point = this.cursor_point_to_space(evt);
- this.throttled_zoom_to_point.bind(this)(point,amount);
- },
- zoom_adjust_scroll: function(f) {
- var adjust_scroll = function() {
- if (!$("#space").length) return;
- if (!this.active_space || !this.active_space_loaded) return;
-
- var el = $("#space")[0];
- var eff_w = this.active_space.width*this.viewport_zoom;
- var eff_h = this.active_space.height*this.viewport_zoom;
-
- var sx = el.scrollLeft;
- var sy = el.scrollTop;
- var cx = window.innerWidth/2;
- var cy = window.innerHeight/2;
- var ncx = f*(sx+cx)-cx;
- var ncy = f*(sy+cy)-cy;
- if (eff_w<window.innerWidth) ncx = 0;
- if (eff_h<window.innerHeight) ncy = 0;
- el.scrollLeft = ncx;
- el.scrollTop = ncy;
- this.handle_scroll();
- };
- if ("requestAnimationFrame" in window) {
- window.requestAnimationFrame(adjust_scroll.bind(this));
- } else {
- adjust_scroll();
- }
- },
- zoom_in: function() {
- if (!this.viewport_zoom) this.viewport_zoom = 1;
- var old_zoom = this.viewport_zoom;
- this.viewport_zoom *= 1.5;
- if (this.viewport_zoom>=2) {
- this.viewport_zoom = 2;
- }
- this.viewport_zoom_percent = parseInt(this.viewport_zoom*100);
- this.adjust_bounds_zoom();
- this.zoom_adjust_scroll(this.viewport_zoom/old_zoom);
- },
- zoom_out: function() {
- if (!this.viewport_zoom) this.viewport_zoom = 1;
- var old_zoom = this.viewport_zoom;
- this.viewport_zoom /= 1.5;
- if (this.viewport_zoom<0.05) {
- this.viewport_zoom = 0.05;
- }
- this.viewport_zoom_percent = parseInt(this.viewport_zoom*100);
- this.adjust_bounds_zoom();
- this.zoom_adjust_scroll(this.viewport_zoom/old_zoom);
- },
- activate_pan_tool: function(evt) {
- if (evt) {
- evt.stopPropagation();
- evt.preventDefault();
- }
- this.active_tool = "pan";
- if (this.stop_pan_timeout) {
- window.clearTimeout(this.stop_pan_timeout);
- }
- // pan exit hack
- this.stop_pan_timeout = window.setTimeout(function () {
- if (this.active_tool == "pan") {
- this.active_tool = "pointer";
- }
- }.bind(this),500);
- },
- approve_pdf_upload: function(evt,approve_pdf_upload, mode){
- this.close_modal();
-
- if(mode == "classic"){
- this.create_artifact_via_upload(evt, this.pending_pdf_file, false);
- }
- if(mode == "grid") {
- this.global_spinner = true;
- save_pdf_file(this.active_space, this.dropped_point, this.pending_pdf_file, approve_pdf_upload, function(createdArtifacts){
- this.global_spinner = false;
- _.each(createdArtifacts, function(new_artifact){
- this.update_board_artifact_viewmodel(new_artifact);
- this.active_space_artifacts.push(new_artifact)
- }.bind(this));
- }.bind(this), function(xhr) {
- this.global_spinner = false;
- alert("Error PDF ("+xhr.status+")");
- }.bind(this));
- }
- },
- handle_data_drop: function(evt) {
- if (this.active_space_role=="viewer") {
- return false;
- }
- var json = evt.dataTransfer.getData('application/json');
- var dest_section = this.active_space;
- var files = evt.dataTransfer.files;
- if (files && files.length) {
- for (var i=0; i<files.length; i++) {
- var file = files[i];
- if (file.type === "application/pdf") {
- var point = this.cursor_point_to_space(evt);
- this.dropped_point = point;
- this.pending_pdf_file = file;
- this.activate_modal('pdfoptions');
- } else {
- this.create_artifact_via_upload(evt, file, (files.length>1));
- }
- }
- } else {
- var json = evt.dataTransfer.getData('application/json');
- if (json) {
- var parsed = JSON.parse(json);
- delete parsed._id;
- parsed.space_id = this.active_space._id;
- var w = 300;
- var h = 200;
- if (parsed.board && parsed.w && parsed.h) {
- w = parsed.w;
- h = parsed.h;
- }
- var point = this.cursor_point_to_space(evt);
- point.x-=w/2;
- point.y-=h/2;
- parsed.board = {
- x: point.x,
- y: point.y,
- w: w,
- h: h,
- z: 20
- };
- if (this.guest_nickname) {
- parsed.editor_name = this.guest_nickname;
- }
- save_artifact(parsed, function(saved_a) {
- this.update_board_artifact_viewmodel(saved_a);
- this.active_space_artifacts.push(saved_a);
- }.bind(this));
- return;
- }
- var html = evt.dataTransfer.getData('text/html');
-
- if (html) {
- var rx = /src="([^"]+)"/g;
- var m = rx.exec(html);
- if (m) {
- this.add_artifact(this.active_space, "image", m[1], evt);
- }
- }
- }
- },
- clear_search_results: function() {
- this.image_search_results = [];
- this.audio_search_results = [];
- this.video_search_results = [];
- },
- download_selected_artifacts: function() {
- var arts = this.selected_artifacts();
- if (arts.length!=1) return;
- if (arts[0].payload_uri) {
- try {
- window.open(arts[0].payload_uri);
- } catch (e) {
- // could not open window
- }
- }
- }
- }
- }
|